// ------------------------------------------------------------------------------------------- // I2C Advanced Slave // ------------------------------------------------------------------------------------------- // // This creates an I2C slave device with simple read/write commands and a small // addressable memory. Note that this communication adds a protocol layer on top of // normal I2C read/write procedures. As such, it is meant to pair with the advanced_master // sketch. The read/write commands are described below. // // For basic I2C communication only, refer to basic_master and basic_slave example sketches. // // This example code is in the public domain. // // ------------------------------------------------------------------------------------------- // WRITE - The I2C Master can write to the device by transmitting the WRITE command, // a memory address to store to, and a sequence of data to store. // The command sequence is: // // START|I2CADDR+W|WRITE|MEMADDR|DATA0|DATA1|DATA2|...|STOP // // where START = I2C START sequence // I2CADDR+W = I2C Slave address + I2C write flag // WRITE = WRITE command // MEMADDR = memory address to store data to // DATAx = data byte to store, multiple bytes are stored to increasing address // STOP = I2C STOP sequence // ------------------------------------------------------------------------------------------- // READ - The I2C Master can read data from the device by transmitting the READ command, // a memory address to read from, and then issuing a STOP/START or Repeated-START, // followed by reading the data. The command sequence is: // // START|I2CADDR+W|READ|MEMADDR|REPSTART|I2CADDR+R|DATA0|DATA1|DATA2|...|STOP // // where START = I2C START sequence // I2CADDR+W = I2C Slave address + I2C write flag // READ = READ command // MEMADDR = memory address to read data from // REPSTART = I2C Repeated-START sequence (or STOP/START if single Master) // I2CADDR+R = I2C Slave address + I2C read flag // DATAx = data byte read by Master, multiple bytes are read from increasing address // STOP = I2C STOP sequence // ------------------------------------------------------------------------------------------- // SETRATE - The I2C Master can adjust the Slave configured I2C rate with this command // The command sequence is: // // START|I2CADDR+W|SETRATE|RATE0|RATE1|RATE2|RATE3|STOP // // where START = I2C START sequence // I2CADDR+W = I2C Slave address + I2C write flag // SETRATE = SETRATE command // RATE0-3 = I2C frequency (uint32_t) LSB-to-MSB format // ------------------------------------------------------------------------------------------- #include // Command definitions #define WRITE 0x10 #define READ 0x20 #define SETRATE 0x30 // Function prototypes void receiveEvent(size_t count); void requestEvent(void); // Memory #define MEM_LEN 256 uint8_t mem[MEM_LEN]; volatile uint8_t cmd; volatile size_t addr; volatile uint32_t rate; // // Setup // void setup() { pinMode(LED_BUILTIN,OUTPUT); // LED // Setup for Slave mode, address 0x44, pins 18/19, external pullups, 400kHz Wire.begin(I2C_SLAVE, 0x44, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000); // init vars cmd = 0; addr = 0; memset(mem, 0, sizeof(mem)); rate = 400000; // register events Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); Serial.begin(115200); } void loop() { digitalWrite(LED_BUILTIN,HIGH); // double pulse LED while waiting for I2C requests delay(10); // if the LED stops the slave is probably stuck in an ISR digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(10); digitalWrite(LED_BUILTIN,LOW); delay(880); } // // handle Rx Event (incoming I2C request/data) // void receiveEvent(size_t count) { if(count) { // grab command cmd = Wire.readByte(); switch(cmd) { case WRITE: addr = Wire.readByte(); // grab addr Wire.read(&mem[addr], count-2); // copy Rx data to databuf break; case READ: addr = Wire.readByte(); // grab addr break; case SETRATE: if(Wire.available() >= 4) { rate = Wire.readByte(); // grab rate rate |= Wire.readByte() << 8; rate |= Wire.readByte() << 16; rate |= Wire.readByte() << 24; Wire.setClock(rate); // set rate } break; } } } // // handle Tx Event (outgoing I2C data) // void requestEvent(void) { switch(cmd) { case READ: Wire.write(&mem[addr], MEM_LEN-addr); // fill Tx buffer (from addr location to end of mem) break; } }