ATTiny13 -- avr-gcc Hallo Welt verwendet über 100 Bytes?

Ich versuche, ein Programm für den ATTiny13 zu schreiben. Mein Problem ist, dass es enorme Größenbeschränkungen gibt. Nun, als ich mein erstes Hello World-Programm erstellte, brauchte ich 100 Bytes Programmspeicherplatz, nur um ein Licht ein- und auszuschalten! Gibt es Optionen, die ich avr-gcc geben kann, um diese Größe zu verkleinern? Außerdem, was ist in crt0? Ich bin nicht so begeistert von der AVR-Montage, daher verstehe ich es nicht viel.

Ich möchte für dieses Projekt nicht auf die Montage verzichten müssen.

Als kleine Randbemerkung würden manche Leute das ein "Blinky"-Programm nennen.
@Johan nun, ich war mir nicht sicher, wie man "blinkenlights" buchstabiert

Antworten (5)

crt0 ist die Startroutine für den uC. Die Routinen führen die Einrichtung der Register und auch die Initialisierung von Daten durch.

Enthalten die 100 Bytes die Interrupt-Vektortabelle? Ich bin mir bei ATtiny13 nicht sicher, aber ATtiny25/45/85 hat 15 Interrupt-Vektoren. Dies würde 30 Bytes beanspruchen.

gcc hat eine Option zum Linken in Ihrem crt0. Sie könnten die AVR-Datei crt0.S nehmen und ändern. Es ist nicht sehr lang, also sollte es nicht schwierig sein.

Ich kann die crt0-Quelle nicht finden, aber in crt1 scheint eine Interrupt-Vektortabelle zu sein. Vielleicht ist es das
Ich kann es auch nicht auf meinem System finden :( Ich habe alle Tools aus dem Quellcode kompiliert, also dachte ich, es wäre dort. Wenn Sie nach "crt0.S atmel" googeln, ein paar Atmel-App-Hinweise zu Startup, crt0 und gcc Optimierung kommen. Vielleicht gibt es einige Hinweise in diesen Dokumenten.
@jlu Ich versuche, den Unterschied zwischen den beiden herauszufinden, habe aber noch nichts Gutes auf Stack Overflow bekommen: stackoverflow.com/questions/2709998/…
avr-libc hat eine andere CRT für jeden AVR-Chiptyp, und die standardmäßigen avr-libc-Distributionen enthalten nur die .o-Version der Datei. Die für ATtiny13 befindet sich unter [avr-libc-path]/avr-3/lib/crttn13.o
@todbot hmm. Ah, ok ja, ich habe es drin/avr-libc-1.6.7/avr/lib/avr2/attiny13/crttn13.S
Es sieht so aus, als ob der Crt-Code gcrt1.S ist und sich in avr-libc/crt1 befindet. Ich glaube, dass das Makefile (im selben Verzeichnis) die Objektdateien für die verschiedenen Geräte kompiliert.

Sie können avr-objdump -d .elf verwenden, um zu sehen, was generiert wird:

Analysieren wir es ein wenig:

[jpc@jpc ~] avr-objdump -d avr.elf | sed -e 's/^/    /' | pbcopy

avr.elf:     file format elf32-avr

Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18        ; 0x14 <__ctors_end>
   2:   0e c0           rjmp    .+28        ; 0x20 <__bad_interrupt>
   4:   0d c0           rjmp    .+26        ; 0x20 <__bad_interrupt>
   6:   0c c0           rjmp    .+24        ; 0x20 <__bad_interrupt>
   8:   0b c0           rjmp    .+22        ; 0x20 <__bad_interrupt>
   a:   0a c0           rjmp    .+20        ; 0x20 <__bad_interrupt>
   c:   09 c0           rjmp    .+18        ; 0x20 <__bad_interrupt>
   e:   08 c0           rjmp    .+16        ; 0x20 <__bad_interrupt>
  10:   07 c0           rjmp    .+14        ; 0x20 <__bad_interrupt>
  12:   06 c0           rjmp    .+12        ; 0x20 <__bad_interrupt>

20 Bytes Interrupt-Vektortabelle (zumindest einige der Einträge könnten weggelassen werden, wenn Sie darauf bestehen und versprechen, dass Sie die entsprechenden Interrupts niemals aktivieren würden).

00000014 <__ctors_end>:
  14:   11 24           eor r1, r1
  16:   1f be           out 0x3f, r1    ; 63
  18:   cf e9           ldi r28, 0x9F   ; 159
  1a:   cd bf           out 0x3d, r28   ; 61
  1c:   02 d0           rcall   .+4         ; 0x22 <main>
  1e:   05 c0           rjmp    .+10        ; 0x2a <_exit>

Löscht SREG (ich bin mir nicht sicher, ob das wirklich nötig ist), schreibt 0x9f (RAMEND) in SPL (den Stapelzeiger) und springt zu main. Das letzte rjmp ist irgendwie überflüssig. (Sie könnten versprechen, niemals vom Main zurückzukehren)

00000020 <__bad_interrupt>:
  20:   ef cf           rjmp    .-34        ; 0x0 <__vectors>

Standard-Interrupt-Prozedur für solche Interrupts, die in C nicht überschrieben wurden (gleiche Regeln wie für __vectors)

00000022 <main>:
  22:   bb 9a           sbi 0x17, 3 ; 23
  24:   c3 9a           sbi 0x18, 3 ; 24
  26:   c3 98           cbi 0x18, 3 ; 24
  28:   fd cf           rjmp    .-6         ; 0x24 <main+0x2>

Ihr Hauptprozess. Eng.

0000002a <_exit>:
  2a:   f8 94           cli

0000002c <__stop_program>:
  2c:   ff cf           rjmp    .-2         ; 0x2c <__stop_program>

Diese beiden sind nicht sehr nützlich. _exit wird wahrscheinlich vom C-Standard benötigt und __stop_program wird benötigt, damit es so funktioniert, wie es sollte.

Was ist Ihre mögliche Anwendung? Ein ATtiny13 hat 1kB Flash und man kann damit viel in C machen. Das crt0 ist die avr-libc C Runtime. Es enthält Dinge wie Stapelverarbeitung, sodass Sie Funktionen mit Argumenten und Rückgabewerten verwenden können.

100 Byte für die Einrichtung von eingebettetem C sind nicht allzu schlecht und haben eine konstante Größe. Das Verdoppeln der Zeilen der Programmlogik ergibt nicht unbedingt 200 Bytes. Auf welcher Optimierungsstufe kompilieren Sie? Sie sollten bei "-Os" sein. Und wie kompilierst du das? Die Makefiles in den Demo-Projekten, die auf der avr-libc-Site verfügbar sind, sind ziemlich gut und umfassend.

Das einfache LED-Ein/Aus-Programm unten benötigt 62 Bytes auf einem ATtiny13 mit "-Os" auf dem avr-gcc 4.3.3. von CrossPack-AVR:

#include <avr/io.h>
#include <avr/delay.h>

int Haupt(leer)
{
    DDRB |= _BV( PB3 );
    während ( 1 ) {
        PORTB |= _BV( PB3 );
        _delay_ms(200);
        PORTB &=~ _BV( PB3 );
        _delay_ms(200);
    }
}

Das Entfernen der _delay_ms()-Aufrufe macht es zu 46 Bytes.

Ein größeres Beispiel für den ATtiny13 sind meine Smart LED-Prototypen . Dieser Code enthält eine 3-Kanal-Software-PWM, eine HSV-zu-RGB-Farbkonvertierung, eine Zustandsmaschine und liest zwei Tasten. Es ist nicht besonders gut geschrieben und kommt auf 864 Bytes. Unter avr-gcc 3.x war es noch kleiner. (aus irgendeinem Grund hat avr-gcc 4 fast alle Programme um ein paar Bytes wachsen lassen)

avr-gcc -std=c99 -Wall -Os -mmcu=attiny13 -o hello.out helloworld.cist die relevante Zeile in meinem Makefile (selbst erstellt). und ich verwende fast identischen Code, außer um die von mir verwendete LED umzudrehen PORTB &= ~(1 << LED);und so weiter
Und ja, die Größe ist konstant, aber selbst 46 Bytes scheinen ziemlich schwer zu sein, wenn man nur einen Stackframe einrichten muss

Wenn Sie wenig Platz haben, probieren Sie die Embedded Workbench von IAR aus - ihre kostenlose "Kickstart"-Version hat eine Beschränkung der Codegröße von 4K-Wörtern, also viel für ATTiny's und wahrscheinlich eine bessere Optimierung als gcc

Optimierungsvergleiche sind ein sehr umstrittenes Thema. Ich würde nicht dorthin gehen.
@tyblu Ich stimme zu, aber IAR ist dafür bekannt, zum Beispiel kleinere Binärdateien als avr-gcc zu produzieren. Ich würde aber auch mikeselectricstuff zustimmen und ich denke, es ist ein vernünftiger Rat.

Solche Geräte werden oft in Assembler programmiert, was zu kleineren ausführbaren Dateien führt. Es lohnt sich, sich die Mühe zu machen und zu lernen, es zu benutzen.

Ich würde zustimmen, aber meiner Meinung nach ist es nicht das Ziel, ganze Geräte in Assembler zu programmieren (ich weiß, dass dies häufig geschieht, und ich habe dies auch getan), sondern in der Lage zu sein, zu decodieren und zu überprüfen, was der C-Compiler hinter Ihrem Rücken tut. Es bedeutet auch, dass Sie häufig den Compiler erraten und den Code, den Sie in C schreiben, optimieren können, um eine kleine ausführbare Größe zu erhalten.