#030 - Programowanie AVR z konsoli
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:

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.

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:

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.
Blink
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