Notifications
Clear all

I2C slave: Does Wire.write() work from the main loop?

4 Posts
2 Users
1 Likes
3,745 Views
mbogelund
(@mbogelund)
Member
Joined: 5 years ago
Posts: 23
Topic starter  

Hi,

I have a question about how Wire.write() is supposed to work.

I have a piece of test code running on and Arduino, which is supposed to take an I2C request for 2 bytes, and sending 2 bytes back using the Wire.write function.

In order to make my ISR/request handler function lean, I only set a boolean in it to indicate I want to send data back, and then do the actual sending in my main loop.

Something like this...

ISR:

  sendData() {

    sendBytes = 1;

  }

Setup:

  onRequest(sendData);

Loop:

if (sendBytes == 1) {

  sendBytes=0;

  Wire.write([3,120]);

}

 

This doesn't work. I always receive [0, 255].

However, if I move the Wire.write-part from the main loop to the ISR:

sendData() {

      Wire.write([3,120]);

 }

then everything works.

I can find an example that Wire.write works from the main loop when it's a master that is sending: https://www.arduino.cc/en/Reference/WireWrite

But when a slave is sending, it seems to happen exclusively from within the ISR:

https://www.arduino.cc/en/Tutorial/MasterReader

 

So my question is:

Can I expect Wire.write() to work from outside the ISR in an I2C slave setup? 

 

This topic was modified 4 years ago by mbogelund

   
Quote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

G'day!
My experience with I2C is very limited, but I do know that running some types of code in ISR's can be problematic due to scope and volatility.  I just checked the header and implementation files for wire.h, and here are the details - Sometimes, the comments offer good direction towards debugging your code:

wire.h (relevant details) - Note that these declarations are virtual functions
----------------------------------------------------------------------------
    virtual size_t write(uint8_t);
    virtual size_t write(const uint8_t *, size_t);

wire.cpp - (implementation file)
-------------------------------------------
// must be called in:
// slave tx event callback or after beginTransmission(address)
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;
// update amount in buffer
txBufferLength = txBufferIndex;
}else{
// in slave send mode
// reply to master
twi_transmit(&data, 1);
}
return 1;
}

// must be called in:
// slave tx event callback or after beginTransmission(address)
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
if(transmitting){
// in master transmitter mode
for(size_t i = 0; i < quantity; ++i){
write(data[i]);
}
}else{
// in slave send mode
// reply to master
twi_transmit(data, quantity);
}
return quantity;
}

Also, check out this pretty good article... it may help you to narrow down the actual problem... note that spelling is also mentioned here:   http://www.gammon.com.au/interrupts

Good luck! 🙂

 


   
mbogelund reacted
ReplyQuote
mbogelund
(@mbogelund)
Member
Joined: 5 years ago
Posts: 23
Topic starter  

Hi @frogandtoad

Thanks!

I'll have to align my slave code to that, then. I simply wanted to run as much code as possible outside the ISR to keept it small and fast. Now I'll have to stuff it with a huge if-then-else construction.

Is volatility really an issue here? I usually define my variables as "volatile" if they are to be changed in the request- and receive-handlers (that's also mentioned in the link you sent). Are you saying this might not be enough?


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@mbogelund

Yes, volatility is always an issue of concern with interrupts, especially because these functions as described in the header declaration are virtual, which means they are dynamically interpreted at run time, and with the added issue of interrupts, that could be the issue, not 100% sure, but it just may be something to review.

Cheers!

 


   
ReplyQuote