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." );
}