Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add I2C device register manipulation functions #543

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 <Wire.h>

// 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:

}
11 changes: 10 additions & 1 deletion libraries/Wire/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion libraries/Wire/library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=Wire
version=1.0
version=1.1
author=Arduino
maintainer=Arduino <info@arduino.cc>
sentence=This library allows you to communicate with I2C and Two Wire Interface devices.
Expand Down
61 changes: 61 additions & 0 deletions libraries/Wire/src/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
13 changes: 13 additions & 0 deletions libraries/Wire/src/Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
#include <inttypes.h>
#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()
Expand Down Expand Up @@ -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); }
Expand Down
Loading