Implementazione del bootloader

Il bootloader è uno strumento fondamentale e indispensabile per l’aggiornamento del codice applicativo di un microcontrollore. Questo articolo, basato su un Application Note di Microchip, esamina le caratteristiche basilari del bootloader sviluppato per la famiglia di microcontrollori PIC32, arrivando a definire anche i dettagli implementativi.

Disporre di un bootloader rappresenta un vantaggio enorme per ogni sviluppatore di software per microcontrollori. E’ infatti possibile aggiornare velocemente il software residente sulla memoria flash del microcontrollore, disponendo di una comune connessione tra il PC di sviluppo ed il sistema target (a seconda dei casi, può essere una comune connessione seriale, USB, Ethernet, Can, etc.). Durante la normale attività di sviluppo è frequente dover aggiornare e scaricare il software numerose volte al giorno, ed è quindi fondamentale avere a disposizione uno strumento che permetta di eseguire queste operazioni in modo veloce ed efficace.

Inoltre, il bootloader rappresenta una valida alternativa ai programmatori e ai debugger esterni di tipo in-circuit, che, pur disponendo in generale di funzionalità più estese e maggiormente complesse, hanno comunque un costo non trascurabile e non sono strettamente necessari per chi è unicamente interessato allo sviluppo software. Il bootloader è pertanto uno strumento di aggiornamento del software semplice ed economico, non richiede conoscenze hardware particolari, ma soltanto un’applicazione software da eseguire sul sistema host (un comune PC). Questa applicazione, comunicando con il firmware del bootloader in esecuzione sul dispositivo PIC32 del target, permette di eseguire le operazioni di cancellazione e di programmazione della memoria flash tramite l’invio di appositi comandi.

IL FUNZIONAMENTO BASILARE DI UN BOOTLOADER

In Figura 1 è mostrato il diagramma di flusso che descrive il comportamento basilare di un bootloader. Il bootloader viene anzitutto caricato dopo ogni reset/power-on del sistema target. Dopo avere eseguito l’inizializzazione del clock di sistema, il bootloader controlla se sono soddisfatte le condizioni per entrare nella modalità di aggiornamento del codice applicativo (“firmware upgrade mode”). Se ciò avviene, il codice applicativo presente sulla memoria flash del microcontrollore viene aggiornato (in questo caso il bootloader stesso eseguirà pertanto delle operazioni di cancellazione e programmazione della memoria flash).

Se invece le condizioni per l’ingresso nella modalità di programmazione non sono valide, il bootloader procede la propria esecuzione verificando se sulla memoria flash integrata risiede un programma applicativo valido (ciò avviene quando il contenuto del vettore di reset dell’applicativo utente non è valido). In caso affermativo lo carica e lo manda in esecuzione, altrimenti si porta automaticamente nello stato di firmware upgrade. Si noti come, sulle schede di sviluppo per i microcontrollori PIC32 di Microchip, sia sempre possibile forzare dall’esterno l’ingresso nella modalità di programmazione agendo su degli switch opportuni (consultare il manuale operatore della scheda di sviluppo specifica).

L’uscita dalla modalità di programmazione può avvenire in modi differenti, a seconda del tipo di interfaccia adottata dal bootloader: per il bootloader con interfaccia di tipo USB HID, Ethernet, oppure seriale (UART), è possibile uscire dalla modalità di aggiornamento del firmware applicando un reset hardware del dispositivo, oppure inviando un comando “Jump to Application” tramite il PC collegato al target per le versioni di bootloader residenti su chiavetta USB o su scheda di memoria SD, è invece possibile uscire dalla modalità di aggiornamento del firmware con un hardware reset oppure quando viene completata la programmazione del firmware. Occorre, inoltre, osservare come riportato nel diagramma di flusso di Figura 1, che è necessario disabilitare ogni interrupt precedentemente abilitato prima di mandare in esecuzione il software applicativo. Eventuali interrupt abilitati durante l’esecuzione del bootloader e lasciati attivi, potrebbero infatti interferire con il programma applicativo e causare un malfunzionamento dello stesso. Gli interrupt dovrebbero quindi essere abilitati e gestiti, quando necessario, direttamente dal software applicativo.

Figura 1: il diagramma di flusso di un bootloader.

Figura 1: il diagramma di flusso di un bootloader

POSIZIONAMENTO IN MEMORIA DEL BOOTLOADER

Il posizionamento del software di bootloading all’interno della memoria flash dipende sostanzialmente dalle dimensioni del bootloader stesso. In generale, possiamo distinguere due schemi di principio, evidenziati a sinistra e a destra, rispettivamente, in Figura 2.

Figura 2: posizionamento del bootloader in memoria

Figura 2: posizionamento del bootloader in memoria

