Antennino: l’Arduino con l’antenna – Carichiamo il bootloader

Avete conosciuto Antennino leggendo la prima puntata di questo articolo, nella quale abbiamo presentato il progetto e descritto l’hardware nei dettagli. Riprendiamo quindi da dove ci siamo fermati, ossia dalla programmazione del suo microcontrollore allo scopo di caricare il bootloader.
Questo perché, come tutte le board basate su architettura Arduino, Antennino prevede nell’ATmega un bootloader, che è un firmware eseguito nella fase di bootstrap (avvio) del microcontrollore e che permette di eseguire alcune operazioni preliminari, la più importante delle quali è gestire il caricamento dei nostri sketch tramite l‘IDE di Arduino impiegando un economico convertitore USB/seriale.
Esistono tanti bootloader per Arduino: potreste anche caricare quello classico che viene impiegato normalmente in Arduino Uno o anche scegliere quello del progetto Moteino realizzato da Felix Ruso, che riteniamo più interessante perché ha la possibilità di gestire l’aggiornamento wireless del firmware. Per fare questo, Ruso ha dovuto aggiungere del codice, quindi la dimensione del bootloader è passata da 512 byte a 1 kB, cosa che riduce lo spazio nella Flash memory utilizzabile dagli sketch; questa rinuncia viene, però, ripagata largamente dai benefici della programmazione da remoto. Ruso ha anche personalizzato la libreria del modulo RFM69.

Carichiamo il bootloader

Vediamo subito cosa ci serve per caricare il bootloader sul nostro Antennino: la programmazione richiede un programmatore con interfaccia ICSP (In Circuit Serial Programming, ossia che permette la programmazione del chip montato nel circuito dove viene impiegato) ed un software che lo gestisca; infatti non basta il semplice convertitore USB/seriale, che si usa quando nell’ATmega è già installato il bootloader.
Anche qui abbiamo diverse alternative, una delle quali è la possibilità di impiegare un semplice Arduino Uno come programmatore di altri Arduino, sul quale deve essere caricato uno sketch specifico e ci serve un cavo piatto a sei poli terminante con un connettore avente la piedinatura indicata in Fig. 1.

Fig. 1

 

Utilizziamo un programmatore commerciale disponibile in questo sito (Fig. 1).
Per quanto riguarda il software anche qui le possibilità sono molteplici. Alcuni utilizzano un software della Atmel (ora Microchip) che si chiama Atmel Studio. Ma è un software pachidermico (soprattutto nelle ultime versioni) e se la vostra necessità è solo quella di caricare il bootloader su Antennino vi consigliamo vivamente di utilizzare un software molto più leggero. La scelta cade forzatamente su Avrdude, un software open source che deve essere impiegato a riga di comando. Naturalmente usarlo a riga di comando non è il massimo della semplicità, quindi quello che vi proponiamo di utilizzare è BitBurner. Il cuore di questo programma è sempre Avrdude, però dotato di GUI (interfaccia grafica) che ne agevola enormemente l’utilizzo. Il programma è essenziale: si presenta con una sola interfaccia con quattro tab con cui è possibile fare tutto. Ricordatevi che il programmatore ICSP deve essere settato per lavorare a 3,3 V. Di seguito analizziamo i passi della programmazione con BitBurner.

Collegare il programmatore e individuare il micro

Per evitare conflitti con il bus SPI, dobbiamo attivare il resistore di pull-up collegato al pin di Chip-Select sul modulo RFM69 chiudendo il ponticello J9. Rimuoviamo (se presenti) le batterie da Antennino, colleghiamo il programmatore ISP alla porta USB del nostro PC, inseriamo il connettore ICSP femmina del programmatore alla porta ICSP maschio di Antennino facendo attenzione al verso di inserimento, quindi mandiamo in esecuzione BitBurner.
Selezioniamo il primo TAB (AVRdude) e nella schermata che si apre (Fig. 2) selezioniamo il nostro Chip (ATmega328P) dalla combo AVR Device; dalla combo Programmer, scegliamo il nostro programmatore (ad esempio Atmel AVR ISP mkII) e la porta di comunicazione (USB).

Fig. 2

 

Ora viene la parte più delicata, quindi seguite passo-passo le varie fasi. Andiamo sul Tab “AVR Fuses” di Fig. 3 e clicchiamo sul pulsante “Read”: con questa operazione andremo a leggere la configurazione attuale (predefinita) dei vari Fuse Bit del nostro microcontrollore. Ci sono moltissimi parametri, ma non fatevi spaventare. Poi spiegheremo nel dettaglio le varie opzioni.
Se tutto funziona come previsto dovrebbe apparire un messaggio nel box di log, dove, a conferma che bitBurner utilizzi AVRDUDE, viene visualizzato lo script di AVRDUDE che viene invocato ed il relativo risultato. Se viene riportato “Fuses OK” “Read Fuses Successful” significa che il nostro chip (Device signature 0x1e950f) è stato individuato in modo corretto.

 

Fig. 3

Programmare i Fuse Bit

I fuse bit sono particolari registri del microcontrollore che permettono di configurare il comportamento di alcuni aspetti dello stesso. Per esempio consentono di definire quale sorgente deve essere utilizzata per il clock di sistema: l’oscillatore interno, una sorgente di clock esterna, oppure un quarzo o risuonatore esterno, la porzione di memoria riservata al bootloader, il livello minimo di tensione di alimentazione che permette di fare partire il micro ed altre impostazioni essenziali per il corretto funzionamento del microcontrollore.
Questa fase è molto delicata perché se sbagliamo a settare i valori dei Fuse Bit potremmo trovarci con un ATmega328P che non ne vorrà più sapere di partire; ad onor del vero esiste una procedura di sblocco ma richiede del lavoro supplementare.
Un errore molto comune è quello di impostare il micro “dicendogli” di utilizzare come sorgente di clock una sorgente esterna e quindi il chip all’avvio si attende che su un certo pin sia presente un clock con una certa frequenza; e se non gli forniamo tale segnale, il nostro caro ATmega328p non si scomoderà proprio a partire.
Bene, fatta questa piccola premessa utile a rendervi consapevoli della delicatezza e importanza dei fuse bit, mettiamoci al lavoro.
I fuse sono suddivisi in quattro blocchi: “LOW FUSE”, “HIGH FUSE”, “EXTENDED FUSE”, “LOCK BIT”. Questi registri sono detti Fuse, “Fusibili”, anche se in pratica non c’è nulla che venga bruciato materialmente nella memoria del microcontrollore: sono detti così perché essi sono salvati nella Flash, quindi nella memoria non volatile del microcontrollore: essi perciò non perdono il loro valore quando viene tolta l’alimentazione. In pratica si tratta di quarto registri da un Byte (8bit) ciascuno. Per definirne lo stato di questi registri possiamo usare la notazione binaria oppure quella esadecimale. Quando diciamo o ci riferiamo al fatto che un valore sia settato/non settato, programmato/non programmato, bisogna prestare attenzione al fatto che 1 significa non settato (non programmato) mentre 0 significa settato (programmato) quindi, in un certo senso la logica è invertita. Questo modo di operare apparentemente illogico trae origine dall’architettura interna delle memorie Flash, le cui celle dopo che sono state cancellate (formattate) hanno tutte il valore 1. Questo spiega la strana logica usata dai fuse per memorizzare i valori.

ANTENNINO - scheda multiruolo Arduino-RFANTENNINO - scheda multiruolo Arduino-RF

Low Fuse

Iniziamo con una carrellata sui Low Fuse, riportati sinteticamente nella Tabella 1, e con la loro impostazione.

Tabella 1

 

CHDIV8 (Clock Divide): in alcuni casi si rende necessario abbassare il clock di sistema dividendone il valore per 8. Per esempio se scegliessimo come sorgente di clock quella interna a 8MHz e il flag CKOUT fosse settato, avremmo un clock di sistema a 1MHz. Il valore predefinito è CKOUT=0 (settato).
CKOUT (Clock Out): questa impostazione permette di fare apparire il segnale di clock di sistema sul Pin PB0 permettendo di pilotare altri circuiti. Il valore predefinito è CKOUT=1 (non settato).
SUT1/SUT0 (Start Up Time): questi due fuse impostano il tempo di avvio del microcontrollore dopo un reset oppure dopo l’uscita da una condizione di sleep (risparmio energetico). Quando viene fornita alimentazione ad un circuito oscillatore, questo necessita di un certo periodo di tempo nonché di un certo numero di oscillazioni prima che il clock fornito sia stabile ed il suo valore corrispondente a quello nominale. Analogamente, il ripristino da una condizione di stand-by, introduce le stesse problematiche perché il microcontrollore richiede un certo tempo e alcuni numeri di cicli di clock per riportare a piena operatività tutte le periferiche interne. Le combinazioni dei due fuse SUT1 e SUT0 determinano l’intervallo da attendere prima che il processo di avvio/ripresa si possa considerare completato (in forma di un’attesa in ms e di un’attesa in cicli di clock): più tale intervallo è lungo, più tempo quindi viene concesso al microcontrollore per avviarsi/risvegliarsi, più saremo sicuri che il processo verrà compiuto correttamente. In alcuni casi di utilizzo in cui si evidenzia l’esigenza di un avvio/risveglio più rapido, si può ridurre il tempo a disposizione al costo di una eventuale incapacità di completare l’operazione. Tale incapacità può manifestarsi occasionalmente se i valori di avvio sono brevi (valori 0-1) ma può capitare anche che il microcontrollore non sia più in grado di avviarsi se si scelgono i tempi più brevi in assoluto (valori 0-0). I tempi impostati da questi fuse vengono sommati al ritardo aggiuntivo introdotto tramite il fuse CKSEL0. I valori predefiniti sono SUT1=1 e SUT0=0 (14 ck + 65 ms) così da fornire il maggior tempo possibile al microcontrollore.

CKSEL (Clock Sources/Clock Selection)

I fuse CKSEL3, CKSEL2, CKSEL1 impostano il tipo di fonte per il segnale di clock, mentre il fuse CKSEL0 introduce un ulteriore tempo di ritardo per l’avvio/risveglio del microcontrollore, tempo che viene sommato a quello ottenuto mediante i fuse SUT1, SUT0. Le fonti di clock selezionabili sono:
oscillatore interno a 8 MHz; oscillatore interno a 128 kHz (utilizzato solo per determinate applicazioni e tramite programmatori particolari, non compatibile con l’ambiente di Arduino); fonte di clock esterna (esempio: un circuito oscillatore); quarzo o risonatore ceramico esterno (con diversi campi di frequenza). Le combinazioni sono molteplici: vengono presi in considerazione diversi parametri, tra cui il consumo del quarzo e la sua frequenza, tutte riportate sulla scheda tecnica del microcontrollore.
Nota: nel programma BitBurner, per agevolare l’utente la configurazione relativa alla frequenza del clock e ai ritardi di startup si selezionano dalla combo box SUT_CKSEL in cui sono elencate tutte le possibili combinazioni.

High Fuse

Passiamo adesso all’impostazione degli High Fuse, che sono descritti nella Tabella 2.

Tabella 2

RSTDISBL (External reset disable): il pin PC6 è deputato al reset del micro. Portando tale pin a massa si ottiene il reset de microcontrollore e si può reinizializzare il funzionamento se qualche cosa va storto nel codice. In qualche caso particolare può essere necessario usare il pin PC6 come un normale Pin di I/0 e quindi in questa eventualità il Flag RSTDISBL deve essere settato (=0). Attenzione però che con questa impostazione si perde la possibilità di riprogrammare il chip. Un motivo per disabilitare il reset potrebbe anche essere la necessità di impedire la riprogrammazione o lo scaricamento del firmware per ragioni di copyright. Valore predefinito (RSTDISBL=1) non settato.
DWEN (debugWIRE enable): abilitando questo fuse si accede alla possibilità di eseguire quella che viene indicata con on-chip debuggin, ma è richiesto un particolare programmatore (tipo AVR Dragon). Quindi anche questo Flag non deve essere alterato rispetto al valore predefinito altrimenti si perde il controllo sulla possibilità di riprogrammare il chip.
SPIEN (Enable Serial programming and Data Downloading): come sappiamo, i chip ATmega possono essere programmati tramite l’interfaccia ISP. Se disabilitiamo questa opzione non saremo più in grado di farlo e quindi è necessario lasciare questa impostazione settata. Il valore predefinito è SPIEN=0 (settato).
WDTON (Watchdog Timer Always On): il WatchDog è in linea di principio un timer che provoca il reset del controllore se non riceve un segnale di conferma del funzionamento corretto del chip entro uno specifico intervallo di tempo. Il Watchdog può inoltre essere settato via software. Il valore predefinito WDTON =1 (non settato).
EESAVE (Preserve EEPROM memory): quando i chip Atmega sono programmati la memoria eeprom è cancellata come lo è la memoria destinata ad ospitare il codice. Il fuse EESAVE può essere usato per notificare al chip di preservare la EEPROM. Questo può essere utile quando si vuole aggiornare il firmware ma si desidera mantenere le configurazioni memorizzate nella EEPROM. Siccome l’impostazione predefinita è EESAVE =0, la EEPROM viene cancellata durante l’aggiornamento del firmware.
BOOTSZ1 & BOOTSZ0 (Boot loader Size): il bootloader è utilizzato per inizializzare i dispositivi e verificare le comunicazioni esterne. In generale, Arduino usa un bootloader per comunicare con un PC e capire se deve caricare uno sketch. Il bootloader è memorizzato nella stessa memoria in cui è caricato il nostro sketch e siccome il bootloader può avere diverse dimensioni, noi possiamo e dobbiamo dire al chip quanto spazio riservare per il bootloader. Notate che le dimensioni specificate sono in word (1 word=2 byte) quindi 512 word=1.024 byte.
BOOTRST Select reset vector: quando questo fuse è settato, nella fase di reset, l’esecuzione del codice inizierà dalla posizione iniziale del bootloader altrimenti se il fuse non è settato il programma inizierà dalla locazione di memoria di partenza del programma 0x0000. Quindi anche se abbiamo configurato i fuse BOOTSZ1 & BOOTSZ0 non settando il fuse BOOTRST la presenza del bootloader verrà ignorata. Il valore predefinito è BOOTRST=1 (non settato).

Tabella 3

Extended Fuse

Procediamo con gli Extended Fuse, riportati nella Tabella 4

Tabella 4

 

e vediamo che gli unici significativi sono i BODLEVEL0, 1 e 2, meglio descritti nella Tabella 5.

Tabella 5

 

Questi Fuse (sul chip Atmega 328p) sono utilizzati solamente per settare il livello del BOD (Brown-Out Detector). Vediamo di cosa si tratta: i chip ATmega possono diventare instabili o inaffidabili quando la tensione di alimentazione non è sufficiente. Per esempio un 328P può lavorare in modo corretto a 16MHz se la sua tensione di alimentazione raggiunge almeno i 4V. Per valori di tensione sotto i 4V il chip ha una alta probabilità di comportarsi in modo imprevedibile. Per assicurarsi che il chip abbia una tensione adeguata per svolgere il suo lavoro, viene in aiuto il registro relativo ai BODLEVEL con il quale è appunto possibile specificare la tensione minima di lavoro del chip. La tensione viene monitorata da un blocco operativo interno al chip stesso. Se la tensione scende sotto il valore prestabilito il chip viene resettato. Il valore predefinito è BODLEVEL2, BODLEVEL1, BODLEVEL0 (=1 non settato). A causa del fatto che alcuni bit non sono utilizzati, il loro valore può risultare “fluttuante” per cui dopo la programmazione del fuse esteso la rilettura del registro può dare un errore di verifica del valore scritto in memoria. In questo caso si consiglia di considerare solo il valore dei primi 3 bit e di impostare a 0 i bit dal 3° al 7°.

