diff --git a/libraries/Wire/examples/register_manipulations/register_manipulations.ino b/libraries/Wire/examples/register_manipulations/register_manipulations.ino new file mode 100644 index 000000000..85097c991 --- /dev/null +++ b/libraries/Wire/examples/register_manipulations/register_manipulations.ino @@ -0,0 +1,78 @@ +/* + * Wire_register_manipulations + * + * This is example showing how to read and write to registers of I2C devices. + * + * The example shows: + * 1. Writing byte to register + * 2. Reading byte from register (both blocking and non-blocking) + * 3. Writing byte to register with verification + * 4. Writing data block to registers (useful for FIFO buffers) + * 5. Reading data block from registers (useful for FIFO buffers) + * + * Example is written by Ivan Stefanov on 10 Sep 2023 + */ + +#include + +// Demo is made for USB Type-C port controller IC FUSB302B +#define FUSB302_ADDR (0x22) // FUSB302B I2C address +#define FUSB302_REG_R (0x01) // FUSB302B I2C register read-only +#define FUSB302_REG_RW (0x02) // FUSB302B I2C register read/write + +void setup() { + Wire.begin(); + Wire.setClock(I2C_FAST_SPEED); + delay(100); // I2C device power-up delay + + Serial.begin(115200); + Serial.println("Wire library register manipulation functions example"); + + uint8_t test = 0; + bool dev = false; + + /* Write and read byte from register */ + + // Write byte to device register + Wire.registerWrite(FUSB302_ADDR, FUSB302_REG_RW, 0x64); + Serial.print("Write to read/write register: "); + Serial.println(0x64, HEX); + + // Read(blocking) byte from device register + test = Wire.registerRead(FUSB302_ADDR, FUSB302_REG_RW); + Serial.print("Read read/write register: "); + Serial.println((unsigned int)test, HEX); + + // Write and verify byte to device register + dev = Wire.registerWriteVerify(FUSB302_ADDR, FUSB302_REG_R, 0xC8); + Serial.print("Write 0xC8 to read-only register > success: "); + Serial.println(dev); + + // Read(non-blocking) byte from device register + test = Wire.registerRead(FUSB302_ADDR, FUSB302_REG_R, false); + Serial.print("Read read-only register: "); + Serial.println((unsigned int)test, HEX); + + // Data to be written to register block + uint8_t arr[4] = {0}, dat[4] = {0x91, 0x64, 0xA4, 0x30}; + + /* Write and read 4 byte block */ + + // write data starting from read-only register followed by 3 read/write registers + Wire.registerBlockWrite(FUSB302_ADDR, FUSB302_REG_R, dat, 4); + Serial.print("Block write data: {0x91, 0x64, 0xA4, 0x30}\n"); + + // read data and print to serial monitor + Wire.registerBlockRead(FUSB302_ADDR, FUSB302_REG_R, arr, sizeof(arr)); + Serial.print("Block Read: "); + for (size_t cnt = 0 ; cnt < 4 ; cnt++) { + Serial.print((unsigned int)arr[cnt], HEX); + Serial.print(", "); + } + Serial.print("\n"); +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt index ee1d0acc5..abe50c0c7 100644 --- a/libraries/Wire/keywords.txt +++ b/libraries/Wire/keywords.txt @@ -19,8 +19,17 @@ endTransmission KEYWORD2 requestFrom KEYWORD2 onReceive KEYWORD2 onRequest KEYWORD2 +registerRead KEYWORD2 +registerWrite KEYWORD2 +registerWriteVerify KEYWORD2 +registerBlockRead KEYWORD2 +registerBlockWrite KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### - +I2C_LOW_SPEED LITERAL1 +I2C_STD_SPEED LITERAL1 +I2C_FAST_SPEED LITERAL1 +I2C_FAST_PLUS_SPEED LITERAL1 +I2C_HIGH_SPEED LITERAL1 diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index e19526e87..ae3d32df5 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -1,5 +1,5 @@ name=Wire -version=1.0 +version=1.1 author=Arduino maintainer=Arduino sentence=This library allows you to communicate with I2C and Two Wire Interface devices. diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 001d924df..7928c7674 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -372,6 +372,67 @@ void TwoWire::onRequest( void (*function)(void) ) user_onRequest = function; } +/* Register manipulation functions */ + +// Reading byte from register (both blocking and non-blocking) +uint8_t TwoWire::registerRead(uint8_t addr, uint8_t reg, const bool blocking) { + uint8_t val = 0; + + beginTransmission(addr); + write(reg); + endTransmission(false); + requestFrom((int)addr, (int)1); + if (blocking == true) { + // blocking until data is received + while (available() == 0) {} + } + val = (uint8_t)read(); + endTransmission(true); + + return val; +} + +// Writing byte to register +void TwoWire::registerWrite(uint8_t addr, uint8_t reg, uint8_t val) { + beginTransmission(addr); + write(reg); + write(val); + endTransmission(true); +} + +// Writing byte to register with verification +bool TwoWire::registerWriteVerify(uint8_t addr, uint8_t reg, uint8_t val) { + registerWrite(addr, reg, val); + return (registerRead(addr, reg) == val) ? true : false; +} + +// Reading data block from registers +void TwoWire::registerBlockRead(uint8_t addr, uint8_t reg, uint8_t *data, size_t len, const bool blocking) { + beginTransmission(addr); + write(reg); + endTransmission(false); + requestFrom((int)addr, (int)len); + for (size_t cnt = 0 ; cnt < len ; cnt++) { + // If blocking mode is set check if the next byte is ready for reading after each byte + // If clock stretching support is not needed this check can be moved before the loop for better performance + // by running only once to check if device has started sending the data + if (blocking == true) { + // blocking until data is received + while (available() == 0) {} + } + data[cnt] = (uint8_t)read(); + } + endTransmission(true); +} + +// Writing data block to registers +void TwoWire::registerBlockWrite(uint8_t addr, uint8_t reg, uint8_t *data, size_t len) { + beginTransmission(addr); + write(reg); + write(data, len); + endTransmission(true); +} + // Preinstantiate Objects ////////////////////////////////////////////////////// TwoWire Wire = TwoWire(); diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index e70d72edb..895b70680 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -26,6 +26,13 @@ #include #include "Stream.h" +// I2C standard speeds +#define I2C_LOW_SPEED (10000) // 10kHz +#define I2C_STD_SPEED (100000) // 100kHz +#define I2C_FAST_SPEED (400000) // 400kHz +#define I2C_FAST_PLUS_SPEED (1000000) // 1MHz +#define I2C_HIGH_SPEED (3400000) // 3.4MHz + #define BUFFER_LENGTH 32 // WIRE_HAS_END means Wire has end() @@ -75,6 +82,12 @@ class TwoWire : public Stream virtual void flush(void); void onReceive( void (*)(int) ); void onRequest( void (*)(void) ); + /* Register manipulation functions */ + uint8_t registerRead(uint8_t addr, uint8_t reg, const bool blocking = true); + void registerWrite(uint8_t addr, uint8_t reg, uint8_t val); + bool registerWriteVerify(uint8_t addr, uint8_t reg, uint8_t val); + void registerBlockRead(uint8_t addr, uint8_t reg, uint8_t *data, size_t len, const bool blocking = true); + void registerBlockWrite(uint8_t addr, uint8_t reg, uint8_t *data, size_t len); inline size_t write(unsigned long n) { return write((uint8_t)n); } inline size_t write(long n) { return write((uint8_t)n); }