Il primo è valido per i bootloader con dimensioni ridotte del codice, e in questo caso il suo codice viene collocato all’interno dell’area “boot flash” della memoria flash del PIC32. In questo caso, l’intera area di memoria “program flash” è a disposizione per contenere l’applicativo dell’utente. La seconda opzione si applica invece nei casi in cui la dimensione del bootloader superi la dimensione dell’area “boot flash” del PIC32, e prevede che il codice del bootloader venga suddiviso in due parti. L’Interrupt Vector Table (IVT) e il codice C di start-up vengono in questo caso collocati all’interno della “boot flash”, mentre la parte rimanente del bootloader viene posta nell’area “program flash”. Occorre, inoltre, precisare che le dimensioni delle aree di memoria “boot flash” e “program flash” dipendono dalla particolare versione del dispositivo (microcontrollore) impiegato. E’ pertanto necessario fare riferimento al paragrafo “Organizzazione della memoria” del datasheet del componente per ottenere maggiori informazioni in merito.

L’IMPLEMENTAZIONE DI UN BOOTLOADER

Il bootloader viene implementato tramite l’utilizzo di un framework. Il firmware del bootloader comunica con l’applicazione presente sul sistema host (un normale PC) tramite un protocollo di comunicazione predefinito. Il framework del bootloader fornisce delle funzioni di Application Programming Interface (API) per la gestione dei messaggi di protocollo provenienti dal PC. Questi messaggi saranno esaminati più in dettaglio nel seguito.

IL FRAMEWORK

In Figura 3 è mostrata l’architettura tipica di un bootloader. Il framework mette a disposizione una serie di funzioni API, le quali possono essere invocate dall’applicazione del bootloader e dal layer di trasporto.

Figura 3: architettura classica di un bootloader.

Figura 3: architettura classica di un bootloader

Il framework aiuta perciò l’utente a modificare agevolmente il software applicativo del bootloader in modo tale da adattarsi a requisiti diversi. Il file Bootloader.c, incluso nel pacchetto scaricabile dal sito Microchip, include il codice del bootloader e riflette il diagramma di flusso rappresentato in Figura 1. Il file Framework.c include invece le funzioni relative al framework, il cui compito principale è quello di gestire i messaggi appartenenti al protocollo di comunicazione ed eseguire i comandi impartiti dal software applicativo residente sul PC host. Infine, i file Uart.c e Usb_HID_tasks.c includono le funzionalità relative alla trasmissione e alla ricezione di basso livello verso l’applicazione host. La tabella di Figura 4 elenca dettagliatamente le diverse funzioni offerte dal framework.

Figura 4: le API del framework.

Figura 4: le API del framework

LE WORD DI CONFIGURAZIONE

E’ importante sottolineare che il bootloader non cancella e non scrive le word di configurazione del dispositivo durante la fase di programmazione del nuovo firmware applicativo. Ciò avviene in quanto queste impostazioni sono utilizzate sia dal bootloader che dal programma applicativo dell’utente. Il contenuto delle word di configurazione potrebbe infatti compromettere il funzionamento del bootloader, ed è pertanto fortemente consigliato scegliere delle impostazioni di configurazione comuni sia al bootloader che all’applicazione utente.

IL PROTOCOLLO DI COMUNICAZIONE

L’applicazione in esecuzione sul PC host utilizza un protocollo di comunicazione per interagire con il firmware del bootloader. Il PC host si comporta come master, ed invia i comandi al firmware del bootloader al fine di eseguire specifiche operazioni.

FORMATO DEL FRAME

Il protocollo di comunicazione utilizza uno specifico formato di frame, come indicato nell’esempio seguente. Il formato del frame è lo stesso in entrambe le direzioni, cioè sia da host verso bootloader che da bootloader verso host. [<SOH>...]<SOH>[<DATA>...]<CRCL>< CRCH><EOT> dove <...> rappresenta un byte, mentre [...] rappresenta un numero di byte opzionale o variabile. Il frame inizia con un carattere di controllo (SOH, Start Of Header, codice Ascii 0x01), e termina con un altro carattere di controllo (EOT, End Of Transmission, codice Ascii 0x04). L’integrità del frame è protetta da un codice di controllo a ridondanza ciclica di tipo CRC-16 (rappresentato dai due byte CRCL e CRCH).

CARATTERI DI CONTROLLO

Alcuni byte contenuti all’interno dell’area dati potrebbero assumere lo stesso valore dei due caratteri di controllo (SOH e EOT). Al fine di evitare possibili errori di interpretazione del messaggio, se uno di questi caratteri è incluso nell’area dati, esso verrà fatto precedere dal carattere Data Link Escape (DLE, codice Ascii 0x10) in modo tale che esso non venga erroneamente interpretato come carattere di controllo. Il bootloader accetta sempre i byte che seguono un carattere <DLE>, ed invia sempre un carattere <DLE> prima di ogni carattere di controllo presente nell’area dati.

