Skip to content

Commit dfcbcb5

Browse files
Add I2C device register manipulation functions
Add register manipulation functions and macros for the standard I2C clock speeds to the `Wire` library. `Wire` library version number change from `1.0` to `1.1`. This is meant to be used for I2C sensors and devices which have internal registers. Library example named `register_manipulations` with all the new functionality is also added.
1 parent 6309212 commit dfcbcb5

File tree

5 files changed

+163
-2
lines changed

5 files changed

+163
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Wire_register_manipulations
3+
*
4+
* This is example showing how to read and write to registers of I2C devices.
5+
*
6+
* The example shows:
7+
* 1. Writing byte to register
8+
* 2. Reading byte from register (both blocking and non-blocking)
9+
* 3. Writing byte to register with verification
10+
* 4. Writing data block to registers (useful for FIFO buffers)
11+
* 5. Reading data block from registers (useful for FIFO buffers)
12+
*
13+
* Example is writen by Ivan Stefanov on 10 Sep 2023
14+
*/
15+
16+
#include <Wire.h>
17+
18+
// Demo is made for USB Type-C port controller IC FUSB302B
19+
#define FUSB302_ADDR (0x22) // FUSB302B I2C address
20+
#define FUSB302_REG_R (0x01) // FUSB302B I2C register read-only
21+
#define FUSB302_REG_RW (0x02) // FUSB302B I2C register read/write
22+
23+
void setup() {
24+
Wire.begin();
25+
Wire.setClock(I2C_FAST_SPEED);
26+
delay(100); // I2C device power-up delay
27+
28+
Serial.begin(115200);
29+
Serial.println("Wire library register manipulation functions example");
30+
31+
uint8_t test = 0;
32+
bool dev = false;
33+
34+
/* Write and read byte from register */
35+
36+
// Write byte to device register
37+
Wire.registerWrite(FUSB302_ADDR, FUSB302_REG_RW, 0x64);
38+
Serial.print("Write to read/write register: ");
39+
Serial.println(0x64, HEX);
40+
41+
// Read(blocking) byte from device register
42+
test = Wire.registerRead(FUSB302_ADDR, FUSB302_REG_RW);
43+
Serial.print("Read read/write register: ");
44+
Serial.println((unsigned int)test, HEX);
45+
46+
// Write and verify byte to device register
47+
dev = Wire.registerWriteVerify(FUSB302_ADDR, FUSB302_REG_R, 0xC8);
48+
Serial.print("Write 0xC8 to read-only register > success: ");
49+
Serial.println(dev);
50+
51+
// Read(non-blocking) byte from device register
52+
test = Wire.registerRead(FUSB302_ADDR, FUSB302_REG_R, false);
53+
Serial.print("Read read-only register: ");
54+
Serial.println((unsigned int)test, HEX);
55+
56+
// Data to be writen to register block
57+
uint8_t arr[4] = {0}, dat[4] = {0x91, 0x64, 0xA4, 0x30};
58+
59+
/* Write and read 4 byte block */
60+
61+
// write data starting from read-only register followed by 3 read/write registers
62+
Wire.registerBlockWrite(FUSB302_ADDR, FUSB302_REG_R, dat, 4);
63+
Serial.print("Block write data: {0x91, 0x64, 0xA4, 0x30}\n");
64+
65+
// read data and print to serial monitor
66+
Wire.registerBlockRead(FUSB302_ADDR, FUSB302_REG_R, arr, sizeof(arr));
67+
Serial.print("Block Read: ");
68+
for (size_t cnt = 0 ; cnt < 4 ; cnt++) {
69+
Serial.print((unsigned int)arr[cnt], HEX);
70+
Serial.print(", ");
71+
}
72+
Serial.print("\n");
73+
}
74+
75+
void loop() {
76+
// put your main code here, to run repeatedly:
77+
78+
}

Diff for: libraries/Wire/keywords.txt

+10-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@ endTransmission KEYWORD2
1919
requestFrom KEYWORD2
2020
onReceive KEYWORD2
2121
onRequest KEYWORD2
22+
registerRead KEYWORD2
23+
registerWrite KEYWORD2
24+
registerWriteVerify KEYWORD2
25+
registerBlockRead KEYWORD2
26+
registerBlockWrite KEYWORD2
2227

2328
#######################################
2429
# Constants (LITERAL1)
2530
#######################################
26-
31+
I2C_LOW_SPEED LITERAL1
32+
I2C_STD_SPEED LITERAL1
33+
I2C_FAST_SPEED LITERAL1
34+
I2C_FAST_PLUS_SPEED LITERAL1
35+
I2C_HIGH_SPEED LITERAL1

