Alrighty, I found my problem!
Convinced that the problem lay in the code that was running on the Arduino acting as a 'bridge' between I2C and serial, I starting examining it closely, which included also digging in to what the Arduino Wire library does. Something caught my eye; the following code that's part of the ISR in the lower-level TWI library that Wire is wrapping:
case TW_SR_STOP: // stop or repeated start condition received
// ack future responses and leave slave receiver state
twi_releaseBus();
// put a null char after data if there's room
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
twi_rxBuffer[twi_rxBufferIndex] = '\0';
}
// callback to user defined callback
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
// since we submit rx buffer to "wire" library, we can reset it
twi_rxBufferIndex = 0;
break;
Hmm, maybe there's a bug with tracking of the index and it's overwriting my trailing LF with that null character it's adding? What size is
TWI_BUFFER_LENGTH, anyway? It's 32 characters? How long are the lines I'm transmitting? Heyyyy... wait a minute... the 'cut-off' point in lines of output where this problem occurs happens to be at
exactly 32 characters!
My eyes strayed further up to where there was another reference to
TWI_BUFFER_LENGTH:
case TW_SR_DATA_ACK: // data received, returned ack
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
// if there is still room in the rx buffer
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
// put byte in buffer and ack
twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
twi_reply(1);
}else{
// otherwise nack
twi_reply(0);
}
break;
Doh!
It's NACK-ing when its receive buffer is full! And at the master side, in my code, I'm handling that by simply skipping transmission of the rest of my buffer. Dammit, I would have noticed that immediately if I had some way of examining what was going across the wire.
And why do they have to have such a small receive buffer?
Anyway, looks like I have a couple of ways of fixing the problem:
- Override the definition of
TWI_BUFFER_LENGTH in the Arduino code and make the buffer larger.
- Reduce the size of my transmit buffer to 32 characters.
- Implement some kind of transmission retry mechanism?
For the latter, what would be the proper way to go about that? Should I have a short pause, then do a repeated start and carry on transmitting the remaining bytes in my send buffer? Perhaps some kind of retry counter as well so that it gives up after too many NACKs?