Arduino, co w środku piszczy – #2 – proces programowania

Arduino, co w środku piszczy – #2 – proces programowania

Poznaliśmy już schemat Arduino – oczywiście omówiliśmy go pobieżnie, ale mam nadzieję, że będzie to zachętą do dalszego i dokładniejszego studiowania tego układu.

Teraz możemy już wgrać program do głównego mikrokontrolera. Oczywiście każdy, kto bawił się Arduino wie, że jest to bardzo proste. Wciskamy przycisk Wgraj i już! Co jednak dzieje się w tle?

Spróbujmy teraz zajrzeć pod maskę i zobaczyć jak naprawdę wygląda programowanie układu, który jest sercem naszego Arduino UNO.

Pusty mikrokontroler prosto ze sklepu

Zanim zobaczymy jak odbywa się programowanie, wykonajmy mały krok wstecz i pomyślmy jak można zaprogramować nową ATmege328. Cześć osób już wie, że Arduino wykorzystuje specjalny bootloader - przejdziemy do tego później. Można oczywiście kupić gotowy, już zaprogramowany układ, jednak wtedy sporo przepłacimy oraz stracimy okazję do poznania czegoś nowego.

Początkowo ta dokumentacja może nie wydawać się ciekawą lekturą na wakacje, ale to właśnie w niej znajdziemy wszystko co nasz mikrokontroler (a więc i Arduino) potrafi. Nawet jeśli początkowo czytanie będzie trudne, zachęcam do pobrania tego dokumentu i wracania do niego przy każdej okazji – np. żeby porównać jego zawartość z tym, co właśnie nauczyliśmy się robić z Arduino.

Do programowania będziemy potrzebowali odpowiedniego interfejsu (programatora). Nie musimy go od razu kupować, ale taka inwestycja będzie warta rozważenia. Jednak zanim pobiegniemy do sklepu, zobaczmy jakie są możliwości programowania układów ATmega328!

Metoda 1: Programowanie równoległe

Ten interfejs był dawniej bardzo popularny. Niestety wykorzystuje on sporo linii (wyprowadzeń) procesora i może wymagać wyjmowania układu oraz montowania w programatorze przy każdym wgrywaniu programu. Nie jest to zbyt wygodne, więc obecnie taki interfejs jest raczej rzadko wykorzystywany (chociaż ma swoje plusy np. podczas produkcji seryjnej, gdzie można szybko zaprogramować procesor przed jego montażem na płytce).

W dokumentacji znajdziemy sposób podłączenia układu do takiego programatora:

Podłączenie mikrokontrolera do programatora równoległego.

Podłączenie mikrokontrolera do programatora równoległego.

Schemat ten ilustruje główną wadę tej metody – dużą liczbę wyprowadzeń.

Metoda 2: debugWire

Zupełnym przeciwieństwem omówionej wcześniej metody jest interfejs debugWire autorstwa Atmel-a. Poza zasilaniem wykorzystywana jest tylko jedna linia! (reset):

Podłączenie mikrokontrolera z wykorzystaniem debugWire.

Podłączenie mikrokontrolera z wykorzystaniem debugWire.

Interfejs ten pozwala nie tylko na programowanie, ale również debugowanie programów. Dzięki temu wyszukiwanie błędów jest o wiele łatwiejsze. Niestety główna wada tego rozwiązania to cena programatora.

Jest to wydatek ponad 300 zł - wart rozważenia, jeśli chcemy profesjonalnie zajmować się tymi układami, jednak chyba za duży dla wielu hobbystów (jeśli ktoś zna tańszą metodę na użycie debugWire, to proszę o informację)!

Metoda 3: SPI

Interfejs ten pojawiał się w wielu kursach przy okazji komunikacji z zewnętrznymi modułami. Jego opis znajdziemy np. w kursie programowania STM32. Okazuje się, że SPI można wykorzystać do zaprogramowania mikrokontrolera ATmega328. W tym przypadku, mikrokontroler będzie pełnił rolę układu podrzędnego (slave).

Sposób podłączenia znajdziemy w dokumentacji:

Podłączenie mikrokontrolera z wykorzystaniem SPI.

Podłączenie mikrokontrolera z wykorzystaniem SPI.

Jak widzimy interfejs wykorzystuje raptem kilka linii: MOSI, MISO, SCK oraz reset. Jest więc dużo wygodniejszy niż programowanie równoległe, a zarazem o wiele tańszy niż firmowy programator. Do komunikacji przez SPI można wykorzystać inny mikrokontroler, np. drugi moduł Arduino, albo wspomniany STM32.

W sklepach elektronicznych dostępne są gotowe programatory podłączane przez USB do komputera PC, które w rzeczywistości wykorzystuję właśnie SPI. Popularnymi rozwiązaniami są chociażby programatory wykorzystujące protokół Stk500v2. Za ~50zł możemy stać się posiadaczem gotowego programatora. Sami możemy też taki programator przygotować (taniej).


Na schemacie Arduino widzieliśmy złącza ICSP (dla mikrokontrolera głównego oraz konwertera USB). Możemy do nich podłączyć programator Stk500v2 i programować ATmegę328 (oraz ATmegę16) bezpośrednio w Arduino.

Do komunikacji z programatorem można wykorzystać Atmel Studio, ale chyba lepszym rozwiązaniem jest wykorzystanie programu avrdude. Jest to niewielki program, dostępny jako open-source. Sterowanie odbywa się z linii poleceń, co ma swoje zalety (wrócimy do tego jeszcze). Jednak osoby przyzwyczajone do interfejsów graficznych też znajdą coś dla siebie: avrdude-gui.

Metoda 4: Bootloader

Poznaliśmy już możliwości programowania mikrokontrolera Atmega328 za pomocą sprzętowych interfejsów. Została nam do omówienia jeszcze jedna opcja – czyli programowanie przez sam procesor. W pierwszej chwili może się to wydawać nieco skomplikowane, jednak z taką opcją spotykamy się obecnie bardzo często.

Przykładowo wszystkie smartfony mają opcję aktualizacji oprogramowania (czasem nawet przydatną). Oznacza to, że możemy wprowadzić telefon w tryb aktualizacji, w czasie której do pamięci flash zostanie wgrane nowe oprogramowanie.

W tym celu musimy najpierw zaprogramować mikrokontroler specjalnym programem do wgrywania aktualizacji – ten program to właśnie bootloader. Jest to najzwyklejszy program, od pisanych przez nas różni się tylko dwiema rzeczami:

  • zastosowaniem – ma pozwalać na wgrywanie nowych wersji programu
  • lokalizacją w pamięci – musimy podzielić dostępną pamięć na dwa obszary:
    • naszą aplikację,
    • bootloader.

Domyślnie programy wgrywane są na początek dostępnej pamięci flash – czyli zaczynając od adresu zero. Natomiast bootloader umieszczany jest w górnych 512 bajtach pamięci (jego adres początkowy hexadecymalnie to 0x7E00).

Sekcje pamięci w mikrokontrolerach AVR.

Sekcje pamięci w mikrokontrolerach AVR.

Atmega328 posiada specjalne bity konfiguracyjne (Fuse-bity), które pozwalają na ustawienie sposobu jej działania. Są przechowywane w pamięci nieulotnej, więc raz zaprogramowane zachowują ustawioną konfigurację.

Dzięki nim można nieco zmienić domyślne zachowanie mikrokontrolera. Po pierwsze górne 512 bajtów może zostać „zabezpieczone” przed przypadkowym zapisem. Dostęp będzie możliwy, ale dopiero po ponownej zmianie fuse-bitów.

Druga zmiana dotyczy działania procesora po uruchomieniu (resecie). Domyślnie program aplikacji znajduje się pod adresem zero i instrukcja zapisana w tym miejscu jest wykonywana po starcie procesora. Zmieniając fuse-bity można sprawić, że zamiast aplikacji głównej zostanie uruchomiony bootloader. Tak właśnie konfigurowane są ATmegi dostarczane z Arduino.

Skąd wziąć bootloader Arduino?

Znajdziemy go w katalogu:

Plik optiboot.c to właśnie nasz bootloader. Jest on kompilowany standardowym kompilatorem C, czyli gcc-avr, gotowy do wgrania obraz to optiboot_atmega328.hex. Jeśli mamy programator stk500v2, możemy ten plik wgrać do nowego mikrokontrolera, zaprogramować fuse-bity i mamy gotowy nowy procesor dla Arduino.

Wszystko co niezbędne do kompilacji bootloadera oraz programowania używając avrdude znajdziemy w pliku Makefile we wspomnianym katalogu. Tam też zobaczymy jak wykonywana jest „relokacja” kodu bootloadera pod magiczny adres 0x7e00.

Jak działa bootloader?

W dużym uproszczeniu – bootloader oczekuje na polecenia przesłane poprzez UART (wykorzystując konwerter USB-UART oparty o ATmegę16). Jeśli takie dane zostaną odebrane, wchodzi w tryb programowania. Natomiast brak danych przez pewien czas sprawia że uruchamiany jest kod zapisany wcześniej w pamięci Flash pod adresem 0, czyli nasza aplikacja.

Emulacja jest na tyle dokładna, że do programowania można wykorzystać avrdude... I właśnie to robi nasz Sketch, kiedy naciskamy przycisk Wgraj. Najpierw kompiluje nasz program, a następnie uruchamia program avrdude i za jego pomocą programuje Flash. Na koniec restatuje mikrokontroler co pozwala na start naszego programu.

Oczywiście to samo moglibyśmy (szybciej) uzyskać wykorzystując sprzętowy programator stk500v2. Jednak Arduino daje nam jego namiastkę, bez dodatkowych kosztów. Ciekawym wnioskiem jest natomiast możliwość programowania Arduino bez Sketch-a. Można uruchomić avrdude (lub avrdude-gui) bezpośrednio, albo z poziomu ulubionego edytora bądź środowiska.

W kolejnej części zobaczymy jak Arduino wykorzystuje standardowy kompilator gcc. Dzięki temu będziemy mogli zupełnie pozbyć się (o ile będziemy chcieli) Sketch-a!

Autor: Piotr (Elvis) Bugalski
Redakcja: Damian (Treker) Szymański

Nawigacja kursu

arduino, Atmega, avr, programowanie, sketch