AVR-GCC podstawowa kompilacja, toolchain, linki

Ten post to przeredagowana wersja mojej starej notatki (dawno nie robiłem nic na avrkach) - nie ma zamysłu w nim na jakąś serie itp.

Jak skompilować prostą aplikację używając tylko narzędzi terminalowych - krótki opis. Nawiasem IDE tak naprawdę to tylko nakładka na te narzędzia - każdy przycisk to uruchomienie jakiejś przedstawionej tu komendy np avrdude z parametrami, których nie musimy podawać z ręki, ale są zaszyte gdzieś w konfiguracji projektu i można je potem wyklikać.

A - aktualnie używam win11 + WSL i to jest robione w ubuntu z poziomu WSLa.

Ok - to instalacja podstawowych tooli:

sudo apt-get install gcc-avr avr-libc avrdude

czyli:

  • gcc-avr -> jest to cały “toolchain” - czyli sterownik kompilacji, kompilator i wszystkie potrzebne toole (binutils) - szczegóły o nich kiedy indziej, generalnie takie same toole są używane praktycznie wszędzie, więc warto się z nimi zapoznać - przydają sie w bardzo dziwnych sytuacjach
  • avr-libc -> standardowa bibioteka C dla właśnie avrów
  • avrdude -> program umożliwiający wgranie binarek do układów

Zobaczmy co nam się pobrało: avr-gcc

Trochę tego jest i każde narzędzie może się przydać kiedyś przy poważniejszym szukaniu błędów itp.

Aktualna wersja avr-gcc na ten moment to: avr-gcc (GCC) 5.4.0

Testowy prosty programik:

#include <stdio.h>

int main(void)
{
    int i = 0;

    while(1)
    {
        i++;
    }
}    

I kompilacja najpierw okrojona to:

avr-gcc main.c

I na tym etapie w sumie mogę skonczyć notatkę, bo znalazłem takie coś: kurs - podstawy AVR - pof i idąc jeszcze dalej - takie coś: kurs programowanie AVR - tam jest totalnie wszystko opisane, ale i tak sobie to wszystko przerobię po swojemu.

OK - więc po wcześniejszej komendzie otrzymaliśmy plik a.out. a_out_file

I tak naprawdę jest to plik “.elf” i widzimy jego podstawowe cechy:

  • Elf 32-bit LSB executable
  • Atmel AVR 8-bit
  • version 1 (SYSV)
  • statically linked
  • not stripped

Możemy sprawdzić jego rozmiar tego co zawiera: size

Sekcje wyciąga się za pomocą komendy:

avr-objdump -x a.out

Jest tam warta uwagi sekcja “trampoline”, która jest aktywna w prockach z większą ilością pamięci i generuje “warstwę pośrednią” przy skokach do funkcji znajdujących się w obszarach powyżej 64kB. Chodzi tutaj o to, że w adresowaniu dostępnym w AVR nie można wykonać tak dużego skoku jednym rozkazem.

Jeśli chcemy podejrzeć asemblera z sekcji wykonywalnych:

avr-objdump -d a.out

a jeśli skompilujemy wszystko z dodatkowymi informacjami debugowymi (czyli przełącznik -gx np -g3) to możemy te informacje wyciągnąć tak:

avr-objdump -g a.out

Tablica symboli to komenda:

avr-objdump -t a.out

Trochę OT się zrobił - idziemy więc dalej.

Wczęsniej była mowa o “okrojonej komendzie” - musimy zawsze przy kompilacji podać na jakiego procka chcemy używać - pouwzględnia to wszystkie różnice między wersjami itp. Jest to parametr “-m”. Można wylistować wszystkie platformy za pomocą:

avr-gcc --target-help

Tak więc pełna kompilacja to:

avr-gcc -mmcu=atmega8 main.c

Programowanie

Odczyt z pamięci procka

Mam podpiętego jakiegoś klona arduino + usbAsp.

Odczyt z procka to komenda:

avrdude -p m328p -P usb -c usbasp -U flash:r:flash.bin:r

Zaprogramowanie

Avrdude nie przyjmie nam wcześniej skompilowanego pliku - potrzebujemy go przerobić na np. bin albo hex narzędziem arv-objcopy:

avr-objcopy -O ihex -R .eeprom a.out program.hex

I zaprogramowanie to:

avrdude -p m328p -P usb -c usbasp -U flash:w:program.hex

Przy okazji jaka jest różnica między plikiem bin i hex - bin to “raw/surowe” dane, musimy dodatkowo sami określić na jaki adres mają być wrzucone. W hexie natomiast taki adres jest zaszyty w pliku plus w hexie tak maprawdę może być wiele takich plików binarnych z różnymi adresami startowymi.

To testowy program migający diodką:

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

int main(void)
{
    DDRB = 0xFF;
    while(1)
    {
        PORTB = 0xFF;
        _delay_ms(1000);
        PORTB= 0x00;
        _delay_ms(1000);
    }
}

Przy próbie kompilacji zobaczymy takie coś:

![kompilacja]{./files/030_4.png}

Generalnie musimy zdefiniować gdzieś symbol “F_CPU” - jest on potrzebny dla biblioteki delay. Żeby nie wpisywać go w źródła dam go w komendzie kompilacji - docelowo takie coś zawsze dodaje się do ustawień projektu w make/cmake/eclipse.

avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL main.c

Potem zrobienie hexa i wgranie:

avr-objcopy -O ihex -R .eeprom a.out program.hex
avrdude -p m328p -P usb -c usbasp -U flash:w:program.hex

I prosty blink blinkuje :)

Dodatkowa linkownia

  • fajny template dla AVR w CMAKE: link