Lock Bit

Le impostazioni di questo registro permettono di disabilitare la possibilità di leggere o scrivere nella memoria ed impedirne quindi la riprogrammazione. Questo registro è molto delicato e vi consigliamo di lasciarne le impostazioni inalterate (0x3F) altrimenti correte il serio rischio di ritrovarvi con chip completamente bloccato.

I valori predefiniti

Ciò detto, diamo uno sguardo all’impostazione predefinita dei Fuse Bit nei microcontrollori ATmega 328/328P vergini, ovvero come sono impostati in fabbrica. La Tabella 6 riporta le impostazioni predefinite per i Low Fuse, la Tabella 7 riguarda gli High Fuse e la Tabella 8 riporta i valori predefiniti degli Extended Fuse. Su BitBurner Individuiamo la sezione “Fuses & Lock bits” e clicchiamo sui due pulsanti Read. Questa operazione permette di acquisire i valori presenti in questi “registi” e probabilmente non saranno quelli che servono a noi. Andiamo quindi a scrivere i valori seguenti: L:0xDE H:0xDC E:0x05 LB:0x3F e clicchiamo sui rispettivi pulsanti Write. Nell’Area di log sottostante dovremmo avere dei messaggi. Al termine proviamo a verificare i dati scritti e clicchiamo nuovamente su Read: se tutto è andato a buon fine dovremmo ritrovare i valori che abbiamo inserito noi e nessun messaggio di errore nella finestra di log.

 

Tabella 6

Tabella 7

Tabella 8

Scriviamo il Bootloader sul chip

Scarichiamo i file dal repository GitHub cliccando sul pulsante verde “Clone or Download” come visibile in Fig. 4.

Fig. 4

Scarichiamo lo zip DualOptiboot-master.zip, quindi scompattiamolo in una cartella di appoggio: ad esempio C:\TMP\.

Quello che ci interessa è il file che si trova in questo percorso:

C:\TMP\DualOptiboot-master\DualOptiboot_V5.0_atmega328_BlinkD9.hex

Il file indicato è il bootloader adatto al nostro microcontrollore ATmega328p, che prevede il LED di notifica settato sul pin di I/O D9.

Fig. 5

Su BitBurner individuiamo il Tab con l’indicazione “AVR Memories” (Fig. 5), selezioniamo il file del bootloader da caricare, poi nella combo box “Memory Programmer” selezioniamo “Flash Only” e clicchiamo sul pulsante “Write”.
A questo punto nella finestra di Log dovremmo veder apparire una barra di progressione che indica la percentuale di caricamento ed al termine dell’operazione, un messaggio rassicurante che ci indica che il caricamento è andato a buon fine.
Se tutto va così, siamo a posto: il nostro Antennino ora ha un cuore pulsante ed è pronto ad ospitare i nostri Sketch.

Conclusioni

Bene, si chiude qui questa seconda ed ultima puntata di Antennino; abbiamo spiegato che cos’è il bootloader e tutte le sue particolarità, scendendo in ogni dettaglio, quindi siamo passati alla scelta del bootloader, del programma con cui caricarlo nel microcontrollore di Antennino e alla procedura di installazione per fare in modo che Antennino sia gestibile dall’IDE di Arduino attraverso la connessione USB del computer. Ora che avete il bootloader potrete installare i vostri sketch.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Menu