Skip to content

Commit bc1f5ef

Browse files
authored
i2c_master: Add support for reading/writing to 16-bit registers (#14289)
1 parent 875e44f commit bc1f5ef

File tree

5 files changed

+130
-3
lines changed

5 files changed

+130
-3
lines changed

docs/i2c_driver.md

+46-2
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ Receive multiple bytes from the selected SPI device.
187187

188188
### `i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
189189

190-
Writes to a register on the I2C device.
190+
Writes to a register with an 8-bit address on the I2C device.
191191

192192
#### Arguments
193193

@@ -208,9 +208,32 @@ Writes to a register on the I2C device.
208208

209209
---
210210

211+
### `i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
212+
213+
Writes to a register with a 16-bit address (big endian) on the I2C device.
214+
215+
#### Arguments
216+
217+
- `uint8_t devaddr`
218+
The 7-bit I2C address of the device.
219+
- `uint16_t regaddr`
220+
The register address to write to.
221+
- `uint8_t *data`
222+
A pointer to the data to transmit.
223+
- `uint16_t length`
224+
The number of bytes to write. Take care not to overrun the length of `data`.
225+
- `uint16_t timeout`
226+
The time in milliseconds to wait for a response from the target device.
227+
228+
#### Return Value
229+
230+
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
231+
232+
---
233+
211234
### `i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
212235

213-
Reads from a register on the I2C device.
236+
Reads from a register with an 8-bit address on the I2C device.
214237

215238
#### Arguments
216239

@@ -229,6 +252,27 @@ Reads from a register on the I2C device.
229252

230253
---
231254

255+
### `i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
256+
257+
Reads from a register with a 16-bit address (big endian) on the I2C device.
258+
259+
#### Arguments
260+
261+
- `uint8_t devaddr`
262+
The 7-bit I2C address of the device.
263+
- `uint16_t regaddr`
264+
The register address to read from.
265+
- `uint16_t length`
266+
The number of bytes to read. Take care not to overrun the length of `data`.
267+
- `uint16_t timeout`
268+
The time in milliseconds to wait for a response from the target device.
269+
270+
#### Return Value
271+
272+
`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
273+
274+
---
275+
232276
### `i2c_status_t i2c_stop(void)`
233277

234278
Stop the current I2C transaction.

platforms/avr/drivers/i2c_master.c

+56
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,25 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
202202
return status;
203203
}
204204

205+
i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
206+
i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
207+
if (status >= 0) {
208+
status = i2c_write(regaddr >> 8, timeout);
209+
210+
if (status >= 0) {
211+
status = i2c_write(regaddr & 0xFF, timeout);
212+
213+
for (uint16_t i = 0; i < length && status >= 0; i++) {
214+
status = i2c_write(data[i], timeout);
215+
}
216+
}
217+
}
218+
219+
i2c_stop();
220+
221+
return status;
222+
}
223+
205224
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
206225
i2c_status_t status = i2c_start(devaddr, timeout);
207226
if (status < 0) {
@@ -235,6 +254,43 @@ i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16
235254
return (status < 0) ? status : I2C_STATUS_SUCCESS;
236255
}
237256

257+
i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
258+
i2c_status_t status = i2c_start(devaddr, timeout);
259+
if (status < 0) {
260+
goto error;
261+
}
262+
263+
status = i2c_write(regaddr >> 8, timeout);
264+
if (status < 0) {
265+
goto error;
266+
}
267+
status = i2c_write(regaddr & 0xFF, timeout);
268+
if (status < 0) {
269+
goto error;
270+
}
271+
272+
status = i2c_start(devaddr | 0x01, timeout);
273+
274+
for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
275+
status = i2c_read_ack(timeout);
276+
if (status >= 0) {
277+
data[i] = status;
278+
}
279+
}
280+
281+
if (status >= 0) {
282+
status = i2c_read_nack(timeout);
283+
if (status >= 0) {
284+
data[(length - 1)] = status;
285+
}
286+
}
287+
288+
error:
289+
i2c_stop();
290+
291+
return (status < 0) ? status : I2C_STATUS_SUCCESS;
292+
}
293+
238294
void i2c_stop(void) {
239295
// transmit STOP condition
240296
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

platforms/avr/drivers/i2c_master.h

+2
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,7 @@ int16_t i2c_read_nack(uint16_t timeout);
3939
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
4040
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
4141
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
42+
i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
4243
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
44+
i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
4345
void i2c_stop(void);

platforms/chibios/drivers/i2c_master.c

+24-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
102102
i2cStart(&I2C_DRIVER, &i2cconfig);
103103

104104
uint8_t complete_packet[length + 1];
105-
for (uint8_t i = 0; i < length; i++) {
105+
for (uint16_t i = 0; i < length; i++) {
106106
complete_packet[i + 1] = data[i];
107107
}
108108
complete_packet[0] = regaddr;
@@ -111,11 +111,34 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
111111
return chibios_to_qmk(&status);
112112
}
113113

114+
i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
115+
i2c_address = devaddr;
116+
i2cStart(&I2C_DRIVER, &i2cconfig);
117+
118+
uint8_t complete_packet[length + 2];
119+
for (uint16_t i = 0; i < length; i++) {
120+
complete_packet[i + 2] = data[i];
121+
}
122+
complete_packet[0] = regaddr >> 8;
123+
complete_packet[1] = regaddr & 0xFF;
124+
125+
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout));
126+
return chibios_to_qmk(&status);
127+
}
128+
114129
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
115130
i2c_address = devaddr;
116131
i2cStart(&I2C_DRIVER, &i2cconfig);
117132
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), &regaddr, 1, data, length, TIME_MS2I(timeout));
118133
return chibios_to_qmk(&status);
119134
}
120135

136+
i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
137+
i2c_address = devaddr;
138+
i2cStart(&I2C_DRIVER, &i2cconfig);
139+
uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF};
140+
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), &register_packet, 2, data, length, TIME_MS2I(timeout));
141+
return chibios_to_qmk(&status);
142+
}
143+
121144
void i2c_stop(void) { i2cStop(&I2C_DRIVER); }

platforms/chibios/drivers/i2c_master.h

+2
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,7 @@ i2c_status_t i2c_start(uint8_t address);
9696
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
9797
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
9898
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
99+
i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
99100
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
101+
i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
100102
void i2c_stop(void);

0 commit comments

Comments
 (0)