COMANDI

L’applicazione su PC host può inviare ciascuno dei comandi elencati nella tabella di Figura 5. Il primo byte dell’area dati del comando identifica il codice del comando stesso.

Figura 5: elenco dei comandi al bootloader.

Figura 5: elenco dei comandi al bootloader

READ BOOTLOADER VERSION

Questo comando viene inviato dal PC per conoscere la versione del bootloader. Il frame del messaggio di richiesta è il seguente: [<SOH>...]<SOH><0x01><CRCL><CRCH ><EOT> Il bootloader risponde con un frame in cui l’area dati comprende due byte: [<SOH>...]<SOH><0x01><MAJOR_VER> <MINOR_VER><CRCL><CRCH><EOT> dove MAJOR_VER e MINOR_VER indicano, rispettivamente, la versione major e minor del bootloader. ERASE FLASH Quando il bootloader riceve questo comando dall’applicazione host, esegue la cancellazione dell’area di memoria “program flash”, quella cioè utilizzata per contenere l’applicazione utente . La struttura del frame relativa a questo comando è la seguente:

[<SOH>...]<SOH><0x02><CRCL><CRC H><EOT>

Il bootloader risponde con un frame di questo tipo: [<SOH>...]<SOH><0x02><CRCL><CRC H><EOT> PROGRAM FLASH Attraverso questo comando, l’applicazione in esecuzione sul sistema host invia uno o più record dati in formato Intel Hex. Il compilatore MPLAB C32 genera in output un’immagine in formato Intel Hex, nella quale ogni linea rappresenta proprio un record di questo tipo. Ciascun record inizia con un carattere “:” e contiene caratteri tutti in formato ASCII. L’applicazione host rimuove il carattere “:” e converte i dati rimanenti da formato ASCII a formato esadecimale, inviandoli poi al bootloader. Quest’ultimo estrae dal record hex l’indirizzo di destinazione e i dati, e scrive i dati ricevuti nella memoria flash (“program flash”) all’indirizzo specificato. Il frame corrispondente inviato dall’applicazione host è formattato nel seguente modo:

[<SOH>...]<SOH><0x03>[<HEX_RECOR D>…]<CRCL><CRCH><EOT> dove <HEX_RECORD>

è il record hex in formato esadecimale. Il messaggio di risposta del bootloader ha un frame di questo tipo:

[<SOH>...]<SOH><0x03><CRCL><CRC H><EOT>

READ CRC

Questo comando serve per verificare il CRC dopo aver eseguito l’operazione di programmazione della memoria flash. In sostanza, la sua funzione è quella di determinare se la “program flash” è stata programmata correttamente o meno. La struttura del frame relativa a questo comando è la seguente:

[<SOH>...]<SOH><0x04><ADRS_LB><ADRS_HB><ADRS_UB><ADRS_MB><NUMBYTES_LB><NUMBYTES_HB><NUMBYTES_UB><NUMBYTES_MB><CRCL><CRCH><EOT>

dove ADRS_LB, ADRS_HB, ADRS_UB e ADRS_MB rappresentano gli indirizzi a 32-bit di memoria flash dai quali inizia il calcolo del CRC. NUMBYTES_ LB, NUMBYTES_HB, NUMBYTES_ UB e NUMBYTES_MB rappresentano invece il numero totale di bytes in formato a 32-bit sui quali deve essere calcolato il CRC. Il bootloader risponde con un frame di questo tipo: [<SOH>...]<SOH><0x04><FLASH_CRCL>< FLASH_CRCH><CRCL><CRCH>< EOT> JUMP TO APPLICATION Attraverso questo comando, l’applicazione su PC host ordina al bootloader di eseguire il codice applicativo utente. Il messaggio di richiesta è il seguente: [<SOH>...]<SOH><0x05><CRCL><CRC H><EOT> Non è prevista alcuna risposta a questo comando da parte del bootloader, in quanto quest’ultimo, dopo la ricezione del comando in oggetto, esce immediatamente dalla modalità di firmware upgrade e comincia a eseguire il codice applicativo.

CONFIGURAZIONE DEL BOOTLOADER

Il codice del bootloader comprende alcune macro per configurare le impostazioni per la compilazione. Le Figure da 6 a 9 elencano queste macro e il loro utilizzo. A seconda dei casi particolari, potrebbe essere necessario modificare in alcuni casi questi valori.

Figura 6: macro di uso generale.

Figura 6: macro di uso generale

 

Figura 7: macro UART bootloader.

Figura 7: macro UART bootloader

 

Figura 8: macro USB HID bootloader

Figura 8: macro USB HID bootloader

 

Figura 9: macro Ethernet bootloader.

Figura 9: macro Ethernet bootloader

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend