I got an Arduino Uno set up as an I2C master to an ATtiny85 slave, using the Wire (Master) and TinyWireS (Slave) libraries.
Communication works well. I have been able to keep the network running correctly for hours. However, I have not been able to let the master request more than a single byte from the slave.
Using the code below the master asks for 4 bytes from the slave, but in my serial console I get only an actual value for the first bytes. The next three bytes read 255.
How can I request multiple bytes from the slave, using the Wire library?
Master (Arduino Uno)
#include <Wire.h>
#define I2C_MASTER_ADDR 0x04
#define I2C_SLAVE_ADDR 0x05
int pollInterval = 700;//Milliseconds
unsigned long lastPoll = 0;
void setup()
{
Wire.begin(I2C_MASTER_ADDR); // join i2c bus
Serial.begin(115200);
Serial.println("Setup complete");
}
/*
* The main loop
*/
int i = 0;
void loop()
{
//Writing to the slave
if( (millis()-lastPoll) > pollInterval)
{
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(0x01);//Register to start at
switch(i)
{
case 0:
Wire.write(255);
Wire.write(0);
Wire.write(0);
i++;
break;
case 1:
Wire.write(0);
Wire.write(255);
Wire.write(0);
i++;
break;
case 2:
Wire.write(0);
Wire.write(0);
Wire.write(255);
i = 0;
break;
}
Wire.endTransmission();
delay(1);//Dont let the slave panic
//Set the register pointer back to 0x01, preparing for a read
Wire.beginTransmission(I2C_SLAVE_ADDR);
Wire.write(0x00);//Register to start at
Wire.endTransmission();
delay(1);//Dont let the slave panic
//Get values from the three registers up from 0x01
Wire.requestFrom(I2C_SLAVE_ADDR, 4);//Request N bytes
while (Wire.available())
{
uint8_t next_byte = Wire.read();
Serial.print(next_byte);Serial.print(" ");
}
Serial.println("\n");
lastPoll = millis();
}//End if time to poll again
}//End loop
Slave - ATTiny85
#include <EEPROM.h>
#include <TinyWireS.h>
#include <Bounce2.h>
#include <WS2812.h>
#ifdef __AVR__ //Which will be true for ATtiny85
#include <avr/power.h>
#endif
#define I2C_SLAVE_DEFAULT_ADDR 0x05
#define BUTTON_DEBOUNCE 5//Debounce milliseconds
#define NEOPIXEL_PIN 1
#define BUTTON_PIN 3
#define NUMPIXELS 1
/*
* I2C Registers
*
* Register map:
* 0x00 - Button state
* 0x01 - led value red
* 0x02 - led value green
* 0x03 - led value blue
*
* Total size: 4
*/
const byte reg_size = 4;
volatile uint16_t i2c_regs[reg_size];
/*
* Internal variables
*/
cRGB value;
volatile boolean led_needs_update = false;
volatile byte reg_position;
/*
* Initialize instances/classes
*/
Bounce button = Bounce();
WS2812 led(NUMPIXELS);
void setup()
{
//Start I2C
//uint8_t _device_addr = EEPROM_DATA::get_device_addr();
TinyWireS.begin(I2C_SLAVE_DEFAULT_ADDR);
TinyWireS.onReceive(i2cReceiveEvent);
TinyWireS.onRequest(i2cRequestEvent);
//Start Led
led.setOutput(NEOPIXEL_PIN);
value.b = 255; value.g = 0; value.r = 0;
led.set_crgb_at(0, value); //Set value at LED found at index 0
led.sync(); // Sends the value to the LED
//Start Button
pinMode(BUTTON_PIN, INPUT_PULLUP);
button.attach(BUTTON_PIN);
button.interval(BUTTON_DEBOUNCE);
}
void loop()
{
button.update();
if(led_needs_update)
{
led_update();
led_needs_update = false;
}
if(button.fell())
{
i2c_regs[0x00] = true;
}
if(button.rose())
{
i2c_regs[0x00] = false;
}
// This needs to be here for the TinyWireS lib
TinyWireS_stop_check();
}
/*
* I2C Handelers
*/
void i2cReceiveEvent(uint8_t howMany)
{
if (howMany < 1)
{
return;// Sanity-check
}
reg_position = TinyWireS.receive();
howMany--;
if (!howMany)
{
return;// This write was only to set the buffer for next read
}
while(howMany--)
{
//Store the recieved data in the currently selected register
i2c_regs[reg_position] = TinyWireS.receive();
//Proceed to the next register
reg_position++;
if (reg_position >= reg_size)
{
reg_position = 0;
}
}
led_needs_update = true;
}//End i2cReceiveEvent()
void i2cRequestEvent()
{
//Send the value on the current register position
TinyWireS.send(i2c_regs[reg_position]);
// Increment the reg position on each read, and loop back to zero
reg_position++;
if (reg_position >= reg_size)
{
reg_position = 0;
}
}//End i2cRequestEvent
/*
* Helper functions
*/
void led_update()
{
cRGB val;
val.r = i2c_regs[0x01];
val.g = i2c_regs[0x02];
val.b = i2c_regs[0x03];
led.set_crgb_at(0, val);
led.sync(); // Sends the value to the LED
}