Bootloader secondario via I2C

Questo articolo della Rubrica Firmware Reload tratta la realizzazione di un bootloader in grado di aggiornare il firmware via I2C e alcuni dei prodotti delle famiglie LPC11xx e LPC17xx di NXP.

Introduzione

Nei microcontrollori delle famiglie LPC11xx e LPC17xx esiste un boot block in cui risiede il bootloader primario. Questo bootloader è eseguito ogni volta che il microcontrollore viene alimentato o resettato. Attraverso questo b.l. è possibile eseguire l’ISP command handler o il codice dell’applicazione utente memorizzata nei settori di flash interna. L’obiettivo di questo progetto è di introdurre una applicazione utente che permetta di aggiornare il firmware applicativo o eseguire quello già memorizzato. Collocato all’indirizzo 0x00, sarà la prima esecuzione che lancia il bootloader primario in modalità user application. Poiché vogliamo che lo scambio del firmware applicativo da aggiornare avvenga via I2C, dobbiamo considerare che dovrà essere un altro microcontrollore a fornire le informazioni.

Avremo quindi una MCU slave sulla quale vogliamo aggiornare il firmware applicativo e una MCU master che comunica via I2C con la CPU slave e che comunica via RS232 con un PC, sul quale un terminale permette di scaricare il file desiderato. In Figura 1 viene schematizzato il sistema come descritto in precedenza. L’utente interagisce con la MCU master attraverso un terminale Tera term. La MCU master supporta 3 comandi: lettura dell'user application firmware ID della MCU slave, aggiorna lo user application firmware e aggiorna il bootloader secondario della MCU slave. Il firmware da scaricare sulla MCU slave è contenuto all’interno della memoria della MCU master, a partire dal settore 1. Quando la MCU master riceve un comando dal PC, comunica con la MCU slave per intraprendere le azioni necessarie. Tutte le transazioni tra la MCU master e la MCU slave sono fatte tramite I2C.

Figura 1: Componenti del sistema.

Figura 1: Componenti del sistema

MAPPA DI MEMORIA

La MCU slave ha il bootloader secondario collocato in corrispondenza del primo settore della flash. Allo startup, il bootloader controlla il codice utente verificando il firmware version ID (gli ultimi 4 byte della memoria flash). Se l’ID non è valido (0xFFFFFFFF), la MCU slave entra nel bootloader secondario e aspetta per un nuovo firmware tramite il bus I2C. Se invece l’ID risulta valido, la MCU entra in application mode ed esegue la routine di reset dello user application firmware all’indirizzo 0x1004. In application mode, lo slave supporta ancora la possibilità di leggere il firmware version ID dell’applicativo e l’aggiornamento del firmware. In più, anche il firmware del bootloader secondario può essere aggiornato utilizzando un comando dedicato proveniente dalla MCU master.

La mappa di memoria della MCU slave è mostrata in Figura 2. La memoria flash è divisa in due regioni. Una è dedicata al piazzamento del firmware applicativo utente e l’altra è dedicata al bootloader secondario. Il bootloader secondario è collocato nei primi 4 KB di memoria flash e viene eseguito per primo quando il sistema si resetta. La versione è memorizzata negli ultimi 4 byte della memoria flash da 0x7FFFC (nel caso la MCU sia un LPC17xx) oppure da 0x7FFC (se la MCU è una LPC11xx). Il bootloader secondario mette a disposizione anche un entry point per chiamare le sue API, l’indirizzo è 0xFF0. In Figura 3 è possibile vedere la mappa di memoria per la MCU master. Il firmware risiede nel settore 0 della flash interna.

Figura 3: Componenti del sistema.

Figura 2: Componenti del sistema

I rimanenti settori sono riservati alla memorizzazione del firmware e del bootloader secondario per la MCU slave. Quando la MCU master deve procedere all’aggiornamento del firmware dello slave, preleva i dati dai settori dedicati e li trasmette via I2C.

IL SOFTWARE

La NXP mette a disposizione una nota applicativa e il codice necessario per sviluppare una applicazione come questa. I comandi che la MCU master può ricevere tramite il terminale sono tradotti in tre “function ID” che vengono inviati via I2C alla MCU slave. In Tabella 3 si possono vedere i rispettivi codici. Per il dettaglio del protocollo I2C tra MCU master e MCU slave si rimanda all’application note di NXP. Analizziamo il ciclo operativo della MCU slave. Il diagramma di flusso della MCU slave è mostrato in Figura 4. All’avvio, la parte di bootloader secondario verifica l’ID del firmware e, se non è valido, si mette in attesa di comandi provenienti dalla MCU master, con la possibilità di aggiornare solo la sezione dedicata all’user application. Se l’ID firmware è valido, ci spostiamo sul lato di destra del diagramma di flusso di Figura 4.

