Arduino Bootloader

Czy ktoś może wyjaśnić, jak działa Arduino bootloader? Nie szukam tutaj odpowiedzi na wysokim poziomie, przeczytałem kod i rozumiem jego istotę.

Istnieje kilka interakcji protokołu, który dzieje się między Arduino IDE i kodu bootloadera, ostatecznie w wyniku szeregu wbudowanych instrukcji montażu, które samo zaprogramować flash z programu przesyłanego przez interfejs szeregowy.

To, czego nie rozumiem, to on line 270:

void (*app_start)(void) = 0x0000; 

...które uznaję za deklarację i inicjalizację do NULL wskaźnika funkcji. Są kolejne wywołania app_start w miejscach, w których bootloader ma delegować do wykonania kodu załadowanego przez użytkownika.

Z pewnością, w jakiś sposób app_start musi w pewnym momencie uzyskać wartość non-NULL, aby to wszystko się połączyło. Nie widzę tego w kodzie bootloadera... czy jest to magicznie połączone przez program, który jest ładowany przez bootloader? Przypuszczam, że główne bootloadera jest punktem wejścia do oprogramowania po zresetowaniu układu.

Owinięty w 70 lub tak linii montażu musi być tajny pierścień dekodera, który mówi główny program, gdzie app_start naprawdę jest? A może to jakaś ukryta wiedza, którą wykorzystuje Arduino IDE? Wiem tylko, że jeśli ktoś nie zmieni app_start na punkt gdzie indziej niż 0, kod bootloadera po prostu wiruje na siebie na zawsze... więc co to jest trick?

Edit

Jestem zainteresowany próbą przeniesienia bootloadera do małego AVR, który nie ma oddzielnej pamięci dla kodu boot loadera. Ponieważ staje się dla mnie oczywiste, że kod bootloadera opiera się na pewnych Ustawieniach bezpieczników i obsłudze chipów, myślę, że jestem naprawdę zainteresowany, wiedząc, co trzeba zrobić, aby przenieść bootloader do chipa, który nie ma tych bezpieczników i wsparcia sprzętowego (ale nadal ma zdolność do samodzielnego programowania)?

Author: vicatcu, 2010-09-06

2 answers

On NULL

Adres 0 nie tworzy wskaźnika null. "Wskaźnik null" jest czymś bardziej abstrakcyjnym: specjalną wartością, którą odpowiednie funkcje powinny uznać za nieprawidłową. C mówi, że wartość specjalna wynosi 0 i podczas gdy język mówi, że dereferencja jest "niezdefiniowanym zachowaniem", w prostym świecie mikrokontrolerów zwykle ma bardzo dobrze zdefiniowany efekt.

Bootloadery ATmega

Normalnie, po resecie, licznik programu AVR (PC) jest inicjowany do 0, w ten sposób mikrokontroler rozpoczyna wykonywanie kodu pod adresem 0.

Jeśli jednak ustawiony jest bezpiecznik resetowania rozruchu ("BOOTRST"), licznik programu jest inicjowany na adres bloku w górnej części pamięci (gdzie zależy to od ustawień bezpieczników, zobacz a datasheet (PDF, 7 MB) dla szczegółów). Kod, który się tam zaczyna, może zrobić wszystko - jeśli naprawdę chcesz, możesz umieścić tam swój własny program, jeśli używasz ICSP (bootloadery generalnie nie mogą nadpisać siebie).

Często jednak jest to specjalny program - bootloader -który jest w stanie odczytać dane z zewnętrznego źródła (często przez UART, I2C, CAN itp.) do przepisać kod programu (przechowywany w pamięci wewnętrznej lub zewnętrznej, w zależności od mikro). Bootloader zazwyczaj szuka "specjalnego zdarzenia", które może być dosłownie wszystkim, ale dla rozwoju jest najwygodniej coś na magistrali danych, Że Będzie Pobierać nowy kod. (Dla produkcja może to być specjalny poziom logiki na pinie, ponieważ można go sprawdzić niemal natychmiast.) Jeśli bootloader zobaczy specjalne zdarzenie, może przejść w tryb bootloading, w którym zmieni pamięć programu, w przeciwnym razie przekaże kontrolę do kodu użytkownika.

Na marginesie, celem bootloadera fuse i górnego bloku pamięci jest umożliwienie użycia bootloadera z bez modyfikacji oryginalnego oprogramowania (o ile nie rozszerza się aż do Bootloadera adres). Zamiast migać tylko z oryginalnym HEX i pożądane bezpieczniki, można migać oryginalny HEX, bootloader, i zmodyfikowane Bezpieczniki, i presto, bootloader dodany.

W każdym razie, w przypadku Arduino, które, jak sądzę, używa protokołu z STK500 , próbuje komunikować się przez UART, a jeśli dostanie albo żadnej odpowiedzi w wyznaczonym czasie:

uint32_t count = 0;
while(!(UCSRA & _BV(RXC))) { // loops until a byte received
    count++;
    if (count > MAX_TIME_COUNT) // 4 seconds or whatever
        app_start();
}

Lub jeśli błąd zbyt dużo, otrzymując nieoczekiwaną odpowiedź:

if (++error_count == MAX_ERROR_COUNT)
    app_start();

Przechodzi kontrolę powrót do głównego programu, znajduje się na 0. W źródle Arduino widzianym powyżej, odbywa się to przez wywołanie app_start();, zdefiniowane jako void (*app_start)(void) = 0x0000;.

Ponieważ jest to wywołanie funkcji C, zanim komputer przeskoczy do 0, przesunie bieżącą wartość komputera na stos, który zawiera również inne zmienne używane w bootloaderze (np. count i error_count z góry). Czy to kradnie RAM z twojego programu? Cóż, po ustawieniu komputera na 0, operacje, które są wykonywane rażąco "naruszają" to, co właściwe C funkcja (która w końcu wróci) powinna wystarczyć. Wśród innych kroków inicjalizacji, resetuje wskaźnik stosu (skutecznie wymazując stos wywołań i wszystkie zmienne lokalne), odzyskując PAMIĘĆ RAM. Zmienne globalne / statyczne są inicjalizowane na 0, których adres może swobodnie pokrywać się z tym, czego używał bootloader, ponieważ programy bootloadera i użytkownika zostały skompilowane niezależnie.

Jedynymi trwałymi efektami bootloadera są modyfikacje sprzętu (peryferyjne) rejestry, których dobry bootloader nie pozostawi w niekorzystnym stanie(włączanie urządzeń peryferyjnych, które mogą marnować energię podczas próby snu). Ogólnie dobrą praktyką jest również pełne zainicjowanie urządzeń peryferyjnych, których będziesz używać, więc nawet jeśli bootloader zrobił coś dziwnego, ustawisz go tak, jak chcesz.

ATtiny Bootloaders

Na ATtinys, jak wspomniałeś, nie ma luksusu z bezpieczników bootloadera ani pamięci, więc Twój kod zawsze będzie zaczynał się od adresu 0. Być może będziesz w stanie umieścić Twój bootloader na wyższe strony pamięci i skieruj na niego wektor resetowania, a następnie za każdym razem, gdy otrzymasz nowy plik szesnastkowy do flashowania, wykonaj polecenie, które jest pod adresem 0: 1, zastąp go adresem bootloadera, a następnie zapisz zastąpiony adres gdzie indziej, aby wywołać normalne wykonanie. (Jeśli jest to RJMP ("relative jump") wartość będzie oczywiście musiała zostać przeliczona)

 37
Author: Nick T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-08 23:10:45

Edit

Jestem zainteresowany próbą przeniesienia bootloadera do małego AVR, który nie ma oddzielnej pamięci dla kodu boot loadera. Ponieważ staje się dla mnie oczywiste, że kod bootloadera opiera się na pewnych Ustawieniach bezpieczników i obsłudze chipów, myślę, że jestem naprawdę zainteresowany, wiedząc, co trzeba zrobić, aby przenieść bootloader do chipa, który nie ma tych bezpieczników i wsparcia sprzętowego (ale nadal ma zdolność do samodzielnego programowania)?

W zależności od ostatecznego celu może łatwiej będzie stworzyć własny bootloader, zamiast próbować go portować. Naprawdę musisz tylko nauczyć się kilku przedmiotów do tej części.

1) uart TX

2) uart rx

3) samodzielne programowanie Flasha

Które można nauczyć się oddzielnie, a następnie połączyć w bootloader. Będziesz chciał część, którą możesz użyć spi lub cokolwiek do napisania Flasha, tak że jeśli twój bootloader nie działa lub cokolwiek pochodzi z części zostanie pomieszane, nadal możesz kontynuować rozwój.

Niezależnie od tego, czy przenosisz lub obracasz swój własny, nadal będziesz musiał zrozumieć te trzy podstawowe rzeczy w odniesieniu do tej części.

 1
Author: old_timer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-23 21:06:34