Aveți de gând să creați propriul bootloader? Apoi, acest document conține răspunsuri la multe întrebări, pe care le veți avea în acest sens. Cele mai multe dintre conceptele menționate aici nu sunt suficient de detaliate în fișele tehnice pentru microcontrolere, dar toate aceste sfaturi sunt importante pentru proiectarea unor bootloadere de încredere. Cele mai multe informații prezentate aici pot fi găsite pe avrfreaks.net împrăștiate pe diferite ramuri. Întrebările de mai jos sunt ordonate de la simplu la complex și pentru a crea un încărcător viabil, probabil că doriți să înțelegeți răspunsurile, cel puțin pentru primele 11 întrebări.
Pentru a stăpâni cu succes materialul, se presupune că deja știți ce este pentru bootloader, știți cum să programați în limba C și că sunteți familiarizați cu crearea de aplicații comune pe 8 biți AVR. Acest document se bazează pe instrumentul AVR-GCC care utilizează bibliotecile AVR-Libc și modelul Makefile. Dacă utilizați un alt instrument, tot ceea ce este descris în acest document rămâne în vigoare, dar exemplele de cod Makefile ar trebui să fie
adaptate corespunzător instrumentului dvs.
De asemenea, rețineți că exemplele se bazează pe modelul AT90USB162 și ar trebui adaptate la AVR înainte de a fi reutilizate.
De unde să încep?
De fapt, bootloader-ul este doar o aplicație AVR obișnuită, care se află într-o zonă specială de memorie flash. În cea mai simplă formă, aplicația poate fi realizată ca încărcător AVR prin specificarea unui semnalizator suplimentar la linker care trebuie adăugat la makefile-ul său:
Ce sunt NRWW și RWW?
Iată ce trebuie să știți despre caracteristicile zonelor RWW și NRWW:
- Încărcătorul poate reprograma aplicațiile situate în zona RWW, în timp ce executarea încărcătorului nu este întreruptă;
- Încărcătorul nu își poate actualiza codul, pur și simplu ca un cod de aplicație;
- Aplicațiile rareori actualizează bootloader-ul;
- Aplicațiile se pot actualiza, dar este mai bine ca bootloaderul să facă acest lucru.
Cum actualizează descărcătorul aplicația?
Cum va primi programul de reprogramare a controlerului depinde de tine. Canalele comune de comunicație sunt UART și USB. Protocolul de comunicare pentru canal poate fi propriu sau standard, cum ar fi AVR109 sau DFU. Odată cu implementarea protocoalelor standard, puteți utiliza instrumentele existente, cum ar fi AVR Studio, care lucrează la protocolul AVR109 sau Flip-ul lui Atmel, care lucrează la protocolul DFU. Cu toate acestea, aceste protocoale standard sunt în general puțin exagerate, iar atunci când se implementează un simplu protocol particularizat, încărcătorul va fi de obicei mai mic și mai curat. Cu toate acestea, în acest caz, va trebui, de asemenea, să dezvoltați propria soluție pentru transferul datelor către încărcător.
În mod obișnuit, încărcătorul este trimis la o singură pagină de memorie. Încărcătorul trebuie să scrie aceste
paginile din zona de bliț destinată aplicației, adică în RWW. AVR-Libc oferă un fișier antet
Actualizatorul poate actualiza valorile de fuziune?
Cu AVR este imposibil. Pentru aceasta aveți nevoie de un programator extern.
De ce să folosiți BOOTLOADER_SECTION de la ?
În ciuda numelui său, macrocomanda BOOTLOADER_SECTION nu este utilă atunci când scrieți bootloaderul. Această macrocomandă vă ajută pur și simplu să vă reasociți funcția în secțiunea NRWW a memoriei flash. Probabil, pentru această macrocomanda, un nume mai potrivit este ceva de genul NRWW_SECTION.
Este posibil ca macrocomanda BOOTLOADER_SECTION să fie necesară dacă aplicația trebuie să reprogrameze propria aplicație, deoarece Această funcție va funcționa numai dacă este executată din partiția NRWW. BOOT_LOADER_SECTION într-adevăr creează doar o secțiune specială pentru numele de cod «.bootloader» (un alt nume pentru că este mai bine să nu-l folosească), și apoi o suplimentare de posturi de pavilion de legătură această secțiune undeva în zona neutilizată a secțiunii de memorie NRWW. Această abordare nu este foarte frecvent utilizată în practică.
Unii oameni tind să utilizeze BOOTLOADER_SECTION pentru a scrie aplicația și încărcătorul într-un singur program, dar aceasta nu este o idee bună. Încărcătorul este bun sub formă de programe independente, care nu depind de aplicația în sine. Aceasta va fi o soluție mai sigură, în timp ce în cazul în care încărcătorul este o aplicație separată, atunci va fi mai ușor să-l creați.
Cum se poate bloca un bootloader pentru microcontrolere?
Cum să bliți imediat aplicația și încărcătorul de încărcare?
Deoarece, sperăm, ați creat aplicația separat și încărcătorul separat, în final veți avea două fișiere hexazecimale separate cu firmware (de exemplu, app.hex și boot.hex). Se pune întrebarea: cum să le umpleți atât în AVR. Există mai multe opțiuni:
În două etape: Umpleți încărcătorul cu un programator extern așa cum este descris în Întrebarea nr. 6. De asemenea, este posibil să fie necesar să setați valorile de fuziune necesare, inclusiv BOOTSZ și BOOTRST. După aceea, puteți pur și simplu utiliza mecanismul obișnuit de comunicație de bootloader pentru transfer și firmware la microcontrolerul aplicației.
Într-un pas: Mergeți fișierele app.hex și boot.hex într-una și utilizați un programator extern pentru a scrie fișierul îmbinat în microcontroler. Este posibil să fie necesar să setați valorile de fuziune necesare, inclusiv BOOTSZ și BOOTRST.
Cred că cea mai ușoară cale de a combina fișierele hexazecimale este utilizarea liniei de comandă srec_cat. Acest instrument este inclus în setul de instrumente srecord. Acesta vine cu WinAVR și este foarte ușor de instalat pe sistemele Unix-like. Iată comanda pe care ar trebui să o utilizați:
De asemenea, puteți îmbina manual fișierele app.hex și boot.hex cu editări mici:
Fiecare fișier hexazecimal are o ultimă intrare, care afirmă că "fișierul se termină". Astfel, după îmbinarea manuală, trebuie să editați fișierul combinat hex - găsiți în el înregistrarea sfârșitul fișierului aflată la sfârșitul app.hex (după ce ați fuzionat undeva în mijlocul fișierului) și ștergeți-l. Înregistrarea este de tip 01. Octetul tipului de înregistrare în format hexazecimal Intel în ordine este al 4-lea octet, astfel că înregistrarea va arăta exact așa: ": 00000001FF". Întreaga linie (cea din mijloc, nu sfârșitul fișierului) trebuie șters.
Pot să folosesc întreruperi în bootloader?
Da, pentru asta este suficient să-i spuneți procesorului să utilizeze vectorul de întrerupere aflat în zona de încărcare și nu în zona de aplicații. Pentru aceasta, undeva la începutul codului încărcătorului (înainte de a utiliza întreruperile), trebuie să adăugați linii ca acestea:
După aceasta, în timpul întreruperilor, contorul de programe va fi mutat în poziția corespunzătoare conform tabelului de întreruperi al încărcătorului. Pentru funcționarea normală, secvența de mai sus de cod trebuie să fie compilate cu optimizări, de asemenea, trebuie să se asigure că manual ansamblul rezultat în instrucțiuni scrise care urmează să fie executat pentru 4 ciclu mașină.
Ce ar trebui să descărcați mai întâi - încărcătorul sau aplicația?
Este aproape întotdeauna cel mai bine să instalați BOOTRST pentru a porni primul bootloader după ce microcontrolerul este repornit. Când încărcătorul de boot este pornit după repornire, puteți reporni mai întâi programul, indiferent dacă codul aplicației este corupt sau deloc.
Pentru cea mai bună lucrare a încărcătoarelor, este necesar ca acestea să reprezinte programe mici, fiabile și rar modificate. Din ziua în care ați trimis dispozitivul în funcțiune, într-adevăr nu doriți să schimbați bootloader-ul pe acesta. Aplicarea, dimpotrivă, necesită mai multă libertate în ceea ce privește actualizarea. Dacă apare o eroare în aplicație care are ca rezultat un accident sau se blochează, sau când firmware-ul este dezactivat, se va produce o întrerupere a alimentării, un încărcător de încredere de încredere care va fi rulat mai întâi poate rezolva cu ușurință această situație.
Dacă aplicația începe după resetarea dispozitivului, puteți utiliza un programator extern pentru a rezolva problemele. Dar dacă dispozitivul nu are o interfață pentru conectarea programatorului, dispozitivul este cel mai probabil să fie aruncat sau reasociat.
Cum știu când să încep aplicația?
Există multe posibilități. Dacă dispozitivul are un buton sau alt mecanism de intrare, puteți trimite semnalul corespunzător apăsând. Apoi, încărcătorul, de regulă, va lansa aplicația imediat. Și în cazul în care butonul nu este apăsat în timpul resetării, încărcătorul continuă execuția. Acesta este un exemplu de funcționare a încărcătorului de piese STK500.
O altă soluție comună pentru bootloader este să verifice legătura externă cu un caracter special în timpul pornirii. Din nou, încărcătorul va lansa de obicei aplicația imediat, dar va continua să fie executat numai după verificarea canalului de comunicare extern și obținerea unui răspuns specific sau căutarea datelor așteptate. Un exemplu al acestei abordări este Atmel Butterfly.
În cazul nostru, niciuna dintre aceste soluții nu este adecvată. Dispozitivul nostru nu are butoane și ne-ar plăcea ca aplicația să ruleze în condiții normale foarte repede. Singurul canal de comunicare extern este USB, din păcate, dispozitivul USB necesită ceva timp (în expresia procesorului) înainte ca schimbul de date cu gazda să fie posibil.
Așa am făcut: presupunând că AVR are un EEPROM, puteți stoca o valoare octet în el, ceea ce indică momentul în care încărcătorul ar trebui să continue să funcționeze și când să pornească aplicația. Această abordare are două etape. Mai întâi, undeva la începutul codului de bootloader, trebuie să adăugați ceva de genul:
Apoi, undeva departe în aplicație, în acea parte a codului, atunci când procesați deja că sunteți sigur că aplicația funcționează corect, adăugați următoarele:
De asemenea, sugerez o modalitate de a forța aplicația bootloader. Trebuie doar să ștergeți octetul APP_RUN și să preveniți recensământul său mai târziu. Am pus în aplicare acest lucru în cererea noastră, și aceasta se face printr-o comandă trimisă prin USB de la programul care rulează pe computer.
Unul dintre dezavantajele acestei abordări este că Atmel EEPROM pe majoritatea controlorilor are o resursă de 100.000 cicluri de scriere / ștergere. Deoarece această abordare produce două cicluri de ștergere / scriere în timpul fiecărei porniri, resursa dispozitivului este limitată la 50.000 de cicluri de repornire. Pentru aplicația noastră, am estimat că durata de viață a dispozitivului este de 13,7 ani, cu 10 rebooturi pe zi. Această limită poate fi ușor extinsă dacă este distribuită uzura celulelor EEPROM.
Cum începe încărcătorul aplicația?
Dar asta nu e tot. Când rulați direct aplicația în acest fel, microcontrolerul nu va fi resetat la starea inițială, așa cum o face după repornire. Valorile registrelor nu sunt șterse și periferia nu este oprită. Există două modalități comune de a face față acestui fapt. Prima abordare este declanșarea intenționată a unei resetări utilizând un cronometru de supraveghere. Aceasta va reseta microcontrolerul la starea inițială și va relua încărcătorul de boot (dacă aveți bitul BOOTRST setat). Dacă nu mai există condițiile care au cauzat încărcătorul (de exemplu, nu mai țineți apăsat butonul), încărcătorul ar trebui să pornească imediat aplicația. Este necesar să se înceapă executarea aplicației cât mai curând posibil, atâta timp cât modificările au atins cât mai puțin posibil resursele microcontrolerului. Iată un exemplu:
Aplicația trebuie apoi să configureze în mod explicit toate resursele pe care le va utiliza.