Che cos'è un boot loader e come lo svilupperei?


53

Ho incontrato molti progetti in cui un microcontrollore AVR utilizza un bootloader (come Arduino), ma non capisco molto bene il concetto.

Come posso creare un bootloader (per qualsiasi microcontrollore)?

Dopo aver scritto il mio bootloader, come viene programmato sul microcontrollore (come qualsiasi programma .hex masterizzato sulla rom flash dell'AVR o qualche altro metodo)?


10
L'hai taggato con il tag bootloader , l'hai letto? In tal caso, hai letto Arduino Bootloader , Arduino Bootloader Follow On , Arduino Bootloader , Buoni strumenti o metodi per comprendere la struttura del bootloader e Arduino Bootloader Dettagli domande? Tutti affrontano parti della tua domanda iniziale. L'ho ridotto alle nuove cose.
Kevin Vermeer,

Un documento sul metodo di BootLoader Design: beningo.com/wp-content/uploads/images/Papers/…
tawil

2
@KevinVermeer Penso che la sua domanda sia più semplice.
richieqianle,

Risposte:


103

Un bootloader è un programma che viene eseguito nel microcontrollore da programmare. Riceve nuove informazioni sul programma esternamente tramite alcuni mezzi di comunicazione e scrive tali informazioni nella memoria del programma del processore.

Ciò è in contrasto con il modo normale di inserire il programma nel microcontrollore, che è tramite hardware speciale incorporato nel micro a tale scopo. Sui PIC, questa è un'interfaccia simile a SPI. Se ricordo bene, gli AVR usano Jtag, o almeno alcuni di loro. Ad ogni modo, ciò richiede dell'hardware esterno che fa oscillare i pin di programmazione proprio per scrivere le informazioni nella memoria del programma. Il file HEX che descrive il contenuto della memoria del programma ha origine su un computer per uso generale, quindi questo hardware si collega al computer da un lato e agli speciali pin di programmazione del micro dall'altro. La mia azienda crea programmatori PIC tra le altre cose come una linea laterale, quindi ho abbastanza familiarità con questo processo sui PIC.

Il punto importante della programmazione esterna tramite hardware specializzato è che funziona indipendentemente dal contenuto esistente della memoria del programma. I microcontrollori iniziano con la memoria del programma cancellata o in uno stato sconosciuto, quindi la programmazione esterna è l'unico mezzo per inserire il primo programma in un micro.

Se sei sicuro del programma che desideri caricare nel tuo prodotto e i tuoi volumi sono abbastanza alti, puoi avere i chip del programma del produttore o del distributore per te. Il chip viene saldato alla scheda come qualsiasi altro chip e l'unità è pronta per partire. Questo può essere appropriato per qualcosa come un giocattolo, per esempio. Una volta che il firmware è finito, è praticamente fatto e sarà prodotto in grandi volumi.

Se i tuoi volumi sono più bassi o, cosa più importante, ti aspetti uno sviluppo del firmware e correzioni di bug in corso, non vuoi acquistare chip pre-programmati. In questo caso, sulla scheda vengono montati chip vuoti e il firmware deve essere caricato sul chip come parte del processo di produzione. In tal caso, le linee di programmazione hardware devono essere rese disponibili in qualche modo. Questo può avvenire tramite un connettore esplicito o pad pogo se si è disposti a creare un dispositivo di prova di produzione. Spesso tali prodotti devono essere testati e magari calibrati comunque, quindi il costo aggiuntivo di scrivere il programma sul processore è generalmente minimo. A volte, quando vengono utilizzati piccoli processori, nel processore viene caricato per la prima volta un firmware di test di produzione speciale. Questo è usato per facilitare il test e la calibrazione dell'unità, quindi il firmware reale viene caricato dopo che l'hardware è noto per essere buono. In questo caso ci sono alcune considerazioni sulla progettazione del circuito per consentire l'accesso alle linee di programmazione in modo sufficiente per il funzionamento del processo di programmazione, ma anche per non disturbare troppo il circuito. Per maggiori dettagli su questo, vedi il mioscrittura di programmazione in-circuit .

Fin qui tutto bene, e non è necessario alcun bootloader. Tuttavia, considerare un prodotto con firmware relativamente complesso che si desidera aggiornare sul campo o addirittura consentire al cliente finale di aggiornare. Non puoi aspettarti che il cliente finale disponga di un gadget programmatore o sapere come utilizzarlo correttamente anche se ne hai fornito uno. In realtà uno dei miei clienti lo fa. Se acquisti l'opzione di personalizzazione del campo speciale, ricevi uno dei miei programmatori con il prodotto.

Tuttavia, nella maggior parte dei casi si desidera solo che il cliente esegua un programma su un PC e che il firmware venga aggiornato magicamente. È qui che entra in gioco un bootloader, soprattutto se il tuo prodotto ha già una porta di comunicazione che può facilmente interfacciarsi con un PC, come USB, RS-232 o Ethernet. Il cliente esegue un programma per PC che parla con il bootloader già nel micro. Questo invia il nuovo binario al bootloader, che lo scrive nella memoria del programma e quindi fa eseguire il nuovo codice.

Sembra semplice, ma non lo è, almeno non se si desidera che questo processo sia solido. Cosa succede se si verifica un errore di comunicazione e il nuovo firmware è corrotto quando arriva al bootloader? Cosa succede se l'alimentazione viene interrotta durante il processo di avvio? Cosa succede se il bootloader ha un bug e craps su se stesso?

Uno scenario semplicistico è che il bootloader viene sempre eseguito dal ripristino. Prova a comunicare con l'host. Se l'host risponde, allora comunica al bootloader che non ha nulla di nuovo o gli invia un nuovo codice. All'arrivo del nuovo codice, il vecchio codice viene sovrascritto. Includi sempre un checksum con il codice caricato, in modo che il bootloader possa dire se la nuova app è intatta. In caso contrario, rimane nel bootloader richiedendo costantemente un caricamento fino a quando qualcosa con un checksum valido viene caricato in memoria. Ciò potrebbe essere accettabile per un dispositivo sempre connesso e possibilmente in cui viene eseguita un'attività in background sull'host che risponde alle richieste del bootloader. Questo schema non è utile per le unità che sono in gran parte autonome e solo occasionalmente si connettono a un computer host.

Di solito il semplice bootloader come descritto sopra non è accettabile poiché non esiste un fail-safe. Se una nuova immagine dell'app non viene ricevuta intatta, si desidera che il dispositivo continui a eseguire la vecchia immagine, non rimanga morto fino a quando non viene eseguito correttamente il caricamento. Per questo motivo, di solito ci sono due moduli speciali nel firmware, un uploader e un bootloader. L'autore del caricamento fa parte dell'app principale. Come parte delle comunicazioni regolari con l'host, è possibile caricare una nuova immagine dell'app. Ciò richiede memoria separata dall'immagine dell'app principale, come una EEPROM esterna o utilizzare un processore più grande in modo che metà dello spazio di memoria del programma possa essere allocato per l'archiviazione della nuova immagine dell'app. L'autore del caricamento scrive semplicemente l'immagine della nuova app ricevuta da qualche parte, ma non la esegue. Quando il processore viene ripristinato, il che potrebbe accadere su comando dall'host dopo un caricamento, il bootloader viene eseguito. Questo è ora un programma totalmente autonomo che non necessita di capacità di comunicazione esterna. Confronta le versioni di app correnti e caricate, controlla i loro checksum e copia la nuova immagine nell'area dell'app se le versioni differiscono e il nuovo checksum delle immagini verifica. Se la nuova immagine è corrotta, esegue semplicemente la vecchia app come prima.

Ho fatto molti bootloader e non ce ne sono due uguali. Non esiste un bootloader generico, nonostante ciò che alcune aziende di microcontrollori vogliono farti credere. Ogni dispositivo ha i propri requisiti e circostanze speciali nei rapporti con l'host. Ecco solo alcune delle configurazioni di bootloader e talvolta uploader che ho usato:

  1. Bootloader di base. Questo dispositivo aveva una linea seriale e sarebbe stato collegato a un host e acceso come necessario. Il bootloader è stato eseguito dalla reimpostazione e ha inviato all'host alcune risposte alla richiesta di caricamento. Se il programma di caricamento era in esecuzione, risponderebbe e invierebbe una nuova immagine dell'app. Se non rispondesse entro 500 ms, il bootloader avrebbe rinunciato ed eseguito l'app esistente. Pertanto, per aggiornare il firmware, è stato necessario eseguire prima l'app di aggiornamento sull'host, quindi connettersi e accendere il dispositivo.

  2. Programma di caricamento della memoria. Qui abbiamo usato il PIC di dimensioni successive che aveva il doppio della memoria del programma. La memoria del programma è stata approssimativamente divisa in 49% app principale, 49% nuova immagine app e 2% bootloader. Il bootloader verrebbe eseguito dal ripristino e copierebbe la nuova immagine dell'app sull'immagine corrente dell'app nelle giuste condizioni.

  3. Immagine EEPROM esterna. Come il n. 2, tranne per il fatto che è stata utilizzata una EEPROM esterna per memorizzare la nuova immagine dell'app. In questo caso il processore con più memoria sarebbe stato anche fisicamente più grande e in una sottofamiglia diversa che non aveva il mix di periferiche di cui avevamo bisogno.

  4. Bootloader TCP. Questo è stato il più complesso di tutti. È stato utilizzato un grande PIC 18F. L'ultimo 1/4 di memoria conteneva circa il bootloader, che aveva la propria copia completa di uno stack di rete TCP. Il bootloader è stato eseguito dal ripristino e ha tentato di connettersi a un server di caricamento speciale in una porta nota a un indirizzo IP precedentemente configurato. Questo era per grandi installazioni dove c'era sempre una macchina server dedicata per l'intero sistema. Ogni piccolo dispositivo effettuerà il check-in con il server di caricamento dopo il ripristino e riceverà una nuova copia dell'app, a seconda dei casi. Il bootloader sovrascriverà l'app esistente con la nuova copia, ma la eseguirà solo se il checksum è selezionato. In caso contrario, tornerebbe al server di caricamento e riproverebbe.

    Poiché il bootloader era esso stesso un pezzo complicato di codice contenente uno stack di rete TCP completo, doveva essere aggiornabile anche sul campo. Il modo in cui lo abbiamo fatto è stato quello di fare in modo che il server di caricamento gli fornisse un'app speciale il cui unico scopo era quello di sovrascrivere il bootloader una volta eseguito, quindi ripristinare la macchina in modo che il nuovo bootloader fosse in esecuzione, il che avrebbe causato al server di upload di inviare il ultima immagine dell'app principale. Tecnicamente, un errore tecnico durante i pochi millisecondi necessari all'app speciale per copiare una nuova immagine sul bootloader sarebbe un errore irrecuperabile. In pratica questo non è mai successo. Eravamo d'accordo con la probabilità molto improbabile di ciò dal momento che questi dispositivi facevano parte di grandi installazioni in cui c'erano già persone che avrebbero fatto manutenzione sul sistema, il che a volte significava sostituire i dispositivi integrati per altri motivi comunque.

Spero che tu possa vedere che ci sono molte altre possibilità, ognuna con i suoi compromessi di rischio, velocità, costo, facilità d'uso, tempi di inattività, ecc.


1
Tutti gli AVR ad eccezione della famiglia Xmega (che ha una nuova interfaccia a 2 fili) utilizzano un'interfaccia SPI mentre vengono mantenuti in ripristino. Quelli più grandi hanno anche JTAG, alcuni hanno una programmazione parallela e quelli più piccoli potrebbero richiedere alta tensione se il reset è stato riconfigurato come I / O. Alcuni MCU, come le famiglie Parallax Propeller e Motorola / Freescale 68HC08, non hanno hardware di programmazione minimo ma bootloader nella ROM.
Yann Vernier,

Confronta le versioni di app correnti e caricate, controlla i loro checksum e copia la nuova immagine nell'area dell'app se le versioni differiscono e il nuovo checksum delle immagini verifica. Sì, ma se si interrompesse l'alimentazione nel mezzo di questa azione, ci sarebbe un'immagine corrotta nell'area "app". Suppongo che potrebbe essere meglio avere un'app bootloader-fail-safe che scrive la nuova app nel flash MCU e se il checksum è valido, scrive anche da qualche parte "ok per avviare la nuova app". Quindi, all'avvio, verifica se è possibile avviare la nuova app, se non lo è continua l'esecuzione stessa (app fail-safe)
Ervadac,

@Erv: se l'alimentazione si interrompe durante la copia della nuova versione sull'attuale, allora il checksum della versione corrente fallirà quando l'alimentazione viene ripristinata e il bootloader viene eseguito nuovamente. Di solito metto la parola checksum alla fine dell'immagine in modo che ogni scrittura parziale abbia ottime possibilità di errore del checksum.
Olin Lathrop,

Ciao. Posso consigliarti il ​​bootloader di tipo 5: anziché lo stack TCP, puoi implementare UDP. Quindi utilizzare TFTP per scaricare l'aggiornamento o il protocollo nativo.
i486,

22

Qual è il concetto di bootloader?

Immagina questo scenario: hai una buona quantità di spazio sul tuo microcontrollore, abbastanza per memorizzare più di 2-3 programmi o applicazioni indipendenti l'uno dall'altro. Supponi che quando avvii il dispositivo, potresti voler scegliere quale eseguire. Quindi cosa avresti bisogno per supportare questo? Avresti bisogno di un programma di avvio che ti consenta di scegliere tra gli altri all'avvio.

Come funziona?

Un bootloader è quel programma: è la prima cosa da eseguire e può caricare altre applicazioni in luoghi specifici della memoria (persistenti come FLASH o volatili come la RAM) e poi saltare al programma desiderato dove subentra l'esecuzione da lì .

Come creare un bootloader avr (o per qualsiasi microcontrollore)?

Non ho mai creato un bootloader ma è così che penso che farei a farlo: inizia a scrivere un programma firmware come faresti normalmente, ma assicurati che sia posizionato in un'area tale che sia sempre la prima cosa da eseguire quando il dispositivo si avvia. In cima alla mia testa, alcune delle funzionalità che vorrei da questo piccolo programma: capacità di caricare un nuovo programma in un posto disponibile in memoria, cancellare un programma precedentemente caricato, scegliere quale programma eseguire (se c'è più di uno) e avere una sorta di struttura di dati di archiviazione (tabella di salto in grado di crescere?) per essere in grado di ricordare dove si trovano gli altri programmi e passare a loro. L'interazione potrebbe avvenire tramite UART, dove può presentare un menu terminale molto semplice e la possibilità di caricare il firmware sullo stesso canale.

