ArduinoCore-API
ArduinoCore-API copied to clipboard
Suggest adding I2C_writeAnything to Wire library
I have the following small template library on my page about I2C ( http://www.gammon.com.au/i2c ):
template <typename T> unsigned int I2C_writeAnything (const T& value)
{
Wire.write((byte *) &value, sizeof (value));
return sizeof (value);
} // end of I2C_writeAnything
template <typename T> unsigned int I2C_readAnything(T& value)
{
byte * p = (byte*) &value;
unsigned int i;
for (i = 0; i < sizeof value; i++)
*p++ = Wire.read();
return i;
} // end of I2C_readAnything
It has been suggested to me that I request that you include this in the standard Wire library (Wire.h). This lets you more easily send things like floats or structs via I2C. For example:
float fnum = 42.666;
Wire.beginTransmission (SLAVE_ADDRESS);
I2C_writeAnything (fnum);
Wire.endTransmission ();
Being a template function it won't add any bloat unless you actually use it.
Related request: https://github.com/arduino/Arduino/issues/3692
A note must be added that only ONE write operation can be used inside of the onRequestEvent()
callback. Since the current Wire library resets the twi_txBufferLength
value inside ..\library\Wire\utility\twi.c during the onRequestEvent()
callback.
uint8_t twi_transmit(const uint8_t* data, uint8_t length){
// stuff
twi_txBufferLength = length;
// stuff
}
Which is call from ..\library\Wire.cpp
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
if(transmitting){
// in master transmitter mode
for(size_t i = 0; i < quantity; ++i){
write(data[i]);
}
}else{
// in slave send mode
// reply to master
twi_transmit(data, quantity);
}
return quantity;
}
The boolean transmitting
is false while in slave mode.
Chuck.
Quite right, which is why I changed I2C_writeAnything
to do a single write and not byte-by-byte. But of course you need to alert the end-user to only call that (I2C_writeAnything) once in a request event. However the point of it in the first place is that it simplifies sending (and receiving) a struct.
I like your coding, I was just recommending that the Single write restriction should be prominently marked, or the underlying code fixed. It is a sore point for me.
I have customized Wire to support repeated calls to onRequestEvent()
to allow Slave mode Arduino I2C to function like 24LCxx series EEPROMs, and added bus failure timeouts. But these fixes are deemed too confusing for novice usage.
Personally, I think that a more complex function is easier to use:
enum STAGE { twi_reStart,twi_start};
void onRequestEvent(STAGE stage){// just use a single byte Wire.write() to support unlimited lengths
switch(stage){
twi_start : ; // slave read bare, no register address set, Start from begining
twi_reStart : ; // slave read, continue from prior register address
}
}
this coding will support
Wire.begin(addr);
Wire.write(z);//register address
Wire.endTransmission(false); // set register address (z)
Wire.requestFrom(addr,x,false); // read from (z) for (x) bytes
Wire.requestFrom(addr,xmore,false); // read from (z+x) for (xmore) bytes
Wire.requestFrom(addr,xevenmore,true); // read from (z+x+xmore) for (xevenmore) bytes, and end transaction
//and now that a stop has been issued on the I2C buss
Wire.requestFrom(addr,x,false); // start reading from address (0), controlled by twi_start Case of onRequestevent()
Wire.requestFrom(addr,xmore,true); // read from (0+x) for (xmore) bytes.
To me this added complexity makes it easier for a novice to effectively uses I2C slave mode to transfer more than one value.
Chuck.
or the underlying code fixed
Quite possibly however that goes outside the scope of this particular change request. :)
A note must be added that only ONE write operation can be used inside of the onRequestEvent()
I just discovered this. But this just further supports adding @nickgammon's template since it allows one to do:
uint16_t temps[6];
...
I2C_writeAnything(temps);
to very easily send 6 uint16_t
s.
It's also worth pointing out that there are 153 "code result" matches on GitHub of use of I2C_writeAnything()
. It's very popular!
Some of them use the older version which does multiple writes. Oh well. :(
My code for I2C_Anything is now on GitHub:
https://github.com/nickgammon/I2C_Anything