Uno degli argomenti che fino ad ora non ho ancora affrontato è quello della memorizzazione dei dati in maniera permanente. Molte applicazioni necessitano infatti di mantenere telune informazioni anche nel caso in cui l'alimentazione viene a mancare. Si pensi ad esempio ad un contacicli nelle macchine di produzione oppure alle password di accesso ai sistemi o anche il numero IP di un host. Anche con i PICMicro è possibile
Facciamo un breve excursus. I sistemi informatici si basano principalmente su questo tipo di memorie:
Rientrano in questa categoria principalmente le memorie RAM, acronimo di Random Access Memory. La RAM è costituita da una serie di celle in grado di memorizzare le informazioni solamente se tali celle vengono mantenute alimentate. Mediante una linea bus indirizzi e una linea bus dati è possibile accedere alla singola cella e leggerne e/o scriverne il valore. Le celle sono assimilabili a condensatori il cui valore di carica determina lo stato di un bit. Le memorie RAM di tipo dinamico (note anche come DRAM) dispongono anche di un pin di controllo detto di refresh che serve a rinfescare il valore di carica delle celle/condensatori. Altre memorie, come le FerroRAM mantengono il dato in memoria senza dover avere il meccanismo di refresh. Altri bit di controllo, come i comandi di lettura (Read) e scrittura (Write) permettono alla CPU di accedere alla memoria.
Ecco come si presentano alcune memorie RAM in uso sui personal computer (fonte Wikipedia):
Questo tipo di memorie in passato sono state impiegate per la memorizzazione di programmi (o parti di essi) che non avevano motivo di venire modificate. I primi home-computer disponevano infatti di una ROM, acronimo di Read-Only Memory, nel quale veniva posto ad esempio un interprete BASIC oppure un "rozzo" sistema operativo. Oggi le ROM, nella loro eccezione esatta, non esistono (quasi) più. Anche i microcontrollori, da oltre dieci anni, hanno abbandonato questa tecnologia e utilizzano, per la memorizzazione del firmware, memorie non volatili di tipo FLASH.
Esistono poi memorie non volatili programmabili come le EPROM (Electrically Programmable ROM) e le EEPROM (Electrically Eraseble Programmable ROM). Le prime ormai sono quasi del tutto sparite, mentre le seconde, pur in tecnologia FLASH e non più CMOS, trovano ampio spazio, anche nel mondo dei microcontrollori!
In questa immagine alcune EPROM, memorie che venogono programmate per via elettrica e cancellate con raggi U.V.
Ed ecco un programmatore multiplo, che viene utilizzato per caricare il firmware in modo contemporaneo su 10 EPROM, leggendone una campione. Programmatori analoghi vengono invece connessi ad un computer per poter caricare il firmware presente su HD.
Tra questo tipo di memoria si annoverano i sistemi di memorizzazione di grosse quantità di dati. Il primo pensiero è rivolto alle unità a disco, come gli hard-disk. In passato i dischi flessibili denominati floppy disk rappresentavano l'evoluzione miniaturizzata dei sistemi di memorizzazione di massa che, fino a quell'epoca, erano rappresentati da grosse bobine di nastro magnetico. Il disco "floppy" o "hard" ha segnato il passo: ha permesso infatti l'accesso rapido e indirizzato ai dati memorizzati, cosa che non era possibile con i nastri magnetici, essendo essi dispositivi con memorizzazione dati di tipo sequenziale.
Oggi i sistemi di memorizzazione di massa si sono notevolmente ampliati e in pochi centimetri cubi di volume possiamo immagazzinare quantità di dati impressionanti, eliminando anche le parti in movimento. L'evoluzione dell'hard disk è infatti il dispositivo a stato solido che tutti conosciamo sotto le sembianze di "chiavette USB" e schede di memoria nei formati e nelle sigle che si leggono ovunque: MMC, SD, CompactFLASH, ecc.
Un ulteriore passo in avanti è rappresentato dal cloud-computing che, nella sua eccezione relativa alla memorizzazione dei dati, svincola gli utenti dal possedere un proprio dispositivo di memorizzazione, demandando questa incombenza a grossi server ai quali il nostro terminale si va a collegare, mediante una connessione in rete.
Tanto per rendere l'idea di come si sono evoluti i sistemi di memorizzazione nel giro di una ventina di anni, ecco una rassegna di dispositivi: si va dal disco di alluminio magnetizzato di un HD da 14 pollici fino alla piccolissima microSD. Le dimensioni dei dispositivi sono inversamente proporzionali alla capacità di memorizzazione.
È giunto il momento di analizzare cosa contiene, in termini di memoria, un microcontrollore. La prima cosa da fare è scegliere un PICMicro ed aprire il suo datasheet. Ed ecco come si presenta l'architettura interna di un PIC16F819. In rosso ho evidenziato le tre memorie RAM, Flash ed EEPROM.
Per avere un'idea delle dimensioni di ciascuna delle memorie, ecco qui un paio di tabelle che dovrebbero aiutare a decifrare.
Dato che il datasheet si riferisce tanto al PIC16F818 quanto al PIC16F819, in rosso ho evidenziato le caratterische del PIC16F819. Riassumendo, ecco le caratteristiche del PIC16F819:
Il fatto che sia indicato un "X14" piuttosto che un "X8", significa che lo spazio di indirizzamento è a 14 o a 8 bit, in funzione del tipo di accesso. Ma questa è un'altra storia, di cui, in parte, racconterò in queste pagine.
Come detto la EEPROM è una ROM cancellabile e programmabile elettricamente, il che significa che con opportuni valori di tensione, è possibile scrivere e/o cancellare dati. La EEPROM è sì una memoria non volatile ed è utile per conservare variabili ritentive, il cui valore deve essere conservato anche in mancanza di energia elettrica, fornita da reti elettriche e/o da batterie tampone, ma dato che non è una memoria ad accesso veloce come la RAM, non viene utilizzata per salvare le variabili di programma!
Dato che la EEPROM interna al PIC è sostanzialmente una memoria FLASH, per la gestione di tale memoria il PIC mette a disposizione un certo numero di registri, i quali permettono tanto l'accesso alla EEPROM quanto alla Program Memory! Sì, alcuni PIC sono programmabili dallo stesso firmware, operazione che ad esempio svolgono i bootloader. C'è però una sostanziale differenza tra la prorgammazione "ordinaria", quella che avviene con modalità ICSP (In Circuit Serial Programming) e l'accesso alla Program Memory da parte del firmware. Ora, non è questo l'argomento dell'articolo ma è necessario averne accennato in quanto, come si vedrà poco più avanti, le impostazioni dei registri possono infatti permettere l'accesso alla Program Memory o alla EEPROM.
Lo schema generale dell'accesso alla EEPROM da parte del PIC è il seguente:
I registri coinvolti nella gestione di Program Memory ed EEPROM sono i seguenti:
Fatta eccezione per EEDATH ed EEADRH, i rimanenti registri sono tutti coinvolti nelle operazioni di lettura e scrittura della EEPROM. Questi sono i ruoli giocati dai singoli registri:
Il registro EECON1 è così composto
Il significato dei bit è il seguente:
bit | nome | significato |
0 | RD | Se posto a 1, avvia una lettura |
1 | WR | Se posto a 1, avvia una scrittura |
2 | WREN |
Se posto a 1, abilita i cicli di scrittura, altrimenti li inibisce |
3 | WRERR |
Bit di sola lettura: se è posto a 1, significa che è avvenuto un errore durante le operazioni di scrittura |
4 | FREE |
Bit per la cancellazione di una cella all'indirizzo composto EEADRH + EEADR (accesso alla Program Memory) |
5 | --- | Non usato |
6 | --- | Non usato |
7 | EEPGD |
Se posto a 1 permette l'accesso alla program memory, viceversa si accede alla EEPROM |
La lettura dei dati dalla EEPROM è senz'altro un'operazione molto semplice. Con quattro passi si arriva dalla richiesta al dato:
In linguaggio C, tutto questo si traduce in poche righe:
unsigned char read_eeprom(unsigned char eeprom_address)
{
unsigned char ee_data;
EEADR = eeprom_address; // EEPROM address stored in the byte register
EEPGD = 0; // Access to EEPROM memory
RD = 1; // Start EEPROM reading
ee_data = EEDATA; // Read the EEDATA
return ee_data;
}
Per chi preferisce l'assembly, è sufficiente copiare le righe che il datasheet mette a disposizione ed il gioco è fatto:
BANKSEL EEADR ; Select Bank of EEADR
MOVF ADDR, W ;
MOVWF EEADR ; Data Memory Address to read
BANKSEL EECON1 ; Select Bank of EECON1
BCF EECON1, EEPGD ; Point to Data memory
BSF EECON1, RD ; EE Read
BANKSEL EEDATA ; Select Bank of EEDATA
MOVF EEDATA, W ; W = EEDATA
La scrittura dei dati in EEPROM è invece una faccenda più complessa. Microchip infatti impone una sequenza di istruzioni da rispettare tassativamente, pena il malfunzionamento della procedura.
In C, nuovamente con qualche riga di codice si riesce ad accedere alla EEPROM in scrittura:
void write_eeprom(unsigned char eeprom_address,unsigned char eeprom_data)
{
char flInterruptEnabled;
// Read the Interrupt status
flInterruptEnabled = GIE;
EEADR = eeprom_address; // EEPROM address stored in the byte register
EEDATA = eeprom_data; // Load the value that must be saved in EEPROM
EEPGD = 0; // Access to EEPROM memory
WREN = 1; // Start a data EEPROM writing cycle
GIE = 0; // Disable Interrupt
/* REQUIRED SEQUENCE */
EECON2 = 0X55;
EECON2 = 0XAA;
WR = 1;
/* REQUIRED SEQUENCE */
// Enabling interrupt, only if required
GIE = flInterruptEnabled; // Enable Interrupt
while (EEIF == 0); // Wait for the end of the writing operation
EEIF = 0; // Clear the EEPROM interrupt flag
WREN = 1;
}
Invece, in assembly il codice è sempre preso dal datasheet:
BANKSEL EECON1 ; Select Bank of EECON1
BTFSC EECON1, WR ; Wait for write
GOTO $-1 ; to complete
BANKSEL EEADR ; Select Bank of EEADR
MOVF ADDR, W ;
MOVWF EEADR ; Data Memory Address to write
MOVF VALUE, W ;
MOVWF EEDATA ; Data Memory Value to write
BANKSEL EECON1 ; Select Bank of EECON1
BCF EECON1, EEPGD ; Point to DATA memory
BSF EECON1, WREN ; Enable writes
BCF INTCON, GIE ; Disable INTs.
MOVLW 55h ;
MOVWF EECON2 ; Write 55h
MOVLW AAh ;
MOVWF EECON2 ; Write AAh
BSF EECON1, WR ; Set WR bit to begin write
BSF INTCON, GIE ; Enable INTs.
BCF EECON1, WREN ; Disable writes
Per il download dell'esempio, si faccia riferimento alla sezione DOWNLOAD di questo articolo.
Cambia qualcosa con i PIC18F. Infatti per questi PIC è facile trovare dispositivi con tagli di EEPROM maggiori di 256 byte, per i quali i soli 8 bit di indirizzamento sono insufficienti. Il PIC18F4620, ad esempio, ha una EEPROM di 1024 byte, ossia pari a 1kbyte; per accedere a tale EEPROM è indispensabile impiegare un indirizzo ad almeno 10 bit.
Le modalità di accesso alla EEPROM è la medesima a quella dei PIC16F, tanto per i tagli fino a 256 byte quanto per quelli fino a 1kbyte. I file sorgente sono disponibili nella sezione DOWNLOAD di questo articolo.
La verifica di quanto accade, con i PIC16F, è espressa da un semplicissimo programma scritto in C per SDCC:
void main(void)
{
InitPic();
write_eeprom(0,0x55);
PORTB=read_eeprom(0);
while (1);
}
Il programma non fa altro che scrivere all'indirizzo 0 della EEPROM il valore esadecimale 0x55. Siccessivamente il programma accede nuovamente alla EEPROM interna per la lettura del dato all'indirizzo 0. Il valore letto viene poi utilizzato per pilotare PORTB. Per verificare che il valore scritto sia effettivamente presente in memoria, è sufficiente utilizzare MPLAB e richiedere lo stato della EEPROM interna. Prima della scrittura si presenta in questo modo:
Dopo aver eseguito il programma, se si legge mediante MPLAB la EEPROM, ecco che si ottiene questo:
Si noti che all'indirizzo 0x00 è presente il valore 0x55, il che è indice di avvenuta scrittura. La lettura del dato è verificabile chiaramente con lo stato di PORTB.
Ho cercato di raccogliere quanto detto in due pacchetti zip, uno per PIC16F e l'altro per PIC18F:
Questo articolo ed il software rilasciato rientrano nell'ambito della licenza CREATIVE COMMONS BY-NC-ND Italia 3.0, secondo quanto indicato nelle note legali qui riportate.
Sintesi delle note legali (italiano) | |
Note legali (italiano) | |
Legal Code (international) | |
Commons deed (international) |
Dalla rassegna LO HAI MAI REALIZZATO CON UN PIC?
Ambiente di sviluppo MPLAB
Compilatore SDCC
Compilatore C18
Datasheet PIC16F819
Datasheet PIC18F4620
Pillole di microcontrollori PIC: