1

I am trying to set up several ATSAM-based AVR chips in a master/slave broadcasting arrangement. I want the master to be able to send a broadcast message to I2C address 0, and then for slaves to respond with different information. I have seen other implementations where this has been successful since I2C devices will typically self-arbitrate and if they are configured to back-off when arbitration is lost, the master can repeat its request and iterate over all addresses on the bus.

The challenge is that while I have Wire.beginTransmission(0) working to reach my slaves from the master, I cannot get Wire.requestFrom(0,6) to work. The slave acts as though no message had arrived in the reply case. This is in the reduced case of one master and one slave.

In the example below, changing RequestFrom to the slave address will work.

I am aware that on the SAMD architecture, ArduinoCore does not configure the SERCOM for I2C broadcasts so I made a one-line modification as follows to enable it:

sercom->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR( ucAddress & 0x7Ful ) | // 0x7F, select only 7 bits
                      SERCOM_I2CS_ADDR_ADDRMASK( 0x00ul ) |
                      SERCOM_I2CS_ADDR_GENCEN // added by JAG

My master code:

#include <Wire.h>

void setup() {

  Serial.begin(9600);
  Serial.println("Sketch start" );

  Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;

void loop() {

  Serial.print("-- Top of loop:" );
  Serial.println( millis() );

  Wire.beginTransmission(0); // transmit to device #8
  Wire.write("x is ");        // sends five bytes
  Wire.write(x);              // sends one byte
  Wire.endTransmission(true);    // stop transmitting


  // delay( 500 );

  uint8_t recvSize = Wire.requestFrom(0, 6);    // request 6 bytes from slave device #8

  Serial.print( "Got bytes: " );
  Serial.print( recvSize );
  Serial.print( "---> ");

  while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    Serial.print( "[") ;
    Serial.print(c);         // print the character
    Serial.print( "]" );
  }
  Serial.println();



  x++;
  delay(500);
}

My slave code:

#include <Wire.h>

void setup() {
  Wire.begin(9);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(requestEvent); // register event
  Serial.begin(9600);           // start serial for output
  Serial.println( "Starting up" );
}

void loop() {
  delay(500);
    Serial.print( "In top of loop (slave): " );
    Serial.println(millis() );
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
  while (1 < Wire.available()) { // loop through all but the last
    char c = Wire.read(); // receive byte as a character
    SerialUSB.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  SerialUSB.println(x);         // print the integer 
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
  Wire.write("hello"); // respond with message of 6 bytes
  // as expected by master
  Serial.println( "<<<< Writing a response." );
}
0

If you broadcast data using Wire.send(data), the slaves would receive this in there onReceive handler but as far as I can remember, the I2C slave will not respond on a Wire.requestFrom(...) broadcast from the master.

Imagine x slaves responding all at the same time to the request...

0

The I2C protocol supports bus arbitration only for masters sending (if more than one master in the bus starts sending at the same time). So, if any slave device would really respond to the General call address 0 with data, the data would geht corrupted if another slave would send data too. With this background it is reasonable, why an I2C slave device wouldn't respond to a request at the General call address.

If you have too many chips in the bus or don't want to address Thema directly due to another reason, you can send a trigger message to the General call address and let the other chips send their data as masters. Keep in mind, that in this case all involved chips must implement correct bus arbitration (and I'm not sure if the Wire library supports this).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.