Arduino / Programmazione · 2 ottobre 2013 3

I bit “FUSE”

FusibiliI microcontrollori Atmel possiedono al loro interno alcuni registri che servono a modificare alcune caratteristiche particolari del microcontrollore, ad esempio le opzioni riguardanti il clock, l’area di memoria da riservare al bootloader, l’attivazione di circuiti interni quali il WatchDog (WD) o il Brown-out Detector (BOD), l’abilitazione del pin del reset ed altro ancora. Questi registri sono detti Fuse, “Fusibili”, anche se non c’è nulla che viene 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. Sono inoltre modificabili solo ricorrendo ad un programmatore esterno, per cui una volta impostati non possono essere alterati dal software o da eventi accidentali.

A seconda del tipo di microcontrollore, i fuse sono generalmente 2 o 3 registri ad 8 bit memorizzati in altrettanti byte di memoria (non tutti i bit di questi registri sono utilizzati) e denominati: Low Fuse (Fuse “basso”), High Fuse (Fuse “alto”) e Extended Fuse (Fuse “esteso”). Quest’ultimo registro è presente solo nei chip Atmel più recenti.

Qui di seguito analizzeremo i fuse riguardanti il microcontrollore Atmega328P, anche se la maggior parte delle informazioni riportate possono essere adattate anche ad altri chip.

[notice]IMPORTANTE: quando si modificano i fuse bisogna tenere a mente che per attivare una certa funzione bisogna porre a 0 (zero) il relativo bit mentre quando la si vuole disattivare bisogna porre ad 1 (uno) il relativo bit.[/notice]

[important]Approfondimento: questo modo di operare apparentemente illogico trae origine dall’architettura interna delle memorie Flash: ogni bit è rappresentato da una cella di memoria costituita da un MOSFET (transistor ad effetto di campo) con 2 gate anziché 1: il primo gate è detto Control Gate (CG) ed è diviso dai sottostanti drain e source da un altro gate, detto Floating Gate (FG), isolato dai suddetti mediante l’uso di 2 strati di ossido di silicio. L’FG è una specie di condensatore, è cioè capace di mantenere indefinitamente l’eventuale carica elettrica che gli viene fornita. Tutti i CG che costituiscono una word della memoria Flash sono collegati ad una stessa linea elettrica. Quando l’FG non è carico, il MOSFET non conduce e la logica di gestione della memoria legge (mediante una cella di carico) questo stato come valore 1. Inserendo una carica elettrica nell’FG, si porta il MOSFET in conduzione e la logica di gestione legge il valore 0. Per cancellare la cella viene utilizzata una tensione a 12/13V con la quale viene “estratta” la carica dal FG, riportando il MOSFET al suo stato inibito (valore 1). Come si evince, la non conduzione del MOSFET è quindi uno stato elettricamente più stabile dell’altro ed è per questo motivo che le celle delle memorie Flash dopo che sono state cancellate (formattate) hanno tutte il valore 1. Questo spiega la strana logica usata dai fuse per memorizzare i valori.[/important]

Low Fuse / Fuse basso

Bit

Nome

Descrizione

Valore di

default

Valore nell’Arduino

7

CKDIV8

Divide il clock per 8

0

0

6

CKOUT

Fornisce il clock sul piedino CLKO (sul 328 è il pin PB0)

1

0

5

SUT1

Imposta il tempo di avvio del microcontrollore

1

0

4

SUT0

Imposta il tempo di avvio del microcontrollore

0

0

3

CKSEL3

Seleziona la fonte del clock

0

0

2

CKSEL2

Seleziona la fonte del clock

0

0

1

CKSEL1

Seleziona la fonte del clock

1

0

0

CKSEL0

Seleziona la fonte del clock

0

0

Analizziamo le varie voci:

  • CKDIV8:questo fuse divide per 8 il segnale fornito dalla sorgente di clock prescelta. Ad esempio, se si sceglie di utilizzare su un Atmega328P standalone l’oscillatore interno ad 8 MHz, impostando il fuse CKDIV8 il clock di sistema effettivo sarà 1 MHz (8 MHz/8=1 MHz).
  • CKOUT:questo fuse permette di fornire sul pin CLKO esterno del microcontrollore il clock di sistema. Sull’Atmega328 tale pin corrisponde al piedino PB0 (pin digitale 8 dell’Arduino).
  • SUT1..0:questi 2 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. Non di meno, l’uscita da una condizione di stand-by, comporta le stesse problematiche perché il microcontrollore necessita di un certo tempo e di alcuni numeri di cicli di clock per riportare a piena operatività tutte le periferiche interne. I fuse SUT1..0 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ù il processo verrà compiuto correttamente. I valori di default sono “1” e “0”, rispettivamente per SUT1 e SUT0, così da fornire il maggior tempo possibile al microcontrollore. In utilizzi in cui si necessiti 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.
  • CKSEL3..0:I fuse CKSEL3..1 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..0. 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.

