Hi, I'm running into slightly unexpected behavior with Wire and an ATMEGA328. The atmega should act as an I2C target (slave).
The protocol of in-hardware external controller(s) is that it/they write an 8-bit base memory address to the target first, switch themselves to reading, and then clock in a varying number of bytes that the target should place on the bus. When the controller has received enough, it terminates the I2C transfer with No ACK + Stop. Essentially, a "sequential read" with implicit "auto increment" of the address.
The issue I run into is, the Wire onRequest() handler gets invoked only for the first byte of the sequential read. That is, controllers see one byte of valid data, and then blank.
How to get an onRequest() also for the subsequent bytes that the controller tries to clock in?
The Wire library does not support the mode where an I2C Slave continues to send data bytes (typically from sequential memory / register locations) until the Master signals the end of the operation with STOP.
Ah. Thanks. Well that's a pity! Is there perhaps another Arduino I2C library that would support that? Worst case I'll have to clone Wire and modify it.
Write them all as Delta_G wrote.
For ATmega chips, the buffer size (inside the Wire library) is 32 byte. You can Wire.write() 32 bytes, starting from 'i2c_offset'.
The Controller (Master) can read 1 up to 32 bytes, and will stop the I2C session when it has enough.
After that, the Controller can not continue to read data in a next I2C session, but has to send the offset first.
Many have tried to "improve" the Wire library, and many have failed.
Do you have a Logic Analyzer ? Then you have seen the "clock pulse stretching". When the Controller want to read data, then the Target needs some time to run the onRequest handler. It creates that time by keeping SCL low.
Question: If the Controller reads (for example) 10 bytes, and the Target has only 9 bytes or has 11 bytes. How does the Controller know that during that I2C session ?
Answer: The Controller does not know that. That is part of how the I2C bus works. The Controller will always read 10 bytes, the Target can not influence that. If the Target has less bytes, then most likely the rest of the bytes are 0xFF.
Wire is built off the functions in twi.c / twi.h. If this feature is really important for you, I'd say make a one-off implementation starting with that code.
Thanks, wondered what Delta_G meant with "all" bytes. The number of bytes expected by the controller is variable, i.e., the ATmega cannot know it in advance. Makes sense now, though, "all" = "worst-case maximal length", and counting on the unused part of the tx buffer getting flushed.
Tried it and the approach works The 32-byte limit is not so great, but so far the controller doesn't appear to have requested more, at least, no error conditions reported over a few minutes of run time.
For "continued" send, I've now additionally modified a copy of Wire.cpp/.h + twi.c/.h; twi.c at TW_ST_DATA_ACK extended with an optional user callback to replenish the tx buffer through a new onRequestMore() callback with associated onRequest()-like plumbing.
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register
TWDR = twi_txBuffer[twi_txBufferIndex++];
+ // if the buffer emptied, request it to be topped up
+ if (twi_txBufferIndex >= twi_txBufferLength) {
+ twi_onSlaveTransmitMore();
+ }
// if there is more to send, ack, otherwise nack
if(twi_txBufferIndex < twi_txBufferLength){
twi_reply(1);
}else{
twi_reply(0);
}
break;
This "request more" approach worked fine, too. Did a 1-byte initial send (vs. upfront 32-byte send) in the onRequest() handler, then trickled in the additional single bytes via a new onRequestMore(). The code in both handlers must be extremely short, though.
Btw, alas, I do not have a scope nor logic analyzer. Would help to see how marginal the timings are...