Come è programmato per il microcontrollore (come qualsiasi programma .hex masterizzato sulla rom flash di avr o qualche altro metodo)?

Se si tratta di un chip completamente vuoto senza bootloader esistente in grado di aggiornarsi, è necessario masterizzare su FLASH proprio come descritto utilizzando la tecnica necessaria per eseguire ciò (ICSP nel caso di AVR).

Questo non è affatto comprensibile di cosa siano i "bootloader". A seconda di ciò che si desidera da uno o dal sistema per cui sono progettati, è possibile progettarne uno per caricare elementi in una posizione specificata nella RAM anziché in FLASH e iniziare l'esecuzione in qualsiasi posizione di memoria arbitraria. O forse ne vuoi uno in grado di scegliere quale sistema operativo caricare all'avvio del tuo PC (vedi ad esempio grub ). I bootloader per i microcontrollori a 8 bit tendono ad essere molto semplici.

Una nota su Arduino: questo bootloader gestisce solo un programma AFAIK, inoltre prende in carico la porta seriale per gestire il caricamento del firmware e altre cose .


Cordiali saluti, la risposta è stata scritta per affrontare i punti elenco originali che ora sono stati modificati.
Jon L

3

Il concetto di caricatore "boot" è simile al concetto di "adescamento" di una pompa. In altre parole, hai bisogno di "qualcosa" che carichi un programma su un determinato indirizzo e quindi inizi a eseguire il programma a quel determinato indirizzo. Quel qualcosa è il boot loader. Nel caso più semplice, il boot loader "appare" all'indirizzo di partenza designato della CPU (zero, molto probabilmente), carica il programma nel segmento di memoria richiesto, trasferisce il controllo su di esso e "scompare". L'aspetto e la scomparsa sono controllati da hardware "esterno". Una possibile implementazione sarebbe quella di utilizzare una ROM che viene attivata tramite un ripristino "hardware" e disattivata con un ripristino "software". Il caricatore nella ROM può essere semplice o complesso come richiesto, e deve essere scritto in forma binaria comprensibile per la specifica CPU. Se lo spazio di indirizzi utilizzato dalla ROM non è necessario, la disattivazione della ROM non sarebbe necessaria. Ovviamente, EEPROM, ePROM, Flash PROM, ecc. Potrebbero essere utilizzati al posto della ROM.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.