The question is about how to have information/control of a variable length read for an Arduino acting as a slave device.
The concrete context is that I want to emulate an EEPROM IC. A byte write to the EEPROM's address sets the internal EEPROM address to start reading from. The subsequent read from the EEPROM's address, will start returning bytes from that internal address which is incremented for each byte read.
"Wire.onRequest(requestEvent);" allows us to set up a handler, but it seems to be called only once on the start of the read.
In the handler it is possible to provide a reply of multiple bytes. However I did not find the documentation allowing to know how many bytes were effectively sent to the master.
I got the initial code from the arduino forum . I've adapted it to this:
#include <Wire.h>
//#define DEBUG
byte XEEPROM[256] = {
0x5D, 0x26, 0x31, 0x91, 0x3e, 0x12, 0x8e, 0x70, 0xa5, 0x57, 0x3d, 0xed, 0x91, 0x99, 0xb4, 0x11,
0x38, 0xde, 0x1b, 0xd6, 0x4c, 0xd9, 0xf5, 0x13, 0x23, 0x94, 0xb8, 0x3d, 0x9c, 0xb0, 0xc4, 0x54,
0xf0, 0x69, 0xca, 0xb3, 0x28, 0x84, 0xa5, 0xc1, 0x80, 0x53, 0x69, 0x0c, 0x38, 0x4f, 0x0c, 0x74,
0xa1, 0x5b, 0x8c, 0x71, 0x34, 0x30, 0x38, 0x30, 0x30, 0x38, 0x31, 0x35, 0x33, 0x31, 0x30, 0x35,
0x00, 0x12, 0x5a, 0x1e, 0xbd, 0x9e, 0x00, 0x00, 0x02, 0x82, 0x30, 0xaa, 0x10, 0xb7, 0x7f, 0x8d,
0x0a, 0xcb, 0x2e, 0xc1, 0xeb, 0x52, 0x20, 0xdc, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x97, 0x55, 0x57, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4d, 0x54, 0x00, 0x42, 0x53, 0x54, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x02, 0x03, 0x05, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xff, 0xff, 0xff,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x68, 0xaa, 0xdd, 0x02, 0x46, 0x45, 0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69, 0x01, 0x04, 0x46, 0x45,
0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69, 0x01, 0x04, 0x46, 0x45, 0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69,
0x12, 0x03, 0x46, 0x45, 0x8f, 0x8f, 0x78, 0x56, 0xbb, 0x69, 0x02, 0x02, 0x46, 0x45, 0x8f, 0x8f,
0x78, 0x56, 0xbb, 0x69, 0x12, 0x02, 0x84, 0x79, 0x80, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00
};
static volatile byte rQ;
void setup()
{
Wire.begin(0x50);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Serial.begin(115200);
Serial.println("I2C EEPROM EMULATION\n");
}
void loop()
{
}
void requestEvent(){
//Wire.write(XEEPROM[rQ]); // Just 1
Wire.write(XEEPROM+rQ,6); /// More than 1
#ifdef DEBUG
Serial.print("ADR:");
Serial.print(rQ,HEX);
Serial.print("R:");
Serial.print(XEEPROM[rQ],HEX); // print the character
Serial.println();
#endif
rQ++; // Increment should depend on number of reads - not sure how to detect that.
}
void receiveEvent(int iData){
rQ = Wire.read();
Serial.print("ADR:");
Serial.print(rQ,HEX);
bool dwHeader=false;
// loop through all but the last
while(1 < Wire.available())
{
if(!dwHeader) {
dwHeader=true;
Serial.print("DATAW:");
}
XEEPROM[rQ]=Wire.read();;
Serial.print(XEEPROM[rQ],HEX); // print the character
}
Serial.println(); // new line
}
The question is about requestEvent and specifically:
void requestEvent(){
//Wire.write(XEEPROM[rQ]); // Just 1
Wire.write(XEEPROM+rQ,6); /// More than 1
rQ++; // Increment should depend on number of reads - not sure how to
}
I would like to send one at a time, or at least be able to increment rQ according to the number of bytes effectively sent.
If you want to look at a datasheet, you can look at the AT24C02 datasheet. With regards to the incrementing internal EEPROM address, the EEPROM specification says:
CURRENT ADDRESS READ: The internal data word address counter maintains the last address accessed during the last read or write operation, incremented by one. This address stays valid between operations as long as the chip power is maintained. The address “roll over” during read is from the last byte of the last memory page to the first byte of the first page. The address “roll over” during write is from the last byte of the current page to the first byte of the same page.
This is why the Arduino code emulating the EEPROM should know exactly how many bytes were read.
Thanks.