60 nap alatt Arduino #30-#31 - IIC busz és az EEPROM
EEPROM írás vagy olvasás hiba
Kérlek segítsetek megfogni, mi lehet a hiba a programomban.
A soros eepromba kétféleképpen írok és kétféleképpen olvasok. Az egyik rutin-párral egy bájtot, a másikkal egy menetben többet.
A blokkos írás-olvasás konzekvensen az elvárásnak megfelelően működik, tehát feltehetőleg hardver hibánk nincs. Érdekes módon a bájtonkénti írás/olvasás közül valamelyik nincs a helyzet magaslatán, néha nem csinálják meg a dolgukat, ilyenkor 255-nek olvasható a memória tartalma.
Miért?
Íme pár futtatás eredménye (reset-et nyomtam meg párszor) :
A soros eepromba kétféleképpen írok és kétféleképpen olvasok. Az egyik rutin-párral egy bájtot, a másikkal egy menetben többet.
A blokkos írás-olvasás konzekvensen az elvárásnak megfelelően működik, tehát feltehetőleg hardver hibánk nincs. Érdekes módon a bájtonkénti írás/olvasás közül valamelyik nincs a helyzet magaslatán, néha nem csinálják meg a dolgukat, ilyenkor 255-nek olvasható a memória tartalma.
Miért?
/* i2c eeprom iras/olvasas*/
/* Macsek, 2012.08.31 */
#include "Wire.h" //I2C, azaz TWI miatt kell
#define I2C_EEPROM_CIM 0x50
#define EEPROM_LAPMERET 64 // 64 bajt 1 lap, ez a belso puffermeret is
#define EEPROM_MERET (32U*1024) //24LC256 = 32kB
#define EEPROM_IRAS_LAPATLEPES_HIBA -1
#define EEPROM_OLVASAS_HIBA -2
void setup(void)
{
byte b;
byte tarolo[64]; //
unsigned int i;
Serial.begin(9600);
Serial.println("EEPROM teszt, Macsek");
Wire.begin();
//teszt
#define TESZT_CIM 300
b = read_eeprom(TESZT_CIM);
Serial.print("olvasott bajt:");
Serial.println(b);
write_eeprom(TESZT_CIM, b+1);
b = read_eeprom(TESZT_CIM);
Serial.print("Iras utan olvasott bajt:");
Serial.println(b);
//// blokkokkal ugyanez
#define TESZT_BLOKK_CIM (2*EEPROM_MERET)
#define TESZT_BLOKK_MERET 10
Serial.println("eeprom blokk olvasas");
read_eeprom_tobbet(TESZT_BLOKK_CIM, tarolo, TESZT_BLOKK_MERET);
for(i=0; i<TESZT_BLOKK_MERET; i++)
{
Serial.print(tarolo);
if (i<TESZT_BLOKK_MERET-1)
Serial.print(", ");
else
Serial.println("");
}
for(i=0; i<TESZT_BLOKK_MERET; i++)
if(tarolo)
//tarolo *= i+2;
tarolo++;
else
tarolo=millis(); // ha nulla volt tegyunk bele valami ertelmeset
write_eeprom_lap(TESZT_BLOKK_CIM, tarolo, TESZT_BLOKK_MERET);
Serial.println("eeprom blokk iras utani ujraolvasas");
read_eeprom_tobbet(TESZT_BLOKK_CIM, tarolo, TESZT_BLOKK_MERET);
for(i=0; i<TESZT_BLOKK_MERET; i++)
{
Serial.print(tarolo);
if (i<TESZT_BLOKK_MERET-1)
Serial.print(", ");
else
Serial.println("\n");
}
;
}
void loop(void)
{
;
}
byte read_eeprom(unsigned int cim)
{
byte valaszkod;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
valaszkod = Wire.endTransmission();
if(valaszkod != 0) // hiba
;
Wire.requestFrom(I2C_EEPROM_CIM, 1);
for(int i=0; i<10 && !Wire.available(); i++)
delay(1);
// hibakezeles??
return( Wire.read() );
}
byte write_eeprom(unsigned int cim, byte kiirando)
{
byte valaszkod;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
Wire.write(kiirando);
valaszkod = Wire.endTransmission();
if(valaszkod != 0) // hiba
;
else
delay(5);
return valaszkod;
}
// ha 0 db-ot ker, akkor igy jart, beolvassuk a teljes eepromot, tobbszor.
// mint Chuck Norris, aki elszamolt a vegtelenig. Ketszer.
byte read_eeprom_tobbet(unsigned int cim, byte *beolvasohely, unsigned int olvasando_db)
{
byte valaszkod;
unsigned int i;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
valaszkod = Wire.endTransmission();
if(valaszkod != 0 ) // hiba
;
else if(valaszkod=Wire.available())
{
Wire.requestFrom(I2C_EEPROM_CIM, olvasando_db);
for(i=0; i<10 && !Wire.available(); i++)
delay(1);
for(i=0; i<olvasando_db; i++)
beolvasohely = Wire.read(); // beolvasas bajtonkent
//// le tudom irni C nyelven is :-)
// do
// *beolvasohely++ = Wire.read(); // beolvasas bajtonkent
// while(--olvasando_db);
}
else
valaszkod = EEPROM_OLVASAS_HIBA;
// hibakezeles??
return( valaszkod );
}
// max 64 byte kiirasa egy lapra (64 bajtos lapon belul)
byte write_eeprom_lap(unsigned int cim, byte *kiirandok, byte kiirando_db)
{
byte valaszkod;
unsigned int i;
#define EEPROM_LAPMASK (0xffff - EEPROM_LAPMERET +1) // azaz (-EEPROM_LAPMERET)
if(cim&EEPROM_LAPMASK == (cim+kiirando_db)&EEPROM_LAPMASK) // Lapon belul marad
{
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
// do
// Wire.write(*kiirandok++); // kiirandok altal mutatott
// while(--kiirando_db);
//// Na jo, rendes leszek es ezt is leirom olvashatoan :-)
for(i=0; i<kiirando_db; i++)
Wire.write(kiirandok);
//?? hibakezeles?
valaszkod = Wire.endTransmission();
if(valaszkod != 0) // hiba
;
else
delay(5); // 5ms a max lap kiirasi ido
}
else
valaszkod = EEPROM_IRAS_LAPATLEPES_HIBA; //HIBA
return valaszkod;
}
Íme pár futtatás eredménye (reset-et nyomtam meg párszor) :
Kód: Egész kijelölése
EEPROM teszt, Macsek
olvasott bajt:255
Iras utan olvasott bajt:255
eeprom blokk olvasas
103, 123, 76, 46, 103, 183, 56, 78, 96, 221
eeprom blokk iras utani ujraolvasas
104, 124, 77, 47, 104, 184, 57, 79, 97, 222
EEPROM teszt, Macsek
olvasott bajt:255
Iras utan olvasott bajt:255
eeprom blokk olvasas
104, 124, 77, 47, 104, 184, 57, 79, 97, 222
eeprom blokk iras utani ujraolvasas
105, 125, 78, 48, 105, 185, 58, 80, 98, 223
EEPROM teszt, Macsek
olvasott bajt:255
Iras utan olvasott bajt:255
eeprom blokk olvasas
105, 125, 78, 48, 105, 185, 58, 80, 98, 223
eeprom blokk iras utani ujraolvasas
106, 126, 79, 49, 106, 186, 59, 81, 99, 224
EEPROM teszt, Macsek
olvasott bajt:255
Iras utan olvasott bajt:255
eeprom blokk olvasas
106, 126, 79, 49, 106, 186, 59, 81, 99, 224
eeprom blokk iras utani ujraolvasas
107, 127, 80, 50, 107, 187, 60, 82, 100, 225
EEPROM teszt, Macsek
olvasott bajt:3
Iras utan olvasott bajt:4
eeprom blokk olvasas
107, 127, 80, 50, 107, 187, 60, 82, 100, 225
eeprom blokk iras utani ujraolvasas
108, 128, 81, 51, 108, 188, 61, 83, 101, 226
EEPROM teszt, Macsek
olvasott bajt:4
Iras utan olvasott bajt:5
eeprom blokk olvasas
108, 128, 81, 51, 108, 188, 61, 83, 101, 226
eeprom blokk iras utani ujraolvasas
109, 129, 82, 52, 109, 189, 62, 84, 102, 227
EEPROM teszt, Macsek
olvasott bajt:255
Iras utan olvasott bajt:255
eeprom blokk olvasas
109, 129, 82, 52, 109, 189, 62, 84, 102, 227
eeprom blokk iras utani ujraolvasas
110, 130, 83, 53, 110, 190, 63, 85, 103, 228
EEPROM teszt, Macsek
olvasott bajt:255
Iras utan olvasott bajt:255
eeprom blokk olvasas
110, 130, 83, 53, 110, 190, 63, 85, 103, 228
eeprom blokk iras utani ujraolvasas
111, 131, 84, 54, 111, 191, 64, 86, 104, 229
EEPROM teszt, Macsek
olvasott bajt:5
Iras utan olvasott bajt:6
eeprom blokk olvasas
111, 131, 84, 54, 111, 191, 64, 86, 104, 229
eeprom blokk iras utani ujraolvasas
112, 132, 85, 55, 112, 192, 65, 87, 105, 230
szegoj írta:Macsek, ez mi ?
Miért növeled (mindig) a tarolo tartalmat ?
- /* i2c eeprom iras/olvasas*/
/* Macsek, 2012.08.31 */
...
void setup(void)
{
...
for(i=0; i<TESZT_BLOKK_MERET; i++)
if(tarolo)
//tarolo *= i+2;
tarolo++;
else
tarolo=millis(); // ha nulla volt tegyunk bele valami ertelmeset
Beolvasok egy blokk adatot.
Megjelenítem, h mit olvastam.
Módosítom, h legközelebb mást olvasson ki onnan.
Visszaírom.
Ellenőrzésképpen megint beolvasom.
És megjelenítem, h mit olvastam vissza.
Ez az egész csak teszt, ami azt mutatja, h jól műxik-e. De sajnos vmi miatt nem. No ezt segítsetek lécci megtalálni, h miért.
Így hirtelen bele kukkantva az adatlapba:
http://pdf1.alldatasheet.com/datasheet- ... LC256.html
11. oldal FIGURE 8-2: RANDOM READ
A cím elküldése után kel még 1 control Byte, utána van adat read!
http://pdf1.alldatasheet.com/datasheet- ... LC256.html
11. oldal FIGURE 8-2: RANDOM READ
A cím elküldése után kel még 1 control Byte, utána van adat read!
Szóval le kelene zárni az adat olvasást:
Kód: Egész kijelölése
byte read_eeprom(unsigned int cim)
{
byte valaszkod;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
valaszkod = Wire.endTransmission();
if(valaszkod != 0) // hiba
;
Wire.requestFrom(I2C_EEPROM_CIM, 1);
for(int i=0; i<10 && !Wire.available(); i++)
delay(1);
// hibakezeles??
return( Wire.read() );
Wire.endTransmission() // lezárás
}
Kód: Egész kijelölése
// ha 0 db-ot ker, akkor igy jart, beolvassuk a teljes eepromot, tobbszor.
// mint Chuck Norris, aki elszamolt a vegtelenig. Ketszer.
byte read_eeprom_tobbet(unsigned int cim, byte *beolvasohely, unsigned int olvasando_db)
{
byte valaszkod;
unsigned int i;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
valaszkod = Wire.endTransmission();
if(valaszkod != 0 ) // hiba
;
else if(valaszkod=Wire.available())
{
Wire.requestFrom(I2C_EEPROM_CIM, olvasando_db);
for(i=0; i<10 && !Wire.available(); i++)
delay(1);
for(i=0; i<olvasando_db; i++)
beolvasohely[i] = Wire.read(); // beolvasas bajtonkent
Wire.endTransmission() // lezárás
//// le tudom irni C nyelven is :-)
// do
// *beolvasohely++ = Wire.read(); // beolvasas bajtonkent
// while(--olvasando_db);
}
else
valaszkod = EEPROM_OLVASAS_HIBA;
// hibakezeles??
return( valaszkod );
}
Köszi a doksi linket és a tippet.kapu48 írta:Így hirtelen bele kukkantva az adatlapba:
http://pdf1.alldatasheet.com/datasheet- ... LC256.html
11. oldal FIGURE 8-2: RANDOM READ
A cím elküldése után kel még 1 control Byte, utána van adat read!
kapu48 írta:Szóval le kelene zárni az adat olvasást:byte read_eeprom(unsigned int cim)
{
byte valaszkod;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
valaszkod = Wire.endTransmission();
if(valaszkod != 0) // hiba
;
Wire.requestFrom(I2C_EEPROM_CIM, 1);
for(int i=0; i<10 && !Wire.available(); i++)
delay(1);
// hibakezeles??
return( Wire.read() );
Wire.endTransmission() // lezárás
}// ha 0 db-ot ker, akkor igy jart, beolvassuk a teljes eepromot, tobbszor.
// mint Chuck Norris, aki elszamolt a vegtelenig. Ketszer.
byte read_eeprom_tobbet(unsigned int cim, byte *beolvasohely, unsigned int olvasando_db)
{
byte valaszkod;
unsigned int i;
Wire.beginTransmission(I2C_EEPROM_CIM);
Wire.write(cim>>8);
Wire.write(cim&0xff);
valaszkod = Wire.endTransmission();
if(valaszkod != 0 ) // hiba
;
else if(valaszkod=Wire.available())
{
Wire.requestFrom(I2C_EEPROM_CIM, olvasando_db);
for(i=0; i<10 && !Wire.available(); i++)
delay(1);
for(i=0; i<olvasando_db; i++)
beolvasohely = Wire.read(); // beolvasas bajtonkent
Wire.endTransmission() // lezárás
//// le tudom irni C nyelven is
// do
// *beolvasohely++ = Wire.read(); // beolvasas bajtonkent
// while(--olvasando_db);
}
else
valaszkod = EEPROM_OLVASAS_HIBA;
// hibakezeles??
return( valaszkod );
}
A kivastagított sorok úgy gondolom elküldik a következő kontrol bájtot.
A blokkos olvasás (read_eeprom_tobbet) egyébként jól működik, legalábbis a teszt szerint.
Ha van valami újabb ötleted (vagy vki másnak) akkor jöhet!
Köszi.
Közben nézegettem minta kódokat, ránézésre még rosszabbak, mint az enyém
Kód: Egész kijelölése
byte readEEPROM(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;
}
TWI buffer
Megkerestem. Tényleg annyi.macsek írta:az dereng, h 32 byte a Wire buffere
c:\Program Files\Arduino\arduino-1.0.1\libraries\Wire\utility\twi.h
Kód: Egész kijelölése
#ifndef TWI_BUFFER_LENGTH
#define TWI_BUFFER_LENGTH 32
#endif
A TWI buffer méret még felülírható, de a Wire buffere hanyagabbul van definiálva, tehát nem ilyen egyszerű felülbírálni:
c:\Program Files\Arduino\arduino-1.0.1\libraries\Wire\Wire.h
Kód: Egész kijelölése
#define BUFFER_LENGTH 32
Megnéztem a C++ forrást is.
c:\Program Files\Arduino\arduino-1.0.1\libraries\Wire\Wire.cpp
Kód: Egész kijelölése
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
// clamp to buffer length
if(quantity > BUFFER_LENGTH){
quantity = BUFFER_LENGTH;
}
Kód: Egész kijelölése
size_t TwoWire::write(uint8_t data)
{
if(transmitting){
// in master transmitter mode
// don't bother if buffer is full
if(txBufferLength >= BUFFER_LENGTH){
setWriteError();
return 0;
}
// put byte in tx buffer
txBuffer[txBufferIndex] = data;
++txBufferIndex;
Konklúzió:
Ha nagyon akarjuk megcsinálható saját, helyettesítő header fájl használatával, de a uC szűkös memóriájából csak azért odaadni a buffernek még 32 bájtot, hogy a lap egy menetben írható legyen, nem feltétlenül indokolt.
Tovább nézegettem a Wire forrását.
Ez azt jelenti, h nem szabad a visszaadott értéket felhasználni, mert nincs dokumentálva és emiatt elvileg bármikor megváltoztathatják egy újabb verzióban?
Ezt mi a francért kötelező meghívni? Semmit nem csinál csak visszaadja, h hány bájt van a bufferben.
Max akkor van értelme, ha addig nem olvasunk, míg nem adja azt, h van már beérkezett adatunk!
Így lenne korrekt az olvasás:
----------
Sajnos a tanfolyami példaprogram sem működik
(az FF-et 99-re cseréltem, a send-eket meg write-re és a receive-eket read-re)
A kód szerint pedig megvárja a beolvasás végét és visszaadja a beolvasott bájtok számát:
Kód: Egész kijelölése
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
// clamp to buffer length
if(quantity > BUFFER_LENGTH){
quantity = BUFFER_LENGTH;
}
// perform blocking read into buffer
uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;
return read;
}
Kód: Egész kijelölése
/*
* Function twi_readFrom
* Desc attempts to become twi bus master and read a
* series of bytes from a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes to read into array
* sendStop: Boolean indicating whether to send a stop at the end
* Output number of bytes read
*/
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 0;
}
// wait until twi is ready, become master receiver
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MRX;
twi_sendStop = sendStop;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
twi_masterBufferLength = length-1; // This is not intuitive, read on...
// On receive, the previously configured ACK/NACK setting is transmitted in
// response to the received byte before the interrupt is signalled.
// Therefor we must actually set NACK when the _next_ to last byte is
// received, causing that NACK to be sent in response to receiving the last
// expected byte of data.
// build sla+w, slave device address + w bit
twi_slarw = TW_READ;
twi_slarw |= address << 1;
if (true == twi_inRepStart) {
// if we're in the repeated start state, then we've already sent the start,
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
// We need to remove ourselves from the repeated start state before we enable interrupts,
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
// up. Also, don't enable the START interrupt. There may be one pending from the
// repeated start that we sent outselves, and that would really confuse things.
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
TWDR = twi_slarw;
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
}
else
// send start condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
// wait for read operation to complete
while(TWI_MRX == twi_state){
continue;
}
if (twi_masterBufferIndex < length)
length = twi_masterBufferIndex;
// copy twi buffer to data
for(i = 0; i < length; ++i){
data[i] = twi_masterBuffer[i];
}
return length;
}
Kód: Egész kijelölése
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::available(void)
{
return rxBufferLength - rxBufferIndex;
}
Max akkor van értelme, ha addig nem olvasunk, míg nem adja azt, h van már beérkezett adatunk!
Így lenne korrekt az olvasás:
Kód: Egész kijelölése
Wire.requestFrom(80, 1);
while(Wire.available()) {
;
}
num = Wire.receive();
Sajnos a tanfolyami példaprogram sem működik
(az FF-et 99-re cseréltem, a send-eket meg write-re és a receive-eket read-re)
/* IIC EEPROM byte alapu kezelese
60 nap alatt arduino tanfolyam
(c) TavIR http://avr.tavir.hu */
//IIC buszt hasznalunk
#include "Wire.h"
//24LC256 chip cime
#define disk1 0x50
void setup(void)
{//Sorosport megnyitasa es IIC inicializalas
Serial.begin(9600);
Wire.begin();
//Melyik cimre irjunk?
unsigned int address = 99;
//Ird be a ..., a ...cimre, a 123-as szamot
writeEEPROM(disk1, address, 123);
//Mi van a .. cimen a chipben? Ird ki sorosporton
Serial.println(readEEPROM(disk1, address));
}
void loop(){
}
void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{
Wire.beginTransmission(deviceaddress);
//Cim magas helyierteke
Wire.write((int)(eeaddress >> );
//Cim alacsony helyierteke
Wire.write((int)(eeaddress & 0xFF));
//Es a beirando adat
Wire.write(data);
Wire.endTransmission();
delay(5);
}
byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
byte rdata = 99;
Wire.beginTransmission(deviceaddress);
//Magas helyiertek
Wire.write((int)(eeaddress >> );
//Alacsony helyiertek
Wire.write((int)(eeaddress & 0xFF));
Wire.endTransmission();
//Egy byte olvasando
Wire.requestFrom(deviceaddress,1);
//Ha sikerult...
if (Wire.available()){
rdata = Wire.read();
}
return rdata;
}