High Fuse / Fuse alto

Bit

Nome

Descrizione

Valore di

default

Valore nell’Arduino

7

RSTDISBL

Disabilita il reset esterno

1

1

6

DWEN

Abilita le funzionalità di debugWIRE

1

1

5

SPIEN

Abilita la comunicazione seriale SPI

0

0

4

WDTON

Rende attivo fisso il timer del WatchDog

1

1

3

EESAVE

Protegge la EEPROM interna dalle cancellature del chip

1

1

2

BOOTSZ1

Seleziona la dimensione da riservare al bootloader

0

1

1

BOOTSZ0

Seleziona la dimensione da riservare al bootloader

0

1

0

BOOTRST

Imposta il vettore di reset

1

0

Analizziamo le varie voci:

  • RSTDISBL:ogni microcontrollore ha un piedino particolare che non funziona come pin di input/output ma è collegato al circuito di reset interno. Dando un segnale basso su tale pin si resetta il microcontrollore. Impostando questo fuse si scollega il circuito di reset e si rende questo pin un normale piedino (anche se con una impedenza interna maggiore): ciò può risultare utile nel caso si necessiti di un ulteriore pin di I/O. Attenzione, però, perché la disattivazione del reset esterno rende impossibile riprogrammare il microcontrollore con le normali tecniche come la tecnica ISP. Per riattivare il reset esterno serve un programmatore ad alta tensione.
  • DWEN:questo fuse attiva la comunicazione seriale debugWIRE, un protocollo di debug alternativo a JTAG sviluppato da Atmel e supportato da alcuni programmatori della società: AVR Dragon, AVR JTAGICE mkII, AVR JTAGICE 3 e AVR One.
  • SPIEN:il fuse SPIEN attiva la comunicazione SPI. Disattivando tale fuse il microcontrollore non può più comunicare con altre periferiche compatibili SPI, quindi non accetta neanche più l’invio di dati con la tecnica ISP, che sfrutta appunto la comunicazione SPI.
  • WDTON:l’Atmega328P (come molti altri microcontrollori) contiene un contatore interno denominato WatchDog Timer (WatchDog letteralmente significa “cane da guardia”) che serve a resettare il chip. Quando viene attivato il WatchDog, se l’utente non resetta il valore del contatore prima che questo raggiunga il valore massimo, il circuito invierà un segnale di reset riavviando il microcontrollore. Tale circuito può risultare utile nel caso di applicazioni critiche in cui bisogna evitare che il codice si blocchi durante l’esecuzione. Il WatchDog può essere attivato o disattivato via software. Impostando tale fuse, il circuito del WatchDog viene attivato permanentemente.
  • EESAVE:i microcontrollori Atmel contengono 3 tipi di memoria differente: Flash, SRAM e EEPROM. La prima contiene il codice dell’utente, la seconda le variabili create dal programma e la terza può essere utilizzata per salvare dati che non devono essere persi nel caso di assenza dell’alimentazione. Tralasciando la SRAM, che è una memoria di servizio, la Flash e la EEPROM possono essere lette e scritte in maniera indipendente, senza che la scrittura di una cancelli il contenuto dell’altra. Esiste però una opzione di avrdude (“-e”) che esegue la cancellazione totale di tutte le memorie non volatili del microcontrollore (“chip erase”). Per preservare il contenuto della EEPROM durante i successivi cicli di cancellatura delle memorie del chip, si può attivare questo fuse.
  • BOOTSZ1..0:questi fuse sono utilizzati per riservare una parte della memoria Flash del microcontrollore destinandola ad accogliere un programma separato. Normalmente la memoria Flash è messa completamente a disposizione del programma dell’utente, che viene avviato non appena viene data alimentazione al microcontrollore. In determinate applicazioni, vedi anche l’Arduino, si ha la necessità di far eseguire un piccolo programma di avvio detto bootloader prima di passare all’esecuzione del codice principale: nel caso dell’Arduino, ad esempio, il bootloader controlla se l’IDE sta spedendo un nuovo sketch sulla seriale e, in caso affermativo, provvede a scriverlo nella memoria Flash sostituendo quello precedentemente memorizzato. I fuse BOOTSZ1..0 riservano a tale programma nella parte alta della memoria un’area di Flash non sovrascrivibile normalmente, la cui dimensione è determinata dal valore dei fuse e dipende dalla quantità di Flash stessa del microcontrollore. Nel caso dell’Atmega328P la dimensione dell’area per il bootloader può essere di: 512 byte (valori “1” e “1” per BOOTSZ1 e BOOTSZ0), 1024 byte (valori “1” e “0”), 2048 byte (valori “0” e “1”) o 4096 byte (valori “0” e “0”). L’Arduino riserva per le schede UNO un quantitativo di 512 byte: le precedenti schede Duemilanove riservavano un quantitativo di 2048 byte. Attenzione al fatto che sul datasheet si leggono quantitativi differenti, questo perché la memoria Flash è a 16 bit e le dimensioni sulla scheda tecnica del microcontrollore sono indicate in word (2 byte), quindi per 512 byte di area viene indicato un valore di 256 word.
  • BOOTRST:normalmente all’avvio il microcontrollore inizia ad eseguire il programma a partire dalla prima locazione di memoria (indirizzo esadecimale $0000). Questa è l’impostazione predefinita (fuse impostato a 1). Quando si attiva il fuse (valore 0), il microcontrollore inizia l’esecuzione a partire dalla prima locazione di memoria dell’area riservata per il bootloader, indirizzo che dipende dal quantitativo di memoria riservata al bootloader stesso tramite i fuse BOOTSZ1..0. Nel caso dell’Atmega328P, l’indirizzo della prima locazione dell’area riservata è: $3F00, $3E00, $3C00 e $3800, rispettivamente per dimensioni di 512/1024/2048/4096 byte. Attenzione: anche in questo caso l’indirizzo di inizio dell’area riservata al bootloader tiene conto del fatto che la memoria è organizzata word di 16 bit per cui l’indirizzo $3F00 corrisponde al 32256° byte dato che $3F00=16128 word=32256 byte. Difatti l’Atmega328P ha 32 kB di Flash, quindi 32768 byte di memoria, per cui se si sottrae dal quantitativo complessivo di Flash, 32768 byte, la dimensione del bootloader della UNO, 512 byte, si ottiene proprio 32256, che è lo spazio a disposizione per gli sketch dell’utente nonché l’indirizzo in byte della prima locazione del bootloader.

Extended Fuse / Fuse esteso

Bit

Nome

Descrizione

Valore di

default

Valore nell’Arduino

7

Non usato

6

Non usato

5

Non usato

4

Non usato

3

Non usato

2

BODLEVEL2

Imposta il livello del Brown-Out Detector

1

1

1

BODLEVEL1

Imposta il livello del Brown-Out Detector

1

0

0

BODLEVEL0

Imposta il livello del Brown-Out Detector

1

1

Analizziamo le vari voci:

  • bit 7..3: non utilizzati
  • BODLEVEL2..1:questi fuse attivano il cosiddetto Brown-Out Detector (BOD), un circuito preposto al monitoraggio della tensione di alimentazione del microcontrollore. Il microcontrollore può operare ad una tensione variabile che, nel caso dell’Atmega328P, può oscillare da un minimo di 1,8V ad un massimo di 5,5V. Anche la frequenza operativa è variabile, potendo oscillare fra 1 e 20 MHz. Esiste un problema: la stabilità. Più la frequenza sale di valore e più la tensione deve stare sopra ad una certa soglia per garantire la stabilità di funzionamento del microcontrollore. La scheda tecnica di ogni microcontrollore riporta diversi grafici da cui si possono estrapolare i valori minimi di tensione per ogni frequenza. Scendere sotto tale soglia può comportare manlfunzionamenti del microcontrollore: per ovviare a questo problema, si può attivare il circuito di BOD, il quale misura costantemente la tensione di alimentazione con il valore impostato. Se la tensione scende sotto tale soglia, il circuito resetta il microcontrollore mantenendo lo stato di reset finché la tensione non torna sopra al valore di soglia. Ad esempio, nell’Arduino il microcontrollore è impostato a 16 MHz: a tale frequenza, necessita di una tensione minima che si aggira intorno ai 4,5V. Per questo motivo, l’Arduino imposta un livello di BOD di 4,3V. I possibili libelli di BOD sono: 4,3 V (fuse “1-0-0” rispettivamente per BODLEVEL2..0), 2,7 V (fuse “1-0-1”) e 1,8 V (fuse “1-1-0”).

Attenzione:

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°. Ad esempio: nel caso dell’Arduino, si usi per il fuse esteso il valore $05.