Come utilizzare una EEPROM esterna con Arduino
EEPROM è l’acronimo di Electrically Erasable Programmable Read-Only Memory (memoria di sola lettura programmabile e cancellabile elettricamente).
La EEPROM è molto importante e utile perché è una forma di memoria non volatile. Ciò significa che anche quando la scheda viene spenta, il chip EEPROM conserva il valore che vi è stato scritto. Pertanto, quando si spegne la scheda e la si riaccende, il dato scritto nella EEPROM può essere letto. In pratica, la EEPROM memorizza e legge il dato in esse contenuto in qualsiasi momento. Ciò significa che è possibile spegnere un dispositivo, tenerlo spento per più giorni, riaccenderlo e ri-leggere i dati in esso contenuti.
L’EEPROM è anche molto efficiente in quanto i singoli byte di una EEPROM tradizionale possono essere letti, cancellati e riscritti in modo indipendente. Nella maggior parte degli altri tipi di memoria non volatile, questo non è possibile. I dispositivi EEPROM seriali come la serie 24 di Microchip consentono di aggiungere ulteriore memoria a qualsiasi dispositivo in grado di comunicare via I²C.
ll chip Microchip 24LC2512 può essere acquistato nel formato DIP a 8 pin. I pin del 24LC512 sono identificabili molto semplicemente e consistono in alimentazione (8), GND (4), protezione da scrittura (7), SCL/SDA (6,5) e tre pin di indirizzo (1, 2, 3).
Stranezze della EEPROM
L’EEPROM come metodo di memorizzazione dei dati presenta due svantaggi principali. Nella maggior parte delle applicazioni, i vantaggi superano gli svantaggi, ma è bene conoscerli prima di incorporare la EEPROM nel vostro prossimo progetto.
Innanzitutto, la tecnologia che fa funzionare la EEPROM limita anche il numero di volte in cui può essere riscritta. Ciò è dovuto al fatto che gli elettroni rimangono intrappolati nei transistor che compongono la ROM e si accumulano fino a rendere irriconoscibile la differenza di carica tra un “1” e uno “0”. Ma non preoccupatevi, la maggior parte delle EEPROM ha un numero massimo di riscritture di 1 milione o più. Finché non si scrive continuamente sulla EEPROM, è improbabile che si raggiunga questo limite massimo. In secondo luogo, la EEPROM non si cancella se si toglie l’alimentazione, ma non conserva i dati a tempo indeterminato. Gli elettroni possono uscire dai transistor e attraversare l’isolante, cancellando di fatto la EEPROM nel tempo. In genere questo fenomeno si verifica nel corso di anni (anche se può essere accelerato dal calore). La maggior parte dei produttori dichiara che i dati sono al sicuro nella EEPROM per 10 anni o più a temperatura ambiente. C’è un’altra cosa da tenere presente quando si sceglie un dispositivo EEPROM per il proprio progetto, la capacità della EEPROM si misura in bit e non in byte, una EEPROM da 512K conterrà 512Kbit di dati, in altre parole, solo 64KB.
Collegamento della EEPROM esterna ad Arduino
Ok, ora che sappiamo cos’è una EEPROM, colleghiamone una e vediamo cosa può fare. Per far parlare il nostro dispositivo, dobbiamo collegare l’alimentazione e le linee seriali I²C. Questo dispositivo, in particolare, funziona a 5VDC, quindi andremo a collegarlo all’uscita 5V del nostro Arduino UNO. Inoltre, le linee I²C avranno bisogno di resistenze di pull-up affinché la comunicazione avvenga correttamente. Il valore di queste resistenze dipende dalla capacità delle linee e dalla frequenza di comunicazione, ma una buona regola per le applicazioni non critiche è di mantenerle nell’intervallo dei kΩ. In questo esempio, utilizzeremo resistenze di pull-up da 4,7kΩ.
Su questo dispositivo sono presenti tre pin per selezionare l’indirizzo I²C; in questo modo è possibile avere più EEPROM sul bus I²C e indirizzarle ciascuna in modo diverso. Per ora andremo a collegare questi pin a GND.
Utilizzeremo una breadboard per collegare il tutto. Lo schema allegato mostra il corretto collegamento per la maggior parte dei dispositivi EEPROM I²C, compresa la nostra EEPROM Microchip serie 24 che vendiamo.
Lettura e scrittura
Nella maggior parte dei casi, quando si utilizza una EEPROM insieme a un microcontrollore, non è necessario vedere tutto il contenuto della memoria in una sola volta. Ci si limita a leggere e scrivere byte qua e là secondo le necessità. In questo esempio, tuttavia, scriveremo un intero file su EEPROM e poi lo rileggeremo per poterlo visualizzare sul nostro computer. In questo modo ci abitueremo all’idea di utilizzare la EEPROM e ci faremo un’idea della quantità di dati che può essere contenuta in un dispositivo di piccole dimensioni.
Scrivere qualcosa
Il nostro schizzo di esempio si limita a prendere qualsiasi byte che arriva attraverso la porta seriale e a scriverlo nella EEPROM, tenendo traccia lungo il percorso di quanti byte sono stati scritti nella memoria.
La scrittura di un byte di memoria nella EEPROM avviene generalmente in tre fasi:
- Inviare il byte più significativo (MSB) dell’indirizzo di memoria su cui si desidera scrivere.
- Inviare il byte meno significativo (LSB) dell’indirizzo di memoria su cui si desidera scrivere.
- Inviare il byte di dati che si desidera memorizzare in questa posizione.
Probabilmente ci sono alcune parole chiave che devono essere spiegate:
Indirizzo di memoria (Memory Addresses)
Se si immagina che tutti i byte di una EEPROM da 512 Kbit siano disposti in una riga da 0 a 64000 – perché ci sono 8 bit in un byte e quindi si possono inserire 64000 byte in una EEPROM da 512 Kbit – allora un indirizzo di memoria è il punto della riga in cui si trova un determinato byte. Dobbiamo inviare questo indirizzo alla EEPROM in modo che sappia dove mettere il byte che stiamo inviando.
Byte più significativo e byte meno significativo (Most Significant Byte and Least Significant Byte)
Poiché ci sono 32000 posti possibili in una EEPROM da 256 Kbit e poiché 255 è il numero più grande che si possa codificare in un byte, dobbiamo inviare questo indirizzo in due byte. Innanzitutto, inviamo il byte più significativo (MSB) – i primi 8 bit in questo caso. Poi inviamo il Least Significant Byte (LSB) – i secondi 8 bit. Perché? Perché è così che il dispositivo si aspetta di riceverli, tutto qui.
Page Writing
La scrittura di un byte alla volta va bene, ma la maggior parte dei dispositivi EEPROM ha una cosa chiamata “page write buffer” che consente di scrivere più byte alla volta nello stesso modo in cui si scrive un singolo byte. Ne approfitteremo nel nostro sketch di esempio. La EEPROM utilizza un contatore interno che aumenta automaticamente la posizione di memoria a ogni successivo byte di dati ricevuto. Una volta inviato un indirizzo di memoria, possiamo farlo seguire da un massimo di 64 byte di dati. La EEPROM presume (giustamente) che un indirizzo di 312 seguito da 10 byte registrerà il byte 0 all’indirizzo 312, il byte 1 all’indirizzo 313, il byte 2 all’indirizzo 314 e così via.
Leggiamo qualcosa
La lettura dalla EEPROM segue sostanzialmente lo stesso processo in tre fasi della scrittura sulla EEPROM:
- Inviare il byte più significativo dell’indirizzo di memoria su cui si desidera scrivere.
- Inviare il byte meno significativo dell’indirizzo di memoria su cui si desidera scrivere.
- Chiedere il byte di dati in quella posizione.
Schema e codice
#include <Wire.h> #define eeprom 0x50 //defines the base address of the EEPROM void setup() { Wire.begin(); //creates a Wire object Serial.begin(9600); unsigned int address = 0; //first address of the EEPROM Serial.println("We write the zip code 22222, a zip code"); for(address = 0; address< 5; address++) { writeEEPROM(eeprom, address, '2'); // Writes 22222 to the EEPROM } for(address = 0; address< 5; address++) { Serial.print(readEEPROM(eeprom, address), HEX); } } void loop() { /* there's nothing in the loop() function because we don't want the arduino to repeatedly write the same thing to the EEPROM over and over. We just want a one-time write, so the loop() function is avoided with EEPROMs. */ } //.........................................defines the writeEEPROM function void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); //writes the MSB Wire.write((int)(eeaddress & 0xFF)); //writes the LSB Wire.write(data); Wire.endTransmission(); } //.........................................defines the readEEPROM function byte readEEPROM(int deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); //writes the MSB Wire.write((int)(eeaddress & 0xFF)); //writes the LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,1); if (Wire.available()) rdata = Wire.read(); return rdata; }