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

(640 KB) Pobierz
652390246 UNPDF
KURS
mikrokontrolerów STM32
Aktualizacja oprogramowanie
z zastosowaniem karty SD lub
przez USB
Nie jest dla nikogo tajemnicą, że mikrokontroler można
zaprogramować z  użyciem programatora. Współczesne
mikrokontrolery mogą być programowane zarówno za pomocą
programatora, jak i  w  systemie. Niżej zaprezentujemy metodę
będącą wariantem programowania w  systemie, a  mianowicie
aktualizację oprogramowania przez interfejs USB lub
z  zastosowaniem karty SD podłączonej poprzez SPI. Atrakcyjna jest
zwłaszcza ta druga metoda, ponieważ wymaga tylko maleńkiej karty
SD, którą można zabrać ze sobą chociażby do kieszeni.
kowanego do aplikacji przemysłowych, pra-
cującego z interfejsem USART, z którego wy-
korzystano jedynie pliki startowe. Dostęp do
karty SD i system plików FAT w wersji tylko
do odczytu zostały napisane na od podstaw.
Są one na tyle uniwersalne, że z łatwością
można je stosować w różnych urządzeniach.
Oprogramowanie obsługujące USB, powsta-
ło trochę wcześniej. Jest ono na tyle uni-
wersalne i łatwe w koniguracji, że w prosty
sposób można je przenosić na różne proce-
sory. Do obsługi standardowych peryferiów
(z wyjątkiem USB) zastosowano zmodyiko-
wane w celu zmniejszenia kodu wynikowego
biblioteki producenta.
Jak wspomniano wcześniej, sam bootlo-
ader jest umieszczony w pamięci FLASH,
a dokładniej na jej początku. Rozwiązanie
to jest konieczne, gdyż po restarcie procesor
musi mieć możliwość uruchomienia go, nie-
zależnie od tego, czy jest w nim poprawny
program, czy nie. Jako że po restarcie pro-
cesor skacze do początku pamięci FLASH
(przy odpowiednim ustawieniu linii BOOT0
i BOOT1) dlatego najłatwiej było umieścić
bootloader na początku tego obszaru. Daje
to nam również dużą uniwersalność, gdyż
nie trzeba się już martwić wgraniem go
w odpowiednie miejsce – ładujemy go raz,
tak jak zwykły program, za pomocą progra-
matora JTAG lub przez USART1. Bootloader
po starcie procesora uruchamia się z pamię-
ci FLASH, ale zaraz na początku swojego
działania kopiuje samego siebie do pamięci
SRAM, a następnie skacze do swojej „kopii”
i od tego momentu działa już z poziomu pa-
mięci RAM. Rozwiązanie to jest konieczne
ze względu na niemożność równoczesnego
czytania i programowania pamięci FLASH.
Następnie wykonywana jest inicjalizacja
niezbędnych peryferiów i sprawdzenie, czy
bootloader ma być wywołany. Dzięki temu
rozwiązaniu nie dokonujemy za każdym
razem aktualizacji oprogramowania, lecz ro-
Większość obecnie produkowanych mi-
krokontrolerów ma pamięć FLASH, która
może być modyikowana wiele razy. Dodatko-
wo, producenci wychodząc naprzeciw użyt-
kownikom udostępniają programowe interfej-
sy pozwalające na dostęp do tychże pamięci
z poziomu aplikacji, przez co można je mo-
dyikować bez konieczności użycia programa-
tora. Nawet jeśli programator nie jest drogim
urządzeniem, to sama konieczność rozebrania
obudowy może być dość uciążliwa. Najczę-
ściej stosowanym współcześnie rozwiąza-
niem jest programowanie w systemie, gdyż
podłączając się np. przez często używany
przez nasze urządzenie interfejs dokonujemy
szybko i prosto operacji serwisowych.
Programując w ten sposób mikrokontro-
lery STM32 zauważyłem możliwość zrobie-
nia uniwersalnej aplikacji, która umieszczo-
na obok docelowego programu będzie służyć
łatwej wymianie oprogramowania.
Pytaniem jest, jaki interfejs najlepiej
nadaje się do tego celu? Najczęściej nowe
mikrokontrolery wyposażone są w interfejs
UART, SPI, I 2 C. UART nadawałby się świet-
nie do komunikacji z komputerem, jednak
nowe komputery nie mają już interfejsu
RS232, z którym UART łączy się przez układ
pośredniczący.
Z drugiej strony wiele urządzeń ma moż-
liwość rejestrowania wyników swojej pracy
na karcie SD. Najprostszym sposobem jej
podłączenia jest port SPI, który jest wspie-
rany przez część kart. Kolejnym kandyda-
tem, jest interfejs USB służący do połączenia
urządzenia z komputerem PC, który wypiera
w tej roli UART. Dodatkowo, nowe mikro-
kontrolery mają często standardowo wbudo-
wany kontroler USB w swoją strukturę.
Z wymienionych wyżej powodów, zde-
cydowałem się na użycie tych dwóch inter-
fejsów, czyli USB i SD (SPI) jako dwie meto-
dy uaktualnienia oprogramowania w proce-
sorze rodziny STM32.
Bootloader
Bootloader jest małym programem
umieszczonym obok programu użytkowni-
ka. Jego zadaniem jest pobranie przez de-
dykowany interfejs nowszej wersji aplikacji
użytkownika. Umieszczono go na początku
wbudowanej w  procesor pamięci FLASH,
tak aby był domyślnie uruchamiany po włą-
czeniu mikrokontrolera. Dzięki temu jest
zawsze uruchamiany przed aplikacją użyt-
kownika, przez co może wystartować nawet
wtedy, gdy aplikacja użytkownika jest w ja-
kiś sposób uszkodzona lub wadliwa. Po uru-
chomieniu sprawdza się, czy bootloader ma
przejść do aktualizacji. Jeżeli nie, to wyłącza
on wszystkie uaktywnione interfejsy proce-
sora i wywołuje aplikację użytkownika.
W artykule opisywane są dwie wersje
zbudowane na szkielecie bootloadera dedy-
60
ELEKTRONIKA PRAKTYCZNA 10/2009
Bootloader dla
Bootloader dla mikrokontrolerów STM32
cisk jest wciśnięty. Używany jest do tego,
aby można było zaktualizować program po
starcie urządzenia niezależnie od tego, czy
w pamięci znajduje się już jakiś program,
czy nie. Jest to pomocne, gdy
aplikacja użytkownika zawiera
błędy i program zawiesza się tuż
po starcie.
Trzeci sposób pozwala na umieszczenie
w programie użytkownika dosłownie kilku
linii kodu, które powodują wywołanie bootlo-
adera. Jest to możliwe na dwa sposoby. Pierw-
szy, to zapisanie do jednego z rejestrów Bac-
kup procesora konkretnej wartości i restart
układu. Po nim bootloader, podczas spraw-
dzania warunków wejścia w tryb aktualizacji,
sprawdza zawartość pierwszego z rejestrów
Backup . Jeżeli jego zawartość jest odpowied-
nia, wówczas kasuje ten rejestr i przechodzi
do wymiany programu. W tym rozwiązaniu
używany jest jeden z rejestrów Backup , dla-
tego jeżeli użytkownikowi bardzo zależy na
zastosowaniu go do innego przeznaczenia, to
wówczas może użyć drugiej metody – polega
ona na skoku do funkcji, której adres znajduje
się w wektorze przerwań samego bootloadera
na pozycji 12 (SVC_Handler). Pod tym wskaź-
nikiem kryje się adres kopii wektora RESET ,
którego wywołanie powoduje natychmiasto-
we przejście do aktualizacji, bez sprawdzania
jakichkolwiek warunków.
Bootloader w wersji SD działa na wszyst-
kich wersjach STM32, ponieważ potrzebuje
do prawidłowej pracy jedynie jednego inter-
fejsu SPI i jednej linii GPIO. Co do USB, to
w grę wchodzą jedynie modele z zaimple-
mentowanym kontrolerem, gdyż tylko te wer-
sje obsługiwane są przez oprogramowanie.
Rys. 1. Procedura programowania
pamięci FLASH mikrokontrolera STM32
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
nieulotnej chroni ją przed zapisem. Dzięki
temu nie ma możliwości przypadkowego jej
uszkodzenia. Aby dokonywać jakichkolwiek
zmian należy najpierw odblokować moż-
liwość zapisu. Dokonuje się tego poprzez
wpisanie do rejestru FLASH_KEYR kontro-
lera pamięci kolejno dwóch wartości: KEY1
= 0x45670123 , a następnie KEY2 = 0xCDE-
F89AB . Od tego momentu można dokonywać
na pamięci operacji kasowania i zapisu, aż
do momentu wystąpienia błędu, który bloku-
je pamięć do kolejnego restartu.
Zapis pamięci. Operacji zapisu do pa-
mięci FASH dokonuje się za pomocą kontro-
lera FPEC, zgodnie z algorytmem pokazanym
na rys. 1 . Do pamięci jednocześnie zapisy-
wane są 2 bajty. Najpierw należy w rejestrze
FLASH_CR ustawić bit PG informujący kon-
troler o tym, że pamięć będzie programo-
wana. Po tej czynności można dokonywać
zapisu – wpisujemy 2 bajty nowej zawarto-
ści bezpośrednio pod adres, pod którym ma
być ona umieszczona. Następnie czekamy
bimy to tylko w ściśle określonych przypad-
kach. Są to:
– Brak jakiegokolwiek oprogramowania
użytkownika w pamięci FLASH.
– Spełnienie warunku wymuszenia przej-
ścia w tryb bootloadera.
– Bootloader został wywołany z poziomu
aplikacji użytkownika.
Sprawdzenie pierwszego warunku po-
lega na odczytania pierwszych komórek
wektora przerwań programu użytkownika
(wskaźnik stosu i wektor RESET ) i sprawdze-
nia czy nie są przypadkiem skasowane. Ten
prosty test oczywiście nie jest w stanie wy-
kryć, czy aplikacja nie zawiera błędów, nie-
mniej jednak wystarcza do stwierdzenia, czy
w ogóle znajduje się ona w pamięci.
Drugi sposób realizowany jest przez
sprawdzenie stanu jednego z pinów GPIO
procesora, tzn. czy podłączony tam przy-
Rys. 2. Procedura kasowania pamięci
FLASH mikrokontrolera STM32 metodą
„strona po stronie”
ELEKTRONIKA PRAKTYCZNA 10/2009
61
652390246.116.png 652390246.127.png 652390246.138.png 652390246.148.png 652390246.001.png 652390246.012.png 652390246.023.png 652390246.034.png 652390246.045.png 652390246.056.png 652390246.067.png 652390246.073.png 652390246.074.png 652390246.075.png 652390246.076.png 652390246.077.png 652390246.078.png 652390246.079.png 652390246.080.png 652390246.081.png 652390246.082.png 652390246.083.png 652390246.084.png 652390246.085.png 652390246.086.png 652390246.087.png 652390246.088.png 652390246.089.png 652390246.090.png 652390246.091.png 652390246.092.png 652390246.093.png 652390246.094.png 652390246.095.png 652390246.096.png 652390246.097.png 652390246.098.png 652390246.099.png 652390246.100.png 652390246.101.png 652390246.102.png 652390246.103.png 652390246.104.png 652390246.105.png 652390246.106.png 652390246.107.png
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
Erase ). Następnie do rejestru FLASH_AR
wpisujemy adres strony, którą kasujemy
i ustawiamy w rejestrze FLASH_CR bit STRT .
W tym momencie rozpoczyna się procedura
kasowania. W kolejnym kroku czekamy na
jej zakończenie, po czym sprawdzamy, czy
strona została skasowana poprawnie poprzez
odczytanie jej zawartości.
Rys. 4. Podłączenie portu USB
– 3 wektory przerwań skojarzone z kontrole-
rem przerwań NVIC: transmisja o niskim
priorytecie, transmisja o wysokim priory-
tecie, wyjście procesora z trybu Suspend.
Do obsługi kontrolera zastosowano uni-
wersalną warstwę USB. Pozwala ona w ła-
twy sposób pisać programy korzystające
z tego interfejsu prawie niezależnie od zasto-
sowanego układu peryferyjnego (procesora).
Na rys. 4 pokazano przykładowe podłącze-
nie złącza USB-B do mikrokontrolera. Poza
liniami D+ i D–, do procesora podłączone
są również dwie dodatkowe linie. Pierwsza
z nich to USB_STM_PWR_DETECT służąca
do wykrywania napięcia zasilającego do-
cierającego bezpośrednio z  komputera PC
i przesyłanego po kablu USB. Fakt wykrycia
podłączenia do Hosta zgłasza się stanem wy-
sokim, zaś sama linia skonigurowana jest
w procesorze jako przerwanie zewnętrzne.
Druga to USB_STM_PULL_UP wykorzysty-
wana do programowego włączania lub wyłą-
czania rezystora 1,5 kV na linii D+. Sygnały
USBDM i USBDP podłączamy do dedykowa-
nych linii mikrokontrolera, natomiast pozo-
stałe dwa do dowolnych linii GPIO.
Do transmisji z komputerem potrzebne
jest jeszcze zdeiniowanie wyższej warstwy
transmisji. Można to zrobić na dwa sposoby:
zdeiniowanie własnego protokołu wymiany
kodu lub użycie gotowego. Z tych dwóch
jedynie drugie wydaje się byś sensowne,
zwłaszcza że taki protokół został już kiedyś
zdeiniowany i to oicjalnie jako jedna ze
standardowych klas urządzeń USB. Mowa tu
o klasie DFU (ang. Device Firmware Upgra-
de), której dokumentację można pobrać ze
strony www.usb.org .
USB DFU. Klasa DFU pozwala na aktu-
alizowanie oprogramowanie urządzenia bez-
pośrednio za pomocą interfejsu USB. Dei-
niuje dwa tryby pracy: tryb pracy normalnej
– użytkownika (Run Time Mode) i tryb DFU
(DFU Mode).
W trybie pierwszym urządzenie USB dzia-
ła normalnie, zgodnie z założeniami, z jakimi
zostało zaprojektowane, np. jest to drukarka,
skaner, konwerter USB/RS232, pamięć ma-
sowa itp. Poza tymi standardowymi możli-
wościami ma ono jeden dodatkowy interfejs
USB – interfejs DFU, który nie ma żadnych
punktów końcowych. Tworząc taki dodatkowy
interfejs dodajemy do deskryptora konigu-
racji dwa dodatkowe deskryptory: interfejsu
i funkcjonalny DFU ( DFU Functional Descrip-
tor ). Host komunikuje się z tym interfejsem za
pomocą transmisji kontrolnej i robi to tylko
w jednym celu – aby przełączyć się w tryb dru-
gi. W tym celu wysyła do interfejsu DFU żąda-
nie DFU_DETACH . Po tym żądaniu urządzenie
przełącza się w tryb DFU na jeden z 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 koniguracją 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 konigurację 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ą
konigurację, tylko z jednym interfejsem –
Bootloader USB
Budowę aplikacji bootloadera pracujące-
go z portem USB przedstawiono na rys. 3 .
Rozwiązanie to bazuje na wbudowanym
w część mikrokontrolerów rodziny STM32
sprzętowym kontrolerze USB Full-Speed De-
vice. Jego główne cechy to:
– Pełna zgodność ze standardem 2.0 full-
speed.
– Do 8 konigurowalnych punktów końco-
wych.
– Pełne sprzętowe kodowanie/dekodowa-
nie ramek USB (CRC, NRZI, bit-stufing
itp.).
– Wsparcie w każdym punkcie końcowym
dla wszystkich typów transmisji (kontro-
lna, przerwaniowa, izochroniczna i ma-
sowa).
– Wsparcie sprzętowe dla przechodzenia
w tryb uśpienia (Suspend) oraz wybu-
dzenia z tego trybu (Resume).
– 512 B przestrzeni pamięci RAM dedyko-
wanej na bufory sprzętowe.
Rys. 3. Schemat blokowy bootloadera USB
62
ELEKTRONIKA PRAKTYCZNA 10/2009
652390246.108.png 652390246.109.png 652390246.110.png 652390246.111.png 652390246.112.png 652390246.113.png 652390246.114.png 652390246.115.png 652390246.117.png 652390246.118.png 652390246.119.png 652390246.120.png 652390246.121.png 652390246.122.png 652390246.123.png 652390246.124.png 652390246.125.png 652390246.126.png 652390246.128.png 652390246.129.png 652390246.130.png 652390246.131.png 652390246.132.png 652390246.133.png 652390246.134.png 652390246.135.png 652390246.136.png 652390246.137.png 652390246.139.png 652390246.140.png 652390246.141.png 652390246.142.png 652390246.143.png 652390246.144.png 652390246.145.png
 