Figura 4: Diagramma di flusso per la MCU slave.

Figura 3: Diagramma di flusso per la MCU slave

L’applicativo è in esecuzione ma la ricezione di un comando come riportato in Tabella 1 genera la conseguente azione, con la differenza che in questo caso anche il comando 0x33 di aggiornamento del bootloader secondario (SBL) sulla MCU slave risulta fattibile. Al termine dell’aggiornamento, un reset permette di portare in esecuzione il nuovo bootloader secondario appena caricato. Nel caso di aggiornamento del firmware applicativo dall’interno del bootloader secondario, la sequenza delle operazioni è quella mostrata nel diagramma di flusso di Figura 5. Nel caso la procedura di aggiornamento avvenga dall’interno dell'applicativo utente il diagramma di flusso è mostrato in Figura 6. Per invocare una funzione del bootloader secondario dall’interno dell’applicativo utente, si usa la zona di entry point con le chiamate alle API che abbiamo generato all’indirizzo 0xFFF (Figura 2).

Figura 2: Mappa di memoria per la MCU slave.

Figura 4: Mappa di memoria per la MCU slave

Tabella 1: Comandi e FnID per il bootloader secondario.

Tabella 1: Comandi e FnID per il bootloader secondario

Il codice potrebbe essere il seguente:

#define SBL_LOCATION 0xFF1 typedef void (*sbl_api)(uint32_t API_Code, uint8_t* pParam);

Servirà poi creare il puntatore, farlo puntare all’indirizzo giusto ed eseguire la chiamata, come di seguito:

sbl_api entry; 
entry = (sbl_api) (SBL_LOCATION); 
(entry)(API_Code, Params);

Per l’esempio proposto attraverso la nota applicativa di NXP, i parametri con cui invocare le API sono mostrati in Tabella 2.

Tabella 2: API per il bootloader secondario.Tabella 2: API per il bootloader secondario.

Tabella 2: API per il bootloader secondario

Ovviamente, per supportare la programmazione dall’interno dell’applicazione è necessario fornire al linker lo “scatter loading description file” che specifica la mappa di memoria per controllare il raggruppamento e il piazzamento delle immagini dei componenti. Per l’intento del progetto è fondamentale che la nuova immagine sia collocata all’indirizzo desiderato e non in un altro punto dove potrebbe corrompere il codice utilizzato per realizzare la programmazione. In Tabella 3 viene mostrato lo scatter loading description file per il bootloader secondario nel caso di implementazione con LPC11xx.

Tabella 3: Scatter loading description file per bootloader secondario(LPC11xx).

Tabella 3: Scatter loading description file per bootloader secondario(LPC11xx)

Il bootloader secondario risiede sul settore 0 della MCU slave. Viene diviso in due regioni, una per memorizzare il firmware stesso, l’altro per pubblicare le API. L’ultimo KB di ram interna che parte da 0x10001C00 per l’LPC11xx viene utilizzato per memorizzare 1KB di “dati firmware” inviati dalla MCU master quando esegue l’aggiornamento dell’applicazione utente. Lo scatter loading description file per l’applicazione utente è invece mostrato in Tabella 4.

Tabella 4: Scatter loading description file per l’applicazione utente(LPC11xx).

Tabella 4: Scatter loading description file per l’applicazione utente(LPC11xx)

L’applicazione utente risiede in flash dal settore 1 fino all’ultimo settore della MCU slave. Anche in questo caso le regioni sono 2, una per memorizzare il firmware e l’altra per memorizzare l’ID di versione del firmware. Anche in questo caso l’ultimo KB di RAM interna viene usato per memorizzare 1KB di firmware inviato dalla MCU master durante l’aggiornamento del bootloader secondario.

Figura 5: Diagramma di flusso per la funzione di aggiornamento dal bootloader secondario sulla MCU slave.

Figura 5: Diagramma di flusso per la funzione di aggiornamento dal bootloader secondario sulla MCU slave

Figura 6: Diagramma di flusso per la funzione di aggiornamento dall’applicativo utente sulla MCU slave.

Figura 6: Diagramma di flusso per la funzione di aggiornamento dall’applicativo utente sulla MCU slave

CONCLUSIONI

Questo semplice progetto di bootloader secondario via I2C vuole essere un esempio per aiutare chi lavora con le MCU delle famiglie LPC11xx e LPC17xx a prendere dimestichezza con il boot e con la suddivisione dell’area di memoria flash. Il codice che NXP mette a disposizione può essere un buon punto di partenza da personalizzare a seconda delle esigenze. Per scaricare il software, il link è il seguente: http://www.lpcware.com/content/nxpfile/an11258-i2c-secondary-boot-loader.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend