Bootloader dla mikrokontrolerów STM32 Aktualizacja oprogramowanie z zastosowaniem karty SD lub przez USB


KURS
Bootloader dla
mikrokontrolerów STM32
Aktualizacja oprogramowanie
z zastosowaniem karty SD lub
przez USB
Nie jest dla nikogo tajemnicą, że mikrokontroler można kowanego do aplikacji przemysłowych, pra-
cującego z interfejsem USART, z którego wy-
zaprogramować z użyciem programatora. Współczesne
korzystano jedynie pliki startowe. Dostęp do
mikrokontrolery mogą być programowane zarówno za pomocą
karty SD i system plików FAT w wersji tylko
programatora, jak i w systemie. Niżej zaprezentujemy metodę
do odczytu zostały napisane na od podstaw.
będącą wariantem programowania w systemie, a mianowicie
Są one na tyle uniwersalne, że z łatwością
aktualizację oprogramowania przez interfejs USB lub
można je stosować w różnych urządzeniach.
z zastosowaniem karty SD podłączonej poprzez SPI. Atrakcyjna jest
Oprogramowanie obsługujące USB, powsta-
zwłaszcza ta druga metoda, ponieważ wymaga tylko maleńkiej karty ło trochę wcześniej. Jest ono na tyle uni-
wersalne i łatwe w konfiguracji, że w prosty
SD, którą można zabrać ze sobą chociażby do kieszeni.
sposób można je przenosić na różne proce-
sory. Do obsługi standardowych peryferiów
Większość obecnie produkowanych mi- podłączenia jest port SPI, który jest wspie- (z wyjątkiem USB) zastosowano zmodyfiko-
krokontrolerów ma pamięć FLASH, która rany przez część kart. Kolejnym kandyda- wane w celu zmniejszenia kodu wynikowego
może być modyfikowana wiele razy. Dodatko- tem, jest interfejs USB służący do połączenia biblioteki producenta.
wo, producenci wychodząc naprzeciw użyt- urządzenia z komputerem PC, który wypiera Jak wspomniano wcześniej, sam bootlo-
kownikom udostępniają programowe interfej- w tej roli UART. Dodatkowo, nowe mikro- ader jest umieszczony w pamięci FLASH,
sy pozwalające na dostęp do tychże pamięci kontrolery mają często standardowo wbudo- a dokładniej na jej początku. Rozwiązanie
z poziomu aplikacji, przez co można je mo- wany kontroler USB w swoją strukturę. to jest konieczne, gdyż po restarcie procesor
dyfikować bez konieczności użycia programa- Z wymienionych wyżej powodów, zde- musi mieć możliwość uruchomienia go, nie-
tora. Nawet jeśli programator nie jest drogim cydowałem się na użycie tych dwóch inter- zależnie od tego, czy jest w nim poprawny
urządzeniem, to sama konieczność rozebrania fejsów, czyli USB i SD (SPI) jako dwie meto- program, czy nie. Jako że po restarcie pro-
obudowy może być dość uciążliwa. Najczę- dy uaktualnienia oprogramowania w proce- cesor skacze do początku pamięci FLASH
ściej stosowanym współcześnie rozwiąza- sorze rodziny STM32. (przy odpowiednim ustawieniu linii BOOT0
niem jest programowanie w systemie, gdyż i BOOT1) dlatego najłatwiej było umieścić
podłączając się np. przez często używany Bootloader bootloader na początku tego obszaru. Daje
przez nasze urządzenie interfejs dokonujemy Bootloader jest małym programem to nam również dużą uniwersalność, gdyż
szybko i prosto operacji serwisowych. umieszczonym obok programu użytkowni- nie trzeba się już martwić wgraniem go
Programując w ten sposób mikrokontro- ka. Jego zadaniem jest pobranie przez de- w odpowiednie miejsce  ładujemy go raz,
lery STM32 zauważyłem możliwość zrobie- dykowany interfejs nowszej wersji aplikacji tak jak zwykły program, za pomocą progra-
nia uniwersalnej aplikacji, która umieszczo- użytkownika. Umieszczono go na początku matora JTAG lub przez USART1. Bootloader
na obok docelowego programu będzie służyć wbudowanej w procesor pamięci FLASH, po starcie procesora uruchamia się z pamię-
łatwej wymianie oprogramowania. tak aby był domyślnie uruchamiany po włą- ci FLASH, ale zaraz na początku swojego
Pytaniem jest, jaki interfejs najlepiej czeniu mikrokontrolera. Dzięki temu jest działania kopiuje samego siebie do pamięci
nadaje się do tego celu? Najczęściej nowe zawsze uruchamiany przed aplikacją użyt- SRAM, a następnie skacze do swojej  kopii
mikrokontrolery wyposażone są w interfejs kownika, przez co może wystartować nawet i od tego momentu działa już z poziomu pa-
UART, SPI, I2C. UART nadawałby się świet- wtedy, gdy aplikacja użytkownika jest w ja- mięci RAM. Rozwiązanie to jest konieczne
nie do komunikacji z komputerem, jednak kiś sposób uszkodzona lub wadliwa. Po uru- ze względu na niemożność równoczesnego
nowe komputery nie mają już interfejsu chomieniu sprawdza się, czy bootloader ma czytania i programowania pamięci FLASH.
RS232, z którym UART łączy się przez układ przejść do aktualizacji. Jeżeli nie, to wyłącza Następnie wykonywana jest inicjalizacja
pośredniczący. on wszystkie uaktywnione interfejsy proce- niezbędnych peryferiów i sprawdzenie, czy
Z drugiej strony wiele urządzeń ma moż- sora i wywołuje aplikację użytkownika. bootloader ma być wywołany. Dzięki temu
liwość rejestrowania wyników swojej pracy W artykule opisywane są dwie wersje rozwiązaniu nie dokonujemy za każdym
na karcie SD. Najprostszym sposobem jej zbudowane na szkielecie bootloadera dedy- razem aktualizacji oprogramowania, lecz ro-
60 ELEKTRONIKA PRAKTYCZNA 10/2009
Bootloader dla mikrokontrolerów STM32
cisk jest wciśnięty. Używany jest do tego, nia, wówczas kasuje ten rejestr i przechodzi
aby można było zaktualizować program po do wymiany programu. W tym rozwiązaniu
starcie urządzenia niezależnie od tego, czy używany jest jeden z rejestrów Backup, dla-
w pamięci znajduje się już jakiś program, tego jeżeli użytkownikowi bardzo zależy na
czy nie. Jest to pomocne, gdy zastosowaniu go do innego przeznaczenia, to
aplikacja użytkownika zawiera wówczas może użyć drugiej metody  polega
błędy i program zawiesza się tuż ona na skoku do funkcji, której adres znajduje
po starcie. się w wektorze przerwań samego bootloadera
Trzeci sposób pozwala na umieszczenie na pozycji 12 (SVC_Handler). Pod tym wskaz-
w programie użytkownika dosłownie kilku nikiem kryje się adres kopii wektora RESET,
linii kodu, które powodują wywołanie bootlo- którego wywołanie powoduje natychmiasto-
adera. Jest to możliwe na dwa sposoby. Pierw- we przejście do aktualizacji, bez sprawdzania
szy, to zapisanie do jednego z rejestrów Bac- jakichkolwiek warunków.
kup procesora konkretnej wartości i restart Bootloader w wersji SD działa na wszyst-
układu. Po nim bootloader, podczas spraw- kich wersjach STM32, ponieważ potrzebuje
dzania warunków wejścia w tryb aktualizacji, do prawidłowej pracy jedynie jednego inter-
sprawdza zawartość pierwszego z rejestrów fejsu SPI i jednej linii GPIO. Co do USB, to
Backup. Jeżeli jego zawartość jest odpowied- w grę wchodzą jedynie modele z zaimple-
mentowanym kontrolerem, gdyż tylko te wer-
sje obsługiwane są przez oprogramowanie.
Flash
Pamięć FLASH, w mikrokontrolerze
STM32 zawiera dedykowany kontroler uła-
twiający do niej dostęp
od strony oprogramowa-
nia. O ile odczyt pamię-
ci można realizować po
prostu przez odnoszenie się do odpowied-
nich adresów, o tyle kasowanie i zapis nie
są już tak łatwe i wymagają odpowiednich
czynności. Z tego powodu producent zaim-
plementował w mikrokontrolerze specjalny
kontroler o nazwie Flash Program/Erase Con-
troller (FPEC).
W mikrokontrolerach STM32 pamięć
FLASH zorganizowana jest w strony, których
rozmiar wynosi 1 kB lub 2 kB, zależnie od
jej wielkości. Ulokowana jest w przestrzeni
adresowej procesora, począwszy od adresu
0x08000000.
Po restarcie procesora kontroler pamięci
Rys. 1. Procedura programowania nieulotnej chroni ją przed zapisem. Dzięki
pamięci FLASH mikrokontrolera STM32 temu nie ma możliwości przypadkowego jej
uszkodzenia. Aby dokonywać jakichkolwiek
bimy to tylko w ściśle określonych przypad- zmian należy najpierw odblokować moż-
kach. Są to: liwość zapisu. Dokonuje się tego poprzez
 Brak jakiegokolwiek oprogramowania wpisanie do rejestru FLASH_KEYR kontro-
użytkownika w pamięci FLASH. lera pamięci kolejno dwóch wartości: KEY1
 Spełnienie warunku wymuszenia przej- = 0x45670123, a następnie KEY2 = 0xCDE-
ścia w tryb bootloadera. F89AB. Od tego momentu można dokonywać
 Bootloader został wywołany z poziomu na pamięci operacji kasowania i zapisu, aż
aplikacji użytkownika. do momentu wystąpienia błędu, który bloku-
Sprawdzenie pierwszego warunku po- je pamięć do kolejnego restartu.
lega na odczytania pierwszych komórek Zapis pamięci. Operacji zapisu do pa-
wektora przerwań programu użytkownika mięci FASH dokonuje się za pomocą kontro-
(wskaznik stosu i wektor RESET) i sprawdze- lera FPEC, zgodnie z algorytmem pokazanym
nia czy nie są przypadkiem skasowane. Ten na rys. 1. Do pamięci jednocześnie zapisy-
prosty test oczywiście nie jest w stanie wy- wane są 2 bajty. Najpierw należy w rejestrze
kryć, czy aplikacja nie zawiera błędów, nie- FLASH_CR ustawić bit PG informujący kon-
mniej jednak wystarcza do stwierdzenia, czy troler o tym, że pamięć będzie programo-
w ogóle znajduje się ona w pamięci. wana. Po tej czynności można dokonywać
Drugi sposób realizowany jest przez Rys. 2. Procedura kasowania pamięci zapisu  wpisujemy 2 bajty nowej zawarto-
sprawdzenie stanu jednego z pinów GPIO FLASH mikrokontrolera STM32 metodą ści bezpośrednio pod adres, pod którym ma
procesora, tzn. czy podłączony tam przy-  strona po stronie być ona umieszczona. Następnie czekamy
ELEKTRONIKA PRAKTYCZNA 10/2009 61
KURS
za zakończenie operacji, po czym sprawdza-
my, czy zapis został dokonany poprawnie.
Przy braku jakichkolwiek błędów, możemy
przejść do zapisu kolejnego słowa. Po zapisa-
niu całej strony kasujemy bit PG.
Kasowanie Pamięci. Kasowanie pamięci
Flash w mikrokontrolerze STM32 może być
wykonane na dwa sposoby: strona po stronie
lub całość pamięci. My oczywiście używamy
tylko kasowania metody  strona po stronie ,
gdyż w pamięci znajduje się nasz bootloader,
który nie wolno usuwać. Procedurę kaso-
wania strona po stronie przedstawiono na
rys. 2.
Operację kasowania rozpoczynamy od
ustawienia w rejestrze FLASH_CR bitu PER
informującego kontroler, że będziemy do-
konywać operacji kasowania strony (Page Rys. 4. Podłączenie portu USB
Erase). Następnie do rejestru FLASH_AR
wpisujemy adres strony, którą kasujemy  3 wektory przerwań skojarzone z kontrole- jedynie drugie wydaje się byś sensowne,
i ustawiamy w rejestrze FLASH_CR bit STRT. rem przerwań NVIC: transmisja o niskim zwłaszcza że taki protokół został już kiedyś
W tym momencie rozpoczyna się procedura priorytecie, transmisja o wysokim priory- zdefiniowany i to oficjalnie jako jedna ze
kasowania. W kolejnym kroku czekamy na tecie, wyjście procesora z trybu Suspend. standardowych klas urządzeń USB. Mowa tu
jej zakończenie, po czym sprawdzamy, czy Do obsługi kontrolera zastosowano uni- o klasie DFU (ang. Device Firmware Upgra-
strona została skasowana poprawnie poprzez wersalną warstwę USB. Pozwala ona w ła- de), której dokumentację można pobrać ze
odczytanie jej zawartości. twy sposób pisać programy korzystające strony www.usb.org.
z tego interfejsu prawie niezależnie od zasto- USB DFU. Klasa DFU pozwala na aktu-
Bootloader USB sowanego układu peryferyjnego (procesora). alizowanie oprogramowanie urządzenia bez-
Budowę aplikacji bootloadera pracujące- Na rys. 4 pokazano przykładowe podłącze- pośrednio za pomocą interfejsu USB. Defi-
go z portem USB przedstawiono na rys. 3. nie złącza USB-B do mikrokontrolera. Poza niuje dwa tryby pracy: tryb pracy normalnej
Rozwiązanie to bazuje na wbudowanym liniami D+ i D , do procesora podłączone  użytkownika (Run Time Mode) i tryb DFU
w część mikrokontrolerów rodziny STM32 są również dwie dodatkowe linie. Pierwsza (DFU Mode).
sprzętowym kontrolerze USB Full-Speed De- z nich to USB_STM_PWR_DETECT służąca W trybie pierwszym urządzenie USB dzia-
vice. Jego główne cechy to: do wykrywania napięcia zasilającego do- ła normalnie, zgodnie z założeniami, z jakimi
 Pełna zgodność ze standardem 2.0 full- cierającego bezpośrednio z komputera PC zostało zaprojektowane, np. jest to drukarka,
speed. i przesyłanego po kablu USB. Fakt wykrycia skaner, konwerter USB/RS232, pamięć ma-
 Do 8 konfigurowalnych punktów końco- podłączenia do Hosta zgłasza się stanem wy- sowa itp. Poza tymi standardowymi możli-
wych. sokim, zaś sama linia skonfigurowana jest wościami ma ono jeden dodatkowy interfejs
 Pełne sprzętowe kodowanie/dekodowa- w procesorze jako przerwanie zewnętrzne. USB  interfejs DFU, który nie ma żadnych
nie ramek USB (CRC, NRZI, bit-stuffing Druga to USB_STM_PULL_UP wykorzysty- punktów końcowych. Tworząc taki dodatkowy
itp.). wana do programowego włączania lub wyłą- interfejs dodajemy do deskryptora konfigu-
 Wsparcie w każdym punkcie końcowym czania rezystora 1,5 kV na linii D+. Sygnały racji dwa dodatkowe deskryptory: interfejsu
dla wszystkich typów transmisji (kontro- USBDM i USBDP podłączamy do dedykowa- i funkcjonalny DFU (DFU Functional Descrip-
lna, przerwaniowa, izochroniczna i ma- nych linii mikrokontrolera, natomiast pozo- tor). Host komunikuje się z tym interfejsem za
sowa). stałe dwa do dowolnych linii GPIO. pomocą transmisji kontrolnej i robi to tylko
 Wsparcie sprzętowe dla przechodzenia Do transmisji z komputerem potrzebne w jednym celu  aby przełączyć się w tryb dru-
w tryb uśpienia (Suspend) oraz wybu- jest jeszcze zdefiniowanie wyższej warstwy gi. W tym celu wysyła do interfejsu DFU żąda-
dzenia z tego trybu (Resume). transmisji. Można to zrobić na dwa sposoby: nie DFU_DETACH. Po tym żądaniu urządzenie
 512 B przestrzeni pamięci RAM dedyko- zdefiniowanie własnego protokołu wymiany przełącza się w tryb DFU na jeden z dwóch
wanej na bufory sprzętowe. kodu lub użycie gotowego. Z tych dwóch sposobów. Jeżeli ma ustawiony bit 3 w polu
bmAttributes w deskryptorze funkcjonalnym
DFU (bitWillDetach), to wówczas wykonuje
sam cykl odłączenia od Hosta i połączenia,
tym razem już z konfiguracją w trybie DFU.
Jeżeli natomiast nie, wówczas rozpoczyna zli-
czanie czasu, aż dojdzie do wartości równej
zawartości pola wValue, jednej ze składowych
żądania DFU_DETACH. Jeżeli otrzyma w tym
czasie od Hosta sygnał zerowania, wówczas
zmienia konfigurację na DFU, w przeciwnym
razie pozostaje w normalnym trybie pracy. Ten
drugi sposób przełączenia pokazano na rys. 5
zaczerpniętym z dokumentacji DFU.
W trybie DFU urządzenie zawiera jedną
Rys. 3. Schemat blokowy bootloadera USB konfigurację, tylko z jednym interfejsem 
62 ELEKTRONIKA PRAKTYCZNA 10/2009
Bootloader dla mikrokontrolerów STM32
wTransferSize zawarty w deskryptorze funk-
cjonalnym DFU). W praktyce przesyłamy
maksymalne paczki (wTransferSize), mniej-
szy rozmiar stosujemy w przypadku ostat-
niej paczki, gdy całkowity rozmiar danych
nie jest wielokrotnością wTransferSize. Gdy
przetransferujemy wszystkie dane, wówczas
Rys. 5. Procedura przejścia urządzenia USB w tryb DFU przy wykorzystaniu resetu Host wysyła pakiet DFU_DNLOAD o rozmia-
otrzymanego od Hosta rze 0, co oznacza, że transmisja danych zo-
stała zakończona. Wtedy przechodzimy do
DFU. Możliwe są alternatywne ustawienia Działanie w trybie DFU opiera się rów- kończenia programowania i uruchamiania
dla tego interfejsu np. w przypadku, gdy nież na żądaniach transmisji kontrolnej, nie- nowego kodu.
mamy kilka różnych pamięci do zaprogra- mniej jednak tu sekwencja żądań jest trochę Do obsługi tego automatu napisana
mowania w układzie. Wówczas dla każdej bardziej skomplikowana, co przedstawiono została specjalna biblioteka pozwalająca
robimy oddzielną wersję interfejsu. Interfejs na rys. 6. zarządzać strumieniem danych z nowym
ten oraz wszystkie alternatywne ustawienia, Pobranie od Hosta nowej wersji opro- oprogramowaniem. Pozwala ona również na
jeżeli istnieją, muszą zawierać dwa deskryp- gramowania określa procedura Dnload. przełączanie alternatywnych ustawień in-
tory opisujące go i są to te same deskrypto- Rozpoczyna się ona w stanie dfuIDLE. Host terfejsów w celu programowania więcej niż
ry jak w przypadku pierwszego trybu pracy przesyła do układu nowe oprogramowanie jednej pamięci.
urządzenia  deskryptor funkcjonalny jest w postaci paczek danych za pomocą żądania Aby otrzymywać dane od Hosta nale-
identyczny, deskryptor interfejsu ma drobne DFU_DNLOAD. Rozmiar tych danych mieści ży dodać do biblioteki DFU funkcję odpo-
różnice na polach numeru interfejsu, nume- się między wartością rozmiaru bufora zero- wiedzialną za przetworzenie otrzymanych
ru alternatywnego ustawienia i kodu proto- wego punktu końcowego (bMaxPacketSize0) danych. Przykładową procedurę obsługi
kołu (bInterfaceProtocol). a maksymalnym rozmiarem paczki (parametr umieszczono na list. 1.
Funkcja ta jest wywoływana zawsze
w momencie skompletowania przez war-
stwę DFU kolejnego pakietu odebranego od
Hosta. Pakiety te są zapisywane do bufora,
który został podpięty wcześniej, w momen-
cie inicjalizacji transmisji. W dokumentacji
standardu DFU powiedziane jest jasno, że
nie ma żadnych ograniczeń, czy zapisujemy
otrzymane fragmenty nowego oprogramowa-
nia na bieżąco, czy też magazynujemy je np.
w jakieś pamięci zewnętrznej by zaprogra-
mować procesor dopiero po skompletowaniu
całego pliku nowego oprogramowania. Ta
druga metoda jest lepsza, gdy musimy mieć
pewność, że cała aplikacja jest kompletna
i poprawnie przesłana do układu. W naszym
przypadku tak nie jest, gdyż nawet jeśli coś
pójdzie nie tak, zawsze możemy rozpocząć
procedurę programowania od nowa. Z tego
powodu w powyższym kodzie programuje-
my pamięć strona po stronie. Po przesłaniu
całego nowego oprogramowania odbieramy
pakiet o długości 0, co jest sygnalizowane
przez wywołanie naszej funkcji boot_DNLO-
AD z parametrem length=0, w celu zasy-
gnalizowania tego faktu. Teraz Host inicjuje
ostatnią fazę (Manifest), która to faza jest też
obsługiwana automatycznie. Możemy oczy-
wiście być o kolejnych krokach informowa-
ni, ale dla tego zastosowania protokołu DFU
nie było to konieczne i ograniczyliśmy się
jedynie do odebrania informacji o przejściu
znów w tryb aplikacji. Wtedy następuje wy-
wołanie nowo zapisanego programu.
Współpraca z systemem Windows
Niestety, w systemie Windows brak
jest domyślnego sterownika dla urządzeń
typu DFU, co zmusiło do jego napisania.
Zawiera jedynie możliwość współpracy
Rys. 6. Automat stanów przedstawiający pracę urządzenia USB w trybie DFU z urządzeniem posiadającym w trybie apli-
ELEKTRONIKA PRAKTYCZNA 10/2009 63
KURS
kacji interfejs DFU i w razie konieczności
List. 1.
static uint8_t boot_DNLOAD(uint8_t **buffer, uint16_t length, uint16_t packet_
pracy z innymi interfejsami należy zmody-
number) {
fikować driver. Do samego programowania if(!length) {
return(dfu_bStatus_OK);
procesora w zupełności ta opcja wystarcza.
}
Do obsługi transmisji powstał program uru-
boot_buffer_head_shift += length;
chamiany z wiersza poleceń. Nie są do nie-
if(boot_buffer_head_shift >= boot_page_size) {
// get into critical section - disable interrupts
go przekazywane żadne parametry  jedy-
__asm volatile ( CPSID I );
nym warunkiem żeby zadziałał jest to, aby FlashUnlock();
if (FlashErasePage(boot_prog_addr))
w tym samym katalogu co program znaj-
// flash erase failed
{
dowały się: plik  file_name.txt , a w nim
FlashLock();
zapisana nazwa pliku binarnego, który
// leave critical section - enable interrupts
__asm volatile ( CPSIE I );
program wysyła do układu oraz ów plik
return(dfu_bStatus_errERASE);
}
binarny. Tu nadmienić muszę jedną rzecz:
if (FlashWritePage(boot_prog_addr, boot_buffer, boot_page_size))
protokół DFU definiuje standard pliku do
// flash write failed
{
wymiany danych. Plik taki zawiera specjal-
FlashLock();
ne informacje o programowanym układzie, // leave critical section - enable interrupts
__asm volatile ( CPSIE I );
wgrywanym programie oraz dane pozwala-
return(dfu_bStatus_errWRITE);
}
jące na dodatkową detekcję błędów. Takie
FlashLock();
rozwiązanie wprowadza konieczność gene- // leave critical section - enable interrupts
__asm volatile ( CPSIE I );
rowania jeszcze dodatkowego pliku. Z roz-
boot_prog_addr += boot_page_size;
wiązania tego zrezygnowano, gdyż sam pro- boot_buffer_head_shift -= boot_page_size;
*buffer = &boot_buffer[boot_buffer_head_shift];
tokół USB ma dobrze zorganizowane rozpo-
while(boot_buffer_head_shift) {
boot_buffer_head_shift--;
znawanie błędów oraz mechanizm powtó-
boot_buffer[boot_buffer_head_shift] = boot_buffer[boot_page_size + boot_
rzeń. Poza tym stworzony bootloader musi buffer_head_shift];
}
mieć mały rozmiar, przez co wprowadzanie
}
else {
dodatkowego sprawdzania sum kontrol-
*buffer = &boot_buffer[boot_buffer_head_shift];
nych CRC i innych elementów spowodo-
}
return(dfu_bStatus_OK);
wałoby zbyt duże powiększenie rozmiaru
}
kodu. Program jak i sterownik na kompute-
rze są przezroczyste dla strumienia danych,
dlatego nic nie stoi na przeszkodzie, żeby
List. 2.
void FAT_ConnectEvent(FAT_Desc *FAT32D)
zamiast funkcji boot_DNLOAD do warstwy
{
DFU podpiąć funkcję, która będzie oceniać FILE file_desc;
uint32_t result;
otrzymany strumień danych pod kątem
uint32_t address_shift = 0;
if(!sfopen(&file_desc, (const char*)FAT32D->FAT_name_string_descriptor,  r ))
zgodności z DFU, a dopiero pózniej wy-
return;
woływać funkcje programujące procesor.
if(!sfopen(&file_desc,  stm32f10x/file_name.txt ,  r )) return;
fread(boot_read_buffer, 1, boot_page_size, &file_desc);
Od strony komputera, nie jest ważne jaki
fclose(&file_desc);
plik wysyłamy do układu  to co podamy if(!sfopen(&file_desc, (const char *)boot_read_buffer,  r )) return;
FlashUnlock();
w pliku  file_name.txt jest traktowane jako
do
{
nazwa pliku, który będzie otwarty w trybie
if (FlashErasePage(DEF_APP_ADDRESS + address_shift)) break;
binarnym, a następnie w całości odczytany
result = fread(boot_read_buffer, 1, boot_page_size, &file_desc);
if (FlashWritePage(DEF_APP_ADDRESS + address_shift, boot_read_buffer,
i wysłany.
result)) break;
address_shift += boot_page_size;
Takie rozwiązanie można skrytykować
} while(result == boot_page_size);
i powiedzieć, że można zaprogramować pro-
FlashLock();
fclose(&file_desc);
cesor czymkolwiek  dowolnymi śmieciami
}
 tak, zgadzam się z tym, ale ten bootloader
miał być z założenia bardzo prosty w uży-
ciu i służyć do szybkiego reprogramowania NSS, działający jako chip select. Sygnały Sam dostęp do pamięci procesora i wy-
mikrokontrolera, dlatego od użytkownika SDSPI_DETECT i SDSPI_WP nie są tu wyko- wołania bootloadera realizowany jest w spo-
wymagane jest to minimum uwagi, aby wie- rzystywane. Służą one do detekcji umieszcze- sób identyczny jak w przypadku USB. Do-
dział, co wysyła do układu. Poza tym, zapro- nia karty w złączu i sprawdzenia, czy do karty stęp do karty realizuje biblioteka o budowie
gramowanie mikrokontrolera czymkolwiek można zapisywać dane. Schemat blokowy modułowej, dzięki czemu w razie potrzeby
spowoduje jedynie, że układ nie zadziała aplikacji bootloadera przedstawiono na rys. 8. łatwo podmienić typ nośnika na inny niż SD.
a aktualizację można będzie przeprowadzić
ponownie, gdyż bootloader nigdy sam się nie
skasuje.
Bootloader SD
Jak wspomniano wcześniej, procesor ko-
munikuje się z kartą SD przez interfejs SPI.
Na rys. 7 umieszczono schemat przykłado-
wego podłączenie karty do procesora.
Do komunikacji używane są cztery linie
SPI: SCK, MISO i MOSI, za pomocą których
wymieniane są dane oraz czwarty sygnał Rys. 7. Podłączenie slotu karty SD do procesora
64 ELEKTRONIKA PRAKTYCZNA 10/2009
Bootloader dla mikrokontrolerów STM32
List. 3. ka w jego kodzie. Na list. 3 umieszczono przy-
#ifndef BOOTLOADER_H_
kładowy plik nagłówkowy pozwalający wywo-
#define BOOTLOADER_H_
łać bootloader na wspomniane wcześniej dwa
// adres tablicy wektorow przerwan bootloadera
sposoby: za pomocą makra BOOTLOADER_
#define BOOTLOADER_VECTOR_ADDR 0x8000000
CALL_BY_JUMP lub BOOTLOADER_CALL_BY_
// definicje przeklejone z plikow bibliotecznych ST
RESET. W pliku, którym go dołączamy musi-
/* --------- PWR registers bit address in the alias region ---------- */
my jedynie dołączyć odpowiednią bibliotekę
#define PWR_OFFSET (PWR_BASE - PERIPH_BASE)
ST definiującą wskazniki do struktur rejestrów
/* --- CR Register ---*/
peryferiów (RCC, BKP, itp). Sam nagłówek nie
/* Alias word address of DBP bit */
#define CR_OFFSET (PWR_OFFSET + 0x00)
załącza ich z tego powodu, że w różnych wer-
#define DBP_BitNumber 0x08
#define CR_DBP_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (DBP_BitNumber * 4))
sjach bibliotek ST znajduje się to w różnych
plikach.
// struktura opisujaca poczatek standardowego wektora przerwan
Plik ten definiuje adres bazowy wektora
typedef struct {
uint32_t SP; przerwań samego bootloadera, który jest zgod-
void (*RESET_ISR)(void);
ny z adresem początku pamięci FLASH. Dalej
void (*NMIExc)(void);
void (*HardFaultExc)(void);
mamy zdefiniowany początek standardowej
void (*MemManageExc)(void);
dla tych procesorów struktury wektora prze-
void (*BusFaultExc)(void);
void (*UsageFaultExc)(void);
rwań. Wyjaśnienia wymaga chyba tylko to, co
void (*RESRV1)(void);
void (*RESRV2)(void);
jest wewnątrz makra BOOTLOADER_CALL_
void (*RESRV3)(void);
BY_RESET. Pierwsze dwie linie to włączenie
void (*RESRV4)(void);
void (*SVC)(void);
zegara dla kontrolera Backup oraz wyłączenie
}BOOTLOADER_CM3_ISR_TABLE;
jego resetu, trzecia jest to odblokowanie zapisu
// definicja wskaznika do tablice przerwan bootloadera
do rejestrów Backup (pochodzi to z biblioteki
#define BOOTLOADER_TAB ((BOOTLOADER_CM3_ISR_TABLE*)BOOTLOADER_VECTOR_ADDR)
stm32f10x_pwr). W czwartej linii wpisujemy
// makro sluzace do wywolania bootloadera przez skoczenie do niego
do pierwszego rejestru danych Backup wartość
#define BOOTLOADER_CALL_BY_JUMP() (BOOTLOADER_TAB->SVC)()
0x159D, której będzie szukać w tymże rejestrze
// makro sluzace do wywolania bootloadera poprzez zapis sygnatury
// do pierwszego rejestru danych Backup i zresetowanie procesora bootloader po resecie. Piąta linia jest to wyge-
#define BOOTLOADER_CALL_BY_RESET() {\
nerowanie programowego sygnału resetu dla
RCC->APB1ENR |= RCC_APB1Periph_BKP | RCC_APB1Periph_PWR;\
RCC->APB1RSTR &= ~((uint32_t)(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR));\
mikrokontrolera. Polega to na ustawieniu bitu
*(vu32 *) CR_DBP_BB = (u32)1;\
VECTRESET (najmłodszy bit) w rejestrze  Ap-
BKP->DR1 = 0x159D;\
SCB->AIRCR = (SCB->AIRCR & 0xFFFF) | (0x5FA << 16) | (1 << 0);\
plication Interrupt and Reset Control Register .
}
Jest to jeden z rejestrów kontrolera NVIC, zdefi-
#endif /*BOOTLOADER_H_*/
niowany w specyfikacji samego rdzenia Cortex
-M3. Po wpisaniu na bit zerowy jedynki z rów-
jako nazwę pliku binarnego znaj- noczesnym wpisaniem na bity 16-31 sygnatury
dującego się w tym samym katalo- 0x5FA następuje zresetowanie procesora.
gu. Następnie otwieramy ten plik
binarny i odczytujemy z niego Podsumowanie
paczki o wielkości rozmiaru stro- Bootloadery te dedykowane są dla mi-
ny pamięci FLASH mikrokontro- krokontrolera STM32, niemniej jednak po
lera, które następnie programu- pewnych przeróbkach można je przenieść
jemy. Po odczytaniu całego pliku na inne platformy. Wywoływane są w ści-
zamykamy go i kończymy pracę śle określonych momentach, dzięki czemu
całej funkcji. Po wyjściu z niej na- nie zakłócają normalnego startu programu.
stępuje uruchomienie programu Dzięki dość uniwersalnej budowie istnie-
Rys. 8. Schemat blokowy bootloadera SD użytkownika. je możliwość poszerzenia możliwości tych
programów. Można się też pokusić o obsługę
Manager pamięci masowych jest tak napraw- Uruchomienie i aplikacja magistrali zewnętrznej procesora, np. w celu
dę zbiorem kilku prostych funkcji, które po- użytkownika programowania zewnętrznych pamięci
zwalają w łatwy sposób kontrolować dostęp Sam bootloader wgrywamy do procesora FLASH i RAM.
do nośników danych. Co do biblioteki FAT, tak jak każdy inny program, za pomocą inter- Piotr Wojtowicz
daje ona jedynie możliwość odczytu plików, fejsu JTAG lub przez USART. Po tej czynności piotreklc60@gmail.com
jednak ze wsparciem dla długich nazw. Na- jest on od razu gotowy do pracy. Aby za jego
pisana została ona od podstaw. pomocą poprawnie uruchomić aplikację użyt- Literatura:
Uruchomienie bootloadera jest tu iden- kownika należy w niej dokonać kilka zabiegów. Dokumentacja STM32:
tyczne jak w przypadku USB. Aplikacja Pierwszy z nich to relokowanie naszej aplika- www.st.com/mcu/inchtml-pages-stm32.html
sterująca również działa bardzo podobnie. cji w pamięci FLASH z adresu 0x8000000 na Strona domowa SD:
Pokazana na list. 2 funkcja FAT_Connec- 0x8002000, czyli o 8 kB do przodu (np. przez www.sdcard.org
tEvent jest związana z biblioteką FAT i wy- zmianę w skrypcie linkera adresu początku pa- Strona domowa USB:
woływana w momencie wykrycia partycji mięci). Drugi to usunięcie ustawienia wektora www.usb.org
FAT16/32. W niej dokonujemy otwarcia ka- przerwań aplikacji użytkownika, gdyż bootlo- Specyfikacja DFU:
talogu głównego, następnie sprawdzamy czy ader wykonuje tą czynność sam. www.usb.org/developers/devclass_docs/
na karcie istnieje katalog stm32f10x, a w nim Dodatkową opcją, wspomnianą wcześniej DFU_1.1.pdf
plik  file_name.txt . Jeżeli tak, wówczas od- jest możliwość wywołania bootloadera w mo- Kody zródłowe:
czytujemy jego zawartość, którą traktujemy mencie zadeklarowanym już przez użytkowni- www.wsn.agh.edu.pl
ELEKTRONIKA PRAKTYCZNA 10/2009 65


Wyszukiwarka

Podobne podstrony:
Aktualizacja oprogramowania
HP Aktualizacja oprogramowania
AVR GCC kompilator C dla mikrokontrolerów AVR, część 12
AVR GCC kompilator C dla mikrokontrolerów AVR, część 11
dmc tz4 , tz5 instrukcja aktualizacji oprogramowania
Płytka testowa dla mikrokontrolerów AT89S oraz AVR
Jak aktualizować oprogramowanie w odbiorniku OPTICUM X402p i OPTICUM X403p
Mikrokontrolery STM32 Bezpieczeństwo i stabilność
Jak aktualizować oprogramowanie w odbiorniku OPTICUM X7
Mikrokontrolery STM32 Wykorzystanie ADC i DMA
AVR GCC kompilator C dla mikrokontrolerów AVR, część 4

więcej podobnych podstron