ATTiny13 - avr-gcc Hello World używa ponad 100 bajtów?

9

Próbuję napisać program dla ATTiny13. Mój problem polega na tym, że ma ogromne ograniczenia wielkości. Tworząc mój pierwszy program Hello World, zajęło 100 bajtów miejsca na program, aby światło się włączało i wyłączało! Czy są jakieś opcje, które mogę dać avr-gcc, aby zmniejszyć ten rozmiar? Ponadto, co jest w crt0? Nie przepadam za montażem AVR, więc nie rozumiem go zbyt wiele…

Nie chcę schodzić do montażu dla tego projektu.

Earlz
źródło
Na marginesie, niektórzy nazwaliby to programem „Blinky”.
Johan
1
@Johan cóż, nie byłem pewien, jak przeliterować „blinkenlights”
Earlz

Odpowiedzi:

9

crt0 to procedura uruchamiania dla uC. Procedury wykonują konfigurację rejestrów, a także inicjalizację danych.

Czy 100 bajtów zawiera tablicę wektorów przerwań? Nie jestem pewien co do ATtiny13, ale ATtiny25 / 45/85 ma 15 wektorów przerwań. Zajmie to 30 bajtów.

gcc ma opcję łączenia w twoim crt0. Możesz wziąć plik AVR crt0.S i zmodyfikować go. To nie jest bardzo długie, więc nie powinno być trudne.

jluciani
źródło
Nie mogę znaleźć źródła crt0, ale w crt1 znajduje się coś, co wydaje się być tabelą wektorów przerwań. Może o to chodzi
Earlz
Nie mogę go również znaleźć w moim systemie :( Skompilowałem wszystkie narzędzia ze źródła, więc pomyślałem, że będzie tam. pojawiła się optymalizacja. Być może w tych dokumentach jest kilka wskazówek
jluciani,
@jlu Próbuję ustalić różnicę między nimi, ale nie udało mi się jeszcze nic dobrego na przepełnieniu stosu: stackoverflow.com/questions/2709998/...
Earlz
2
avr-libc ma inną CRT dla każdego typu układu AVR, a standardowe dystrybucje avr-libc obejmują tylko wersję pliku .o. Ten dla ATtiny13 znajduje się na [avr-libc-path] /avr-3/lib/crttn13.o
todbot
@todbot hmm. Ach, ok tak, mam to/avr-libc-1.6.7/avr/lib/avr2/attiny13/crttn13.S
Earlz
19

Możesz użyć avr-objdump -d .elf, aby zobaczyć, co jest generowane:

Przeanalizujmy to trochę:

[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>

Tablica wektorów przerwań 20 bajtów (przynajmniej niektóre wpisy można pominąć, jeśli nalegasz i obiecujesz, że nigdy nie włączysz odpowiednich przerwań).

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>

Czyści SREG (nie jestem pewien, czy to jest naprawdę potrzebne), zapisuje 0x9f (RAMEND) do SPL (wskaźnik stosu) i przeskakuje do main. Ostatni rjmp jest trochę zbędny. (możesz obiecać, że nigdy nie wrócisz z głównego)

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

Domyślna procedura przerwania dla tych przerwań, które nie zostały zastąpione w C. (takie same reguły jak dla wektorów __)

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>

Twój główny proc. Mocno.

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

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

Te dwa nie są bardzo przydatne. _exit jest prawdopodobnie wymagany przez standard C i __stop_program jest potrzebny, aby działał tak, jak powinien.

jpc
źródło
16

Jakie jest twoje ostateczne zastosowanie? ATtiny13 ma 1kB flasha i możesz z tym wiele zrobić w C. Crt0 to środowisko uruchomieniowe C avr-libc. Zawiera rzeczy takie jak obsługa stosu, dzięki czemu można używać funkcji z argumentami i zwracanymi wartościami.

100 bajtów na osadzoną konfigurację C nie jest takie złe i ma stały rozmiar. Podwojenie linii logiki programu niekoniecznie spowoduje, że będzie to 200 bajtów. Na jakim poziomie optymalizacji się kompilujesz? Powinieneś być w „-Os”. Jak to kompilujesz? Pliki Makefile w projektach demonstracyjnych dostępnych na stronie avr-libc są całkiem dobre i wyczerpujące.

Prosty program włączania / wyłączania LED poniżej zajmuje 62 bajty na ATtiny13 z „-Os” na avr-gcc 4.3.3. z CrossPack-AVR:

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

int main (void)
{
    DDRB | = _BV (PB3);
    while (1) { 
        PORTB | = _BV (PB3);
        _delay_ms (200);
        PORTB & = ~ _V (PB3);
        _delay_ms (200);
    }
}

Usunięcie wywołań _delay_ms () powoduje, że zajmuje on 46 bajtów.

Większy przykład na ATtiny13 to moje prototypy Smart LED . Ten kod zawiera 3-kanałowe oprogramowanie PWM, konwersję kolorów HSV na RGB, automat stanów i odczytuje dwa przyciski. Nie jest dobrze napisany i ma 864 bajtów. W wersji avr-gcc 3.x był jeszcze mniejszy. (z jakiegoś powodu avr-gcc 4 spowodował, że prawie wszystkie programy wzrosły o kilka bajtów)

todbot
źródło
avr-gcc -std=c99 -Wall -Os -mmcu=attiny13 -o hello.out helloworld.cjest odpowiednią linią w moim makefile (utworzonym przez siebie). i używam prawie identycznego kodu, z wyjątkiem tego, żeby przełączyć diodę LED, której używam PORTB &= ~(1 << LED);i tak
Earlz
I tak, rozmiar jest stały, ale nawet 46 bajtów wydaje się trochę ciężki, jeśli wszystko, co musi zrobić, to ustawić ramkę stosu
Earlz
2

Jeśli brakuje Ci miejsca, wypróbuj wbudowany stół roboczy IAR - ich bezpłatna wersja „kickstart” ma limit rozmiaru kodu słowa 4K, więc wystarczająco dużo dla ATTiny i prawdopodobnie lepsza optymalizacja niż gcc

mikeselectricstuff
źródło
1
Porównania optymalizacyjne są przedmiotem dużej rywalizacji. Nie poszedłbym tam.
tyblu,
1
@tyblu Zgadzam się, ale IAR jest znany z tworzenia mniejszych plików binarnych niż na przykład avr-gcc. Zgodziłbym się również z mikeselectricstuff i myślę, że to rozsądna rada.
Morten Jensen
1

Takie urządzenia są często programowane w asemblerze, co powoduje mniejsze pliki wykonywalne. Warto podjąć wysiłek i nauczyć się z niego korzystać.

Leon Heller
źródło
1
Zgodziłbym się, ale celem IMHO nie jest programowanie całych urządzeń w asemblerze (wiem, że tak się często robi i ja też to zrobiłem), ale możliwość dekodowania i weryfikacji działania kompilatora C za twoimi plecami. Oznacza to również, że często będziesz w stanie odgadnąć kompilator i zoptymalizować kod napisany w C, aby uzyskać mały rozmiar pliku wykonywalnego.
JPC