EEprom esterna I2C

Ho provato l’esempio trovato all’indirizzo:
http://arduino.cc/playground/Code/I2CEEPROM
ma non funzionano; ritorna sempre 255 cioè nessun dato.

Nell’esempio viene utilizzato 0x50 come codice DEVICE ma io so che
il codice delle EEPROM I2C è 0xA0.
Li ho utilizzati entrambi sempre con lo stesso risultato.

Le 2 routine ricavate dall’indirizzo di cui sopra e che ho utlizzato sono queste:

#include <Wire.h> //I2C library
//—Scrive un byte su EEprom I2C----------------------------------------------
void i2C_Scrive_B(int ind_dev, unsigned int ind, byte data ) {
int rdata = data;
Wire.beginTransmission(ind_dev);
Wire.send((int)(ind >> 8)); // MSB
Wire.send((int)(ind & 0xFF)); // LSB
Wire.send(rdata);
Wire.endTransmission();
}
//—Legge un byte da EEprom I2C-----------------------------------------------
byte i2C_Legge_B( int ind_dev, unsigned int ind ) {
byte rdata = 0xFF;
Wire.beginTransmission(ind_dev);
Wire.send((int)(ind >> 8)); // MSB
Wire.send((int)(ind & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(ind_dev,1);
if (Wire.available()) rdata = Wire.receive();
return rdata;
}

E per lettura e scrittura ho utilizzato questo codice:

int ind_dev=0xA0;
unsigned int ind=3;
byte data=12;
byte dato;
//-------------------------------------------------------------
//—Predisposizione-------------------------------------------
void setup() {
Serial.begin(9600); //Velocità porta seriale.
i2C_Scrive_B(ind_dev,ind,data);
}
//—Ciclo principale------------------------------------------
void loop() {
dato=i2C_Legge_B(ind_dev,ind);
Serial.println(dato,DEC);
delay(3000);
}

Qualcuno ha mai utilizzato queste funzioni?

Altre funzioni funzionanti? Dove?

Grazie

Carletto

L'indirizzo di una EEPROM è composto da una parte fissa, riportata sul datasheet, poi c'è anche la parte assegnata dall'utente tramite alcuni pin.

Poi servono le R di pull-up per far funzionare il bus I2C.

Potresti pubblicare anche il circuito oltre che lo sketch?

Grazie Leo72 per l’interessamento, allego lo schema, è un classico che tra l’altro
ho già utilizzato altre volte con i PIC, con Arduino (ATMEL) sono nuovo.

Ho una scheda mega 2560 R2.

Sto provando un pò di cose, proverò poi anche la tua libreria swRTC.

Saluti Carletto.

EEprom I2C.pdf (13.3 KB)

Lo schemino è giusto, l'indirizzo base è 0x50, come segnato sul datasheet. L'unica cosa sono le R di pull-up: per il bus I2C servono tra 1K5 e 2K2, non più alte, altrimenti abbassi troppo la corrente.

Con il sketch che trovi a http://todbot.com/blog/2009/11/29/i2cscanner-pde-arduino-as-i2c-bus-scanner/ puoi scannerizzare il bus I2C e ottieni gli indirizzi dei dispositivi collegati. se cambi la riga byte end_address = 100; in byte end_address = 128; scanna tutti gli indirizzi possibili.

Ciao Uwe

leo72 - Ho sostituito le resistenze di pull-up, le ho messe da 1k8 e non è cambiato niente. Ho provato a vedere i segnali con oscilloscopio ma niente.

uwefed - Ho provato a caricare quel file (I2CScanner.pde) che mi hai suggerito. Mi restituisce una tabella con i 128 indirizzi, ne ha trovato 1, il numero 80. A questo punto ho inserito il numero 80 come "control byte" anzichè il numero 0XA0, ma il risultato è sempre lo stesso. Non è cambiato niente.

E' poi il numero da utilizzare come "control byte" della EEprom?

Saluti Carletto.

Ma 8010=A016
Quindi l’indirizzo è giusto che sia A016, ma anch’io te l’avevo detto dato che da datasheet, l’indirizzo è composto dalla parte fissa 10102 a cui si somma la parte variabile composta dallo stato dei pin A0-A2, nel tuo caso mettendoli a massa tutti hai 0002 per cui 10102-0002=10100002 da cui si ottiene 8010/0xA016

Scusami carletto, stiamo girando nel cerchio. Gli eeprom non son tutti uguali; quale EEPROM stai usando? Ciao Uwe

Ho provato con una EEprom 24C32 e poi con una 24C65
ma il risultatto è sempre lo stesso.
Scrivo il n° 12 e leggo 255 cioè vuoto.

Sono nuovo di Arduino e quindi non ho dimestichezza con i principi, funzioni ecc.

Anche se programmo microcontrollori PIC da un decennio e scrivere e leggere
le EEprom non era un problema.

Qualcuno ha mai utilizzato queste routine?
Magari non sono funzionanti.

Qui di seguito tutto il codice con le librerie che ho copiato dal sito.

Grazie per ulteriori consigli.

#include <Wire.h> //I2C library
//-------------------------------------------------------------
int ind_dev=0XA0;
unsigned int ind=3;
byte invia=12;
byte riceve;
//—Predisposizione-------------------------------------------
void setup() {
Wire.begin(); //Inizializza il bus I2C.
Serial.begin(9600); //Velocità porta seriale.
i2c_eeprom_write_byte(ind_dev,ind,invia);
delay(200);
Serial.print("Scrittura n° : ");
Serial.println(invia,DEC);
}
//—Ciclo principale------------------------------------------
void loop() {
riceve=i2c_eeprom_read_byte(ind_dev,ind);
delay(200);
Serial.print("Lettura n° : ");
Serial.println(riceve,DEC);
delay(3000);
}
//-----------------------------------------------------------------------------
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
int rdata = data;
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.send(rdata);
Wire.endTransmission();
}
//-----------------------------------------------------------------------------
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
byte rdata = 0xFF;
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,1);
if (Wire.available()) rdata = Wire.receive();
return rdata;
}
//-----------------------------------------------------------------------------
// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library
// has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddresspage >> 8)); // MSB
Wire.send((int)(eeaddresspage & 0xFF)); // LSB
byte c;
for ( c = 0; c < length; c++)
Wire.send(data

);
    Wire.endTransmission();
  }