Diff for: libraries/Wire/library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Wire
2-
version=1.0
2+
version=1.1
33
author=Arduino
44
maintainer=Arduino <[email protected]>
55
sentence=This library allows you to communicate with I2C and Two Wire Interface devices.

Diff for: libraries/Wire/src/Wire.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,67 @@ void TwoWire::onRequest( void (*function)(void) )
372372
user_onRequest = function;
373373
}
374374

375+
/* Register manipulation functions */
376+
377+
// Reading byte from register (both blocking and non-blocking)
378+
uint8_t TwoWire::registerRead(uint8_t addr, uint8_t reg, const bool blocking) {
379+
uint8_t val = 0;
380+
381+
beginTransmission(addr);
382+
write(reg);
383+
endTransmission(false);
384+
requestFrom((int)addr, (int)1);
385+
if (blocking == true) {
386+
// blocking until data is received
387+
while (available() == 0) {}
388+
}
389+
val = (uint8_t)read();
390+
endTransmission(true);
391+
392+
return val;
393+
}
394+
395+
// Writing byte to register
396+
void TwoWire::registerWrite(uint8_t addr, uint8_t reg, uint8_t val) {
397+
beginTransmission(addr);
398+
write(reg);
399+
write(val);
400+
endTransmission(true);
401+
}
402+
403+
// Writing byte to register with verification
404+
bool TwoWire::registerWriteVerify(uint8_t addr, uint8_t reg, uint8_t val) {
405+
registerWrite(addr, reg, val);
406+
return (registerRead(addr, reg) == val) ? true : false;
407+
}
408+
409+
// Reading data block from registers
410+
void TwoWire::registerBlockRead(uint8_t addr, uint8_t reg, uint8_t *data, size_t len, const bool blocking) {
411+
beginTransmission(addr);
412+
write(reg);
413+
endTransmission(false);
414+
requestFrom((int)addr, (int)len);
415+
for (size_t cnt = 0 ; cnt < len ; cnt++) {
416+
// If blocking mode is set check if the next byte is ready for reading after each byte
417+
// If clock stretching support is not needed this check can be moved before the loop for better performance
418+
// by running only once to check if device has started sending the data
419+
if (blocking == true) {
420+
// blocking until data is received
421+
while (available() == 0) {}
422+
}
423+
data[cnt] = (uint8_t)read();
424+
}
425+
endTransmission(true);
426+
}
427+
428+
// Writing data block to registers
429+
void TwoWire::registerBlockWrite(uint8_t addr, uint8_t reg, uint8_t *data, size_t len) {
430+
beginTransmission(addr);
431+
write(reg);
432+
write(data, len);
433+
endTransmission(true);
434+
}
435+
375436
// Preinstantiate Objects //////////////////////////////////////////////////////
376437

377438
TwoWire Wire = TwoWire();

Diff for: libraries/Wire/src/Wire.h

+13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@
2626
#include <inttypes.h>
2727
#include "Stream.h"
2828

29+
// I2C standard speeds
30+
#define I2C_LOW_SPEED (10000) // 10kHz
31+
#define I2C_STD_SPEED (100000) // 100kHz
32+
#define I2C_FAST_SPEED (400000) // 400kHz
33+
#define I2C_FAST_PLUS_SPEED (1000000) // 1MHz
34+
#define I2C_HIGH_SPEED (3400000) // 3.4MHz
35+
2936
#define BUFFER_LENGTH 32
3037

3138
// WIRE_HAS_END means Wire has end()
@@ -75,6 +82,12 @@ class TwoWire : public Stream
7582
virtual void flush(void);
7683
void onReceive( void (*)(int) );
7784
void onRequest( void (*)(void) );
85+
/* Register manipulation functions */
86+
uint8_t registerRead(uint8_t addr, uint8_t reg, const bool blocking = true);
87+
void registerWrite(uint8_t addr, uint8_t reg, uint8_t val);
88+
bool registerWriteVerify(uint8_t addr, uint8_t reg, uint8_t val);
89+
void registerBlockRead(uint8_t addr, uint8_t reg, uint8_t *data, size_t len, const bool blocking = true);
90+
void registerBlockWrite(uint8_t addr, uint8_t reg, uint8_t *data, size_t len);
7891

7992
inline size_t write(unsigned long n) { return write((uint8_t)n); }
8093
inline size_t write(long n) { return write((uint8_t)n); }

0 commit comments

Comments
 (0)