Bootloader dla mikrokontrolerów STM32
Rys. 5. Procedura przejścia urządzenia USB w tryb DFU przy wykorzystaniu resetu
otrzymanego od Hosta
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
Host wysyła pakiet DFU_DNLOAD o rozmia-
rze 0, co oznacza, że transmisja danych zo-
stała zakończona. Wtedy przechodzimy do
kończenia programowania i  uruchamiania
nowego kodu.
Do obsługi tego automatu napisana
została specjalna biblioteka pozwalająca
zarządzać strumieniem danych z  nowym
oprogramowaniem. Pozwala ona również na
przełączanie alternatywnych ustawień in-
terfejsów w celu programowania więcej niż
jednej pamięci.
Aby otrzymywać dane od Hosta nale-
ży dodać do biblioteki DFU funkcję odpo-
wiedzialną za przetworzenie otrzymanych
danych. Przykładową procedurę obsługi
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.
DFU. Możliwe są alternatywne ustawienia
dla tego interfejsu np. w przypadku, gdy
mamy kilka różnych pamięci do zaprogra-
mowania w układzie. Wówczas dla każdej
robimy oddzielną wersję interfejsu. Interfejs
ten oraz wszystkie alternatywne ustawienia,
jeżeli istnieją, muszą zawierać dwa deskryp-
tory opisujące go i są to te same deskrypto-
ry jak w przypadku pierwszego trybu pracy
urządzenia – deskryptor funkcjonalny jest
identyczny, deskryptor interfejsu ma drobne
różnice na polach numeru interfejsu, nume-
ru alternatywnego ustawienia i kodu proto-
kołu ( bInterfaceProtocol ).
Działanie w trybie DFU opiera się rów-
nież na żądaniach transmisji kontrolnej, nie-
mniej jednak tu sekwencja żądań jest trochę
bardziej skomplikowana, co przedstawiono
na rys. 6 .
Pobranie od Hosta nowej wersji opro-
gramowania określa procedura Dnload .
Rozpoczyna się ona w stanie dfuIDLE . Host
przesyła do układu nowe oprogramowanie
w postaci paczek danych za pomocą żądania
DFU_DNLOAD . Rozmiar tych danych mieści
się między wartością rozmiaru bufora zero-
wego punktu końcowego ( bMaxPacketSize0 )
a maksymalnym rozmiarem paczki (parametr
Rys. 6. Automat stanów przedstawiający pracę urządzenia USB w trybie DFU
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
z urządzeniem posiadającym w trybie apli-
ELEKTRONIKA PRAKTYCZNA 10/2009
63
652390246.146.png 652390246.147.png 652390246.149.png 652390246.150.png 652390246.151.png 652390246.152.png 652390246.153.png 652390246.154.png 652390246.155.png 652390246.156.png 652390246.157.png 652390246.158.png 652390246.002.png 652390246.003.png 652390246.004.png 652390246.005.png 652390246.006.png 652390246.007.png 652390246.008.png 652390246.009.png 652390246.010.png 652390246.011.png 652390246.013.png 652390246.014.png 652390246.015.png 652390246.016.png 652390246.017.png 652390246.018.png 652390246.019.png 652390246.020.png 652390246.021.png 652390246.022.png 652390246.024.png 652390246.025.png 652390246.026.png 652390246.027.png 652390246.028.png 652390246.029.png 652390246.030.png 652390246.031.png 652390246.032.png 652390246.033.png 652390246.035.png 652390246.036.png 652390246.037.png 652390246.038.png 652390246.039.png 652390246.040.png 652390246.041.png 652390246.042.png 652390246.043.png 652390246.044.png 652390246.046.png 652390246.047.png 652390246.048.png 652390246.049.png 652390246.050.png 652390246.051.png 652390246.052.png
KURS
kacji interfejs DFU i w razie konieczności
pracy z innymi interfejsami należy zmody-
i kować driver. Do samego programowania
procesora w zupełności ta opcja wystarcza.
Do obsługi transmisji powstał program uru-
chamiany z wiersza poleceń. Nie są do nie-
go przekazywane żadne parametry – jedy-
nym warunkiem żeby zadziałał jest to, aby
w tym samym katalogu co program znaj-
dowały się: plik „i le_name.txt”, a w nim
zapisana nazwa pliku binarnego, który
program wysyła do układu oraz ów plik
binarny. Tu nadmienić muszę jedną rzecz:
protokół DFU dei niuje standard pliku do
wymiany danych. Plik taki zawiera specjal-
ne informacje o programowanym układzie,
wgrywanym programie oraz dane pozwala-
jące na dodatkową detekcję błędów. Takie
rozwiązanie wprowadza konieczność gene-
rowania jeszcze dodatkowego pliku. Z roz-
wiązania tego zrezygnowano, gdyż sam pro-
tokół USB ma dobrze zorganizowane rozpo-
znawanie błędów oraz mechanizm powtó-
rzeń. Poza tym stworzony bootloader musi
mieć mały rozmiar, przez co wprowadzanie
dodatkowego sprawdzania sum kontrol-
nych CRC i innych elementów spowodo-
wałoby zbyt duże powiększenie rozmiaru
kodu. Program jak i sterownik na kompute-
rze są przeźroczyste dla strumienia danych,
dlatego nic nie stoi na przeszkodzie, żeby
zamiast funkcji boot_DNLOAD do warstwy
DFU podpiąć funkcję, która będzie oceniać
otrzymany strumień danych pod kątem
zgodności z DFU, a dopiero później wy-
woływać funkcje programujące procesor.
Od strony komputera, nie jest ważne jaki
plik wysyłamy do układu – to co podamy
w pliku „i le_name.txt” jest traktowane jako
nazwa pliku, który będzie otwarty w trybie
binarnym, a następnie w całości odczytany
i wysłany.
Takie rozwiązanie można skrytykować
i powiedzieć, że można zaprogramować pro-
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
mikrokontrolera, dlatego od użytkownika
wymagane jest to minimum uwagi, aby wie-
dział, co wysyła do układu. Poza tym, zapro-
gramowanie mikrokontrolera czymkolwiek
spowoduje jedynie, że układ nie zadziała
a aktualizację można będzie przeprowadzić
ponownie, gdyż bootloader nigdy sam się nie
skasuje.
List. 1.
static uint8_t boot_DNLOAD(uint8_t **buffer, uint16_t length, uint16_t packet_
number) {
if(!length) {
return(dfu_bStatus_OK);
}
boot_buffer_head_shift += length;
if(boot_buffer_head_shift >= boot_page_size) {
// get into critical section - disable interrupts
__asm volatile („ CPSID I”);
FlashUnlock();
if (FlashErasePage(boot_prog_addr))
// fl ash erase failed
{
FlashLock();
// leave critical section - enable interrupts
__asm volatile („ CPSIE I”);
return(dfu_bStatus_errERASE);
}
if (FlashWritePage(boot_prog_addr, boot_buffer, boot_page_size))
// fl ash write failed
{
FlashLock();
// leave critical section - enable interrupts
__asm volatile („ CPSIE I”);
return(dfu_bStatus_errWRITE);
}
FlashLock();
// leave critical section - enable interrupts
__asm volatile („ CPSIE I”);
boot_prog_addr += boot_page_size;
boot_buffer_head_shift -= boot_page_size;
*buffer = &boot_buffer[boot_buffer_head_shift];
while(boot_buffer_head_shift) {
boot_buffer_head_shift--;
boot_buffer[boot_buffer_head_shift] = boot_buffer[boot_page_size + boot_
buffer_head_shift];
}
}
else {
*buffer = &boot_buffer[boot_buffer_head_shift];
}
return(dfu_bStatus_OK);
}
List. 2.
void FAT_ConnectEvent(FAT_Desc *FAT32D)
{
FILE fi le_desc;
uint32_t result;
uint32_t address_shift = 0;
if(!sfopen(&fi le_desc, (const char*)FAT32D->FAT_name_string_descriptor, „r”))
return;
if(!sfopen(&fi le_desc, „stm32f10x/fi le_name.txt”, „r”)) return;
fread(boot_read_buffer, 1, boot_page_size, &fi le_desc);
fclose(&fi le_desc);
if(!sfopen(&fi le_desc, (const char *)boot_read_buffer, „r”)) return;
FlashUnlock();
do
{
if (FlashErasePage(DEF_APP_ADDRESS + address_shift)) break;
result = fread(boot_read_buffer, 1, boot_page_size, &fi le_desc);
if (FlashWritePage(DEF_APP_ADDRESS + address_shift, boot_read_buffer,
result)) break;
address_shift += boot_page_size;
} while(result == boot_page_size);
FlashLock();
fclose(&fi le_desc);
}
NSS, działający jako chip select. Sygnały
SDSPI_DETECT i SDSPI_WP nie są tu wyko-
rzystywane. Służą one do detekcji umieszcze-
nia karty w złączu i sprawdzenia, czy do karty
można zapisywać dane. Schemat blokowy
aplikacji bootloadera przedstawiono na rys. 8 .
Sam dostęp do pamięci procesora i wy-
wołania bootloadera realizowany jest w spo-
sób identyczny jak w przypadku USB. Do-
stęp do karty realizuje biblioteka o budowie
modułowej, dzięki czemu w razie potrzeby
łatwo podmienić typ nośnika na inny niż SD.
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
652390246.053.png 652390246.054.png 652390246.055.png 652390246.057.png 652390246.058.png 652390246.059.png 652390246.060.png 652390246.061.png 652390246.062.png 652390246.063.png 652390246.064.png 652390246.065.png 652390246.066.png 652390246.068.png 652390246.069.png 652390246.070.png 652390246.071.png 652390246.072.png
 
Zgłoś jeśli naruszono regulamin