//-----------------------------------------------------------------------------
  // maybe let's not read more than 30 or 32 bytes at a time!
  void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
    Wire.beginTransmission(deviceaddress);
    Wire.send((int)(eeaddress >> 8)); // MSB
    Wire.send((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,length);
    int c = 0;
    for ( c = 0; c < length; c++ )
      if (Wire.available()) buffer[c] = Wire.receive();
  }

Io le ho usate e non mi hanno dato problemi. Domanda scema: ma hai messo le masse in comune?

Cambia qualcosa se metti il seguente??? unsigned int ind_dev=0XA0;

.......ma hai messo le masse in comune?

Si, GND della mia mega2560 è collegata con i pin 1,2,3 e 4 della EEprom.

Con il tester tra questi pin e il pin 8 leggo la tensione di alimentazione cioe 5 volt, anche i pin 5 e 6 misurano 5 volt con GND per il pull-up.

Ho riprovato oggi le EEprom che ho su una board con il PIC18F2525 e funziona.

Sara la mia arduino che non funziona? Ho collegato il BUS al pin 20 SDA e al pin 21 SCL. Ci sono altri pin che si possono utilizzare come BUS I2C?

Ciao grazie.

I pin SDA e SCL sono fissi perché mappati in HW per cui non puoi cambiarli.
Io ho la UNO ma non credo c’entri molto.

Prova questo sketch:

/*
Example 21.2  Reading and writing data to Microchip 24LC256 EEPROMS over I2C
tronixstuff.com/tutorials > Chapter 21  CC by-sa v3.0
*/
#include  "Wire.h"    // for I2C
#define chip1 0x50    // device address for left-hand chip on our breadboard
#define chip2 0x51    // and the right

// always have your values in variables
unsigned int pointer = 69; // we need this to be unsigned, as you may have an address > 32767
byte d=0; // example variable to handle data going in and out of EERPROMS

void setup() {
    delay(5000);
    Serial.begin(9600); // for screen output
    Wire.begin();   // wake up, I2C!
}

void writeData(int device, unsigned int add, byte data) {
// writes a byte of data 'data' to the chip at I2C address 'device', in memory location 'add'
    Wire.beginTransmission(device);
    Wire.send((int)(add >> 8));   // left-part of pointer address
    Wire.send((int)(add & 0xFF)); // and the right
    Wire.send(data);
    Wire.endTransmission();
    delay(10);
}

byte readData(int device, unsigned int add) {
// reads a byte of data from memory location 'add' in chip at I2C address 'device'
    byte result;  // returned value
    Wire.beginTransmission(device); //  these three lines set the pointer position in the EEPROM
    Wire.send((int)(add >> 8));   // left-part of pointer address
    Wire.send((int)(add & 0xFF)); // and the right
    Wire.endTransmission();
    Wire.requestFrom(device,1); // now get the byte of data...
    result = Wire.receive();  return result; // and return it as a result of the function readData
}

void loop() {
    Serial.println("Writing data...");
    for (int a=0; a<20; a++) {
        writeData(chip1,a,a);
        writeData(chip2,a,a); // looks like a tiny EEPROM RAID solution!
    }
    Serial.println("Reading data...");
    for (int a=0; a<20; a++) {
        Serial.print("chip1 pointer ");
        Serial.print(a);
        Serial.print(" holds ");
        d=readData(chip1,a);
        Serial.println(d, DEC);
    }
    for (int a=0; a<20; a++) {
        Serial.print("chip2 pointer ");
        Serial.print(a);
        Serial.print(" holds ");
        d=readData(chip2,a);
        Serial.println(d, DEC);
    }
    delay(500);
}

E’ per 2 chip EEPROM, togli il codice che legge/scrive sul secondo e provalo.

RISOLTO!

Grazie leo72.

Ho cambiato il control byte in 0X50 come dal tuo listato, quindi OK.

Non ho capito però perchè se nel datasheet della EEprom è indicato come

A + il codice del chip, se i pin 2, 3, 4 sono collegati al GND la seconda cifra vale 0

quindi il codice dovrebbe essere 0XA0 in esadecimale.

Ma visto che funziona cosi c'è di sicuro un perchè e mi piacerebbe conoscerlo,

Grazie di nuovo leo72.

Carletto

Rileggi questi miei interventi:

leo72:
L’indirizzo di una EEPROM è composto da una parte fissa, riportata sul datasheet, poi c’è anche la parte assegnata dall’utente tramite alcuni pin.

leo72:
Ma 8010=A016
Quindi l’indirizzo è giusto che sia A016, ma anch’io te l’avevo detto dato che da datasheet, l’indirizzo è composto dalla parte fissa 10102 a cui si somma la parte variabile composta dallo stato dei pin A0-A2, nel tuo caso mettendoli a massa tutti hai 0002 per cui 10102-0002=10100002 da cui si ottiene 8010/0xA016