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

9

Ich versuche ein Programm für das ATTiny13 zu schreiben. Mein Problem ist, dass es enorme Größenbeschränkungen gibt. Nun, als ich mein erstes Hello World-Programm machte, brauchte ich 100 Bytes Programmspeicher, um ein Licht ein- und auszuschalten! Gibt es Optionen, die ich avr-gcc geben kann, um diese Größe zu verringern? Auch was ist in der crt0? Ich bin nicht besonders begeistert von der AVR-Montage, daher verstehe ich das nicht sehr.

Ich möchte für dieses Projekt nicht zur Montage gehen müssen.

Earlz
quelle
Als kleine Randnotiz würden einige Leute das ein "Blinky" -Programm nennen.
Johan
1
@ Joan gut ich war nicht sicher, wie man "blinkenlights" buchstabiert
Earlz

Antworten:

9

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

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

gcc hat eine Option zum Verknüpfen Ihres crt0. Sie können die AVR-Datei crt0.S nehmen und ändern. Es ist nicht sehr lang und sollte daher nicht schwierig sein.

jluciani
quelle
Ich kann die crt0-Quelle nicht finden, aber in crt1 gibt es eine Interrupt-Vektortabelle. Vielleicht ist es das
Earlz
Ich kann es auch auf meinem System nicht finden :( Ich habe alle Tools aus dem Quellcode kompiliert, also dachte ich, es wäre da. Wenn Sie nach "crt0.S atmel" googeln, ein paar Atmel-App-Hinweise zu Startup, crt0 und gcc Optimierung kommt auf. Vielleicht gibt es einige Hinweise in diesen Dokumenten.
jluciani
@jlu Ich versuche, den Unterschied zwischen den beiden herauszufinden, aber noch nichts Gutes auf Stack Overflow bekommen: stackoverflow.com/questions/2709998/…
Earlz
2
avr-libc hat für jeden AVR-Chip-Typ eine andere CRT, und die Standard-avr-libc-Distributionen enthalten nur die .o-Version der Datei. Die für den ATtiny13 befindet sich unter [avr-libc-path] /avr-3/lib/crttn13.o
todbot
@todbot hmm. Ah, ok ja, ich habe es in/avr-libc-1.6.7/avr/lib/avr2/attiny13/crttn13.S
Earlz
19

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

Lassen Sie es uns ein wenig analysieren:

[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-Byte-Interrupt-Vektortabelle (zumindest einige der Einträge könnten weggelassen werden, wenn Sie darauf bestanden und versprochen haben, die entsprechenden Interrupts niemals zu aktivieren).

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 nicht sicher, ob dies wirklich benötigt wird), schreibt 0x9f (RAMEND) in SPL (den Stapelzeiger) und springt zu main. Der letzte rjmp ist irgendwie redundant. (Sie könnten versprechen, niemals von der Hauptstraße zurückzukehren)

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

Standard-Interrupt-Prozedur für diese Interrupts, bei denen keine in C überschrieben wurde (dieselben 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>

Dein Hauptprozess. Fest.

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 ordnungsgemäß funktioniert.

jpc
quelle
16

Was ist Ihre spätere Bewerbung? Ein ATtiny13 hat 1 KB Flash und damit kann man in C viel anfangen. Das crt0 ist die avr-libc C-Laufzeit. Es enthält Dinge wie die Stapelbehandlung, sodass Sie Funktionen mit Argumenten und Rückgabewerten verwenden können.

100 Bytes für das Embedded C-Setup sind nicht schlecht und haben eine konstante Größe. Das Verdoppeln der Zeilen der Programmlogik macht 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 main (nichtig)
{
    DDRB | = _BV (PB3);
    während (1) { 
        PORTB | = _BV (PB3);
        Verzögerung (200);
        PORTB & = ~ _BV (PB3);
        Verzögerung (200);
    }}
}}

Durch Entfernen der Aufrufe von _delay_ms () werden 46 Byte benötigt.

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 mit 864 Bytes. Unter avr-gcc 3.x war es noch kleiner. (Aus irgendeinem Grund hat avr-gcc 4 fast alle Programme um einige Bytes wachsen lassen)

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

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

mikeselectricstuff
quelle
1
Optimierungsvergleiche sind umstritten. Ich würde nicht dorthin gehen.
Tyblu
1
@tyblu Ich stimme zu, aber IAR ist dafür bekannt, kleinere Binärdateien als avr-gcc zu produzieren. Ich würde auch mikeselectricstuff zustimmen und ich denke, es ist ein vernünftiger Rat.
Morten Jensen
1

Solche Geräte werden häufig im Assembler programmiert, was zu kleineren ausführbaren Dateien führt. Es lohnt sich, sich anzustrengen und zu lernen, es zu benutzen.

Leon Heller
quelle
1
Ich würde zustimmen, aber meiner Meinung nach besteht das Ziel nicht darin, ganze Geräte in der Baugruppe zu programmieren (ich weiß, dass dies häufig gemacht wird und ich habe dies auch getan), sondern in der Lage zu sein, zu dekodieren und zu überprüfen, was der C-Compiler hinter Ihrem Rücken tut. Dies bedeutet auch, dass Sie häufig in der Lage sind, den Compiler zu erraten und den in C geschriebenen Code zu optimieren, um eine kleine ausführbare Größe zu erhalten.
JPC