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
Indice |
C'è memoria e memoria...
Facciamo un breve excursus. I sistemi informatici si basano principalmente su questo tipo di memorie: memorie volatili;memorie non volatili;memoria di massa
Memorie volatili
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):
Memorie non volatili
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.
Memorie di massa
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.
I PICMicro e le memorie
È 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:
- Flash: 3584 byte;
- RAM: 256 byte;
- EEPROM: 256 byte
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.
La EEPROM e i suoi registri
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 memori 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 cheavviene 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:
- EECON1
- EECON2
- EEDATA
- EEDATH
- EEADRE
- EADRH
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:
- EECON1: è il registro di configurazione principale. Contiene al suo interno bit per impostare l'accesso in scrittura o lettura, lo stato di eventuali errori, l'accesso alla Program Memory o alla EEPROM
- EECON2: non è un vero e proprio registro, infatti una lettura di EECON2 comporta solamente come risultato '0'. Questo registro è utilizzato dal PIC nella sequenza di scrittura dei dati
- EEDATA: registro a 8 bit che contiene il dato da scrivere in EEPROM oppure il dato che la EEPROM restituisce a seguito di una lettura
- EEADR: è il registro che contiene l'indirizzo della cella di memoria della EEPROM nella quale si vuole scrivere o leggere un dato
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 | EPGD | Se posto a 1 permette l'accesso alla program memory, viceversa si accede alla EEPROM |
Accesso in lettura
La lettura dei dati dalla EEPROM è senz'altro un'operazione molto semplice. Con quattro passi si arriva dalla richiesta al dato:
- Scrivere nel registro EEADR l'indirizzo della cella alla quale si vuole accedere
- Porre a 0 il bit EEPGD del registro EECON1, in modo da dichiarare l'accesso alla EEPROM
- Porre a 1 il bit RD di EECON1, in modo da dare il via alle operazioni di lettura
- Leggere il dato dal registro EEDAT
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
Accesso in scrittura
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.
- Qualora gli interrupt siano abilitati, verificare che il bit EEIF sia posto a 1, il che significa che non è in corso alcuna operazione di scrittura. Viceversa, verificare che il bit WR di EECON1 non sia posto a 1, proprio ad indicare che non sia in atto alcuna operazione di scrittura
- Scrivere nel registro EEADR l'indirizzo della cella alla quale si vuole accedere
- Scrivere nel registro EEDAT il dato da scrivere
- Porre a 0 il bit EEPGD del registro EECON1, in modo da dichiarare l'accesso alla EEPROM
- Porre a 1 il bit WREN del registro EECON1, in modo da abilitare le operazioni di scrittrura
- Disabilitare gli interrupt, qualora siano stati abilitati in precedenza
- Eseguire una specifica sequenza composta da 5 istruzioni: scrittura di 0x55 prima nel registro W e poi nel registro EECON2, scrittura di 0xAA prima nel registro W e poi nel registro EECON2, avviare il ciclo di scrittura ponendo a 1 il bit WR
- Riabilitare gli interrupt, se erano stati utilizzati
- Porre il bit WREN a 0 per disabilitare le operazioni di scrittura
- Al termine della scrittura, il bit WR viene automaticamente posto a 0 e il bit EEIF viene posto a 1, ad indicare che le operazioni sono state concluse.
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.
</pre>
EEPROM interne ai PIC18F
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.
Un esempio per PIC16F
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.
Download
Ho cercato di raccogliere quanto detto in due pacchetti zip, uno per PIC16F e l'altro per PIC18F:
- Accesso alla EEPROM per PIC16F (codice C per SDCC);
- Accesso alla EEPROM per PIC18F (codice C per Microchip C18);
Licenza
Questo articolo ed il software rilasciato rientrano nell'ambito della licenza CREATIVE COMMONS BY-NC-ND 3.0, secondo quanto indicato nelle note legali qui riportate.
Sintesi delle note legali (italiano)
Biblografia
- Datasheet PIC16F819: http://ww1.microchip.com/downloads/en/devicedoc/39598e.pdf
- Ambiente di sviluppo MPLAB: http://www.microchip.com/mplab
- Compilatore SDCC: http://sdcc.sourceforge.net
- GPUTILS: http://gputils.sourceforge.net
- Sito web PicExperience
- Collana "LO HAI MAI REALIZZATO CON UN PIC?":
- Il contamarce
- Una sorpresa musicale per Babbo Natale
- Una tecnica antirimbalzo
- Il dado elettronico
- Un approccio ai timer dei PICMicro
- I PIC e i segnali analogici: la conversione A/D
- Generare segnali PWM con i PICMicro
- La lampada SIBILLA!
- Una tecnica di misura della tensione di batteria
- Il PIC tiene la data e l'ora
- Una prima occhiata a SDCC
- PIC Watch un semplice OROLOGIO SVEGLIA
- I PICMicro e i display LCD alfanumerici (parte 1)
- I PICMicro e i display LCD alfanumerici (parte 2)
- Una semplice tecnica di PWM software