Wire.onRequest & Wire.onReceive

I try to build an I2C real slave. Real slave mean it simulate I2C device. It is mean I can place data in specific reg and read from specific reg in it. I build a a 2D arrey of reg add, data.
Now I send from master command.

  1. write data. Send device add, reg add, data
Wire.beginTransmission(deviceAddress);
  Wire.write(registerAddress);
 Wire.write(data);
  Wire.endTransmission();
  1. read data. Send device add, reg add with erite and then start again with read device add.
Wire.beginTransmission(deviceAddress);
  Wire.write(registerAddress);
  Wire.endTransmission(false) ;
  Wire.requestFrom(deviceAddress, length);

For slave I see two function that could help me but I don't sure what each of them does.
Wire.onRequest & Wire.onReceive
On write and read I have to know what reg is request and then know that on wrie to take the data and on read to know to send the data.
So does Wire.onReceive is good for write to salve (so I will check I have 2 bytes recieve reg add, data ) ?
but the hard part is reading from slave, when I first have to know what reg request. Can I use Wire.onReceive to know 1. I have read command (only 1 byte is send reg add), and also know which reg add request and then wait for the Wire.onRequest to send the data out?
Does those function can be use in a raw or only one of them at each time, and if so is there anther function that can do the job for read?
Thnanks.

The slave remembers the last register address received. That address can be used for reading or writing. The register size is specific to the slave. Also auto-increment of the address can be specified for transmission of multiple registers.

onReceive() is called after all data are transmitted by the master. The slave reads these bytes from Wire.
onRequest() has to transmit as many bytes as the master requests, in one or more invocations, until the master ends the transmission.

Thanks.
But does the onReceive() will also work for the slave after Wire.endTransmission(false) from the master? It is mean that if the master sends only the first part of the read(retransmission), does at that point the slave get the onReceive() and can get the register add , before it get the onRequest() when he should know which reg data to send?

Go ahead. Build it. Show us the code.
If you are using Arduino Uno boards, then it might work reliable. There are, however, many rules.

I have written a few notes on Github: Arduino in Target mode

If you keep the emulated "registers" and the emulated "register_address" in variables, then it will work just like a sensor. If the Master is also an Arduino board, then you probably won't notice the difference.

The term "register" is a reserved word and "index" is shorter than "register_address".

byte data[40];
byte index;
volatile bool flag;

void receiveEvent(int howMany)
{
  if(howMany > 0)  // extra safety check, there should be at least one byte
  {
    // The first byte is the register address
    index = Wire.read();
  }

  // Are there more byte to store in the emulated registers ?
  if(howMany > 1)
  {
    for(int i=0; i<howMany-1; i++)
    {
      data[index] = Wire.read();
      index++;
      if(index >= 40)
        index = 0;       // rollover to zero
    }
    // Set a flag, to tell the code in the loop() 
    // that new data has arrived.
    flag = true;       
  }
}

void requestEvent()
{
  // Just one byte.
  // The Master should not request more bytes with this code.
  Wire.write(data[index]);
  index++;
    if(index >= 40)
      index = 0;       // rollover to zero
}

If you use this code, then I can point out at least 10 problems with it.

Yes, the parameter "false" keeps the I2C bus claimed in hardware. It makes no difference for the software.

Thanks for you answer.
Some questions about it.

  1. Do you mean recieveEvent is the callback for OnRecive snd requestEvent is for OnRewuest?
  2. If so does the address request get from recieveEvent, and then wait for the requestEvent, to send the data back?
  3. What do you mean by "If you use this code, then I can point out at least 10 problems with it.". So the code is not good to use?
    Bar

About 1:
Yes, you may call them "callback" routines.
The Arduino Wire library for an Arduino Uno is interrupt driven. The receiveEvent() and requestEvent() functions are called from a interrupt. So you should be careful what you do in those functions.

About 2:
There is no such thing as address request. Can you study the basics of the I2C bus ?

There are only two things: The Master can send data or the Master can request data.
There is absolutely nothing else in the I2C protocol. Those things are never linked together, they are totally different things. Each one needs a I2C session. Data bytes can not go in two directions during a single I2C session.

The I2C address on the I2C bus is recognized in hardware by the Slave. When the hardware recognizes its own address, then the interrupt inside the Wire library comes in action.

At a higher level, the Master can send first a "register_address" and then another I2C session to request some the data.
At a higher level, the Slave could store that "register_address" and use it as a index to the data when there is a call to requestEvent(). The Slave does not wait for something. It suddenly gets a call to the receiveEvent() or the requestEvent() function.

About 3:
It depends if there are libraries that turn of the interrupts for a while. I depends on the code in the loop(). It depends on how often the Master sends or requests data and if it is alright that data is overwritten while that data is still being processed. It depends if you want to detect that some messages were missed because there was a delay in the loop(). And so on.

I2C Slave must be equipped with "I2C Logic Interface". Microcontroller like ATmega328P of UNO Board has built-in hardware "I2C Logic Interface". ATmega328P MCU can be used either as Master or Slave.

There are sensors that come with built-in I2C Logic Interface like BME280, MPU6050, etc.

When you say that you want to build a "real slave", then the meaning is not clear.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.