Hi there!
I really like the idea to create my own i2c devices communicating with a master. I found some tutorials but I do have a question with the timing when the chip does its thing in the loop and the onRequest/onRecieve events.
I have this very simple Attiny85 i2c device with a photoresistor that I would like to read its value via i2c which works so far.
Code (Master, library methods):
void SCi2cLDR::refresh()
{
int i=0;
byte buf[2];
Wire.requestFrom(deviceAddress, 2);
while (Wire.available())
{
buf[i] = Wire.read();
i++;
}
byte tmp[] = {buf[0],buf[1]};
lightIntensity = bytesToUInt16(tmp);
}
int SCi2cLDR::bytesToUInt16(byte b[])
{
int outVal = b[1] << 8;
outVal = outVal + b[0];
return outVal;
}
Code (Slave on ATTiny85):
#include <TinyWireS.h>
#define I2C_ADDRESS 0x40
#define PIN_LDR A3
int REGISTER_SIZE = 2;
int REGISTER_POINTER = 0;
byte REGISTERS[] =
{
0x00,
0x00,
};
void setup()
{
pinMode(PIN_LDR,INPUT);
TinyWireS.begin(I2C_ADDRESS);
TinyWireS.onRequest(requestEvent);
}
void loop()
{
TinyWireS_stop_check();
}
void requestEvent()
{
if (REGISTER_POINTER == 0)
{
readSensor();
}
TinyWireS.send(REGISTERS[REGISTER_POINTER]);
REGISTER_POINTER++;
if (REGISTER_POINTER >= REGISTER_SIZE)
{
REGISTER_POINTER = 0;
}
}
void readSensor()
{
int value = analogRead(PIN_LDR);
REGISTERS[0] = value >> 8;
REGISTERS[1] = value & 0xFF;
}
As you can see Im converting the analogRead integer value to 2 bytes and write it to the register array on the tiny exactly when the requestEvent() is called. I dont think this is good practice...
The code here works but I have one question:
Is it okay to do the reading/refresh of the LDR value in the requestEvent()? As far as I understand i2c is quite timing critical and I want to have clean code for future i2c devices where the update/refresh of its sensor values could take more time and confuse the i2c timing maybe.
I moved the readSensors() method in the loop so the ATTiny firmware looks like this:
void loop()
{
readSensor();
TinyWireS_stop_check();
}
void requestEvent()
{
TinyWireS.send(REGISTERS[REGISTER_POINTER]);
REGISTER_POINTER++;
if (REGISTER_POINTER >= REGISTER_SIZE)
{
REGISTER_POINTER = 0;
}
}
Which gives me gibberish and I suspect that this is due the timing of i2c and I think that the requestEvent() gets called maybe between readings and in one buffer is the old value and the new value in the other.
So in a nutshell:
When is the best time to read the sensors and write it in the register without interfering the i2c protocol?
Thanks in advance!