aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDrashna Jaelre2025-11-11 13:02:35 +0100
committerGitHub2025-11-11 13:02:35 +0100
commit28eeb92f8eec5b8268d2a74ad0561670d14e189a (patch)
tree55e9a33aa1bd678116118da48a103f7ef4365061
parentefc5d63383b64291f25c8377bcfae8178dd63302 (diff)
Add I2C Transmit and Receive function (#25637)
* feat: adds a transmit and receive i2c method * fix: address the i2c transmit and receive length on u16 * Add AVR/LUFA implementation Didn't add a progmem version, since that would only apply to receive. Figured it wasn't worth it, but can add. * Rearrange order of functions * Add docs * Fix doc gen error * Fix lint issues * fix more lint issues
-rw-r--r--docs/drivers/i2c.md25
-rw-r--r--drivers/i2c_master.h15
-rw-r--r--platforms/avr/drivers/i2c_master.c26
-rw-r--r--platforms/chibios/drivers/i2c_master.c6
4 files changed, 72 insertions, 0 deletions
diff --git a/docs/drivers/i2c.md b/docs/drivers/i2c.md
index ad74d0e481..75823c682b 100644
--- a/docs/drivers/i2c.md
+++ b/docs/drivers/i2c.md
@@ -221,6 +221,31 @@ Receive multiple bytes from the selected I2C device.
---
+### `i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout)` {#api-i2c-transmit-and-receive}
+
+Send and receive multiple bytes from the selected I2C device.
+
+#### Arguments {#api-i2c-transmit-and-receive-arguments}
+
+ - `uint8_t address`
+ The 7-bit I2C address of the device.
+ - `const uint8_t* tx_data`
+ A pointer to the data to transmit.
+ - `uint16_t tx_length`
+ The number of bytes to write. Take care not to overrun the length of `tx_data`.
+ - `uint8_t* rx_data`
+ A pointer to a buffer to read into.
+ - `uint16_t rx_length`
+ The number of bytes to read. Take care not to overrun the length of `data`.
+ - `uint16_t timeout`
+ The time in milliseconds to wait for a response from the target device.
+
+#### Return Value {#api-i2c-transmit-and-receive-return}
+
+`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
+
+---
+
### `i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-write-register}
Write to a register with an 8-bit address on the I2C device.
diff --git a/drivers/i2c_master.h b/drivers/i2c_master.h
index dbe1cd42fa..5f6094bc81 100644
--- a/drivers/i2c_master.h
+++ b/drivers/i2c_master.h
@@ -73,6 +73,21 @@ i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t* data, uint16_t lengt
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
/**
+ * \brief Send multiple bytes and then receive multiple bytes from the selected I2C device.
+ *
+ * \param address The 7-bit I2C address of the device.
+ * \param tx_data A pointer to the data to transmit.
+ * \param tx_length The number of bytes to write. Take care not to overrun the length of `tx_data`.
+ * \param rx_data A pointer to a buffer to read into.
+ * \param rx_length The number of bytes to read. Take care not to overrun the length of `rx_data`.
+ * \param timeout The time in milliseconds to wait for a response from the target device.
+ *
+ * \return `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
+ */
+
+i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout);
+
+/**
* \brief Write to a register with an 8-bit address on the I2C device.
*
* \param devaddr The 7-bit I2C address of the device.
diff --git a/platforms/avr/drivers/i2c_master.c b/platforms/avr/drivers/i2c_master.c
index 9136f4a7b9..e5caa995cf 100644
--- a/platforms/avr/drivers/i2c_master.c
+++ b/platforms/avr/drivers/i2c_master.c
@@ -207,6 +207,32 @@ i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16
return (status < 0) ? status : I2C_STATUS_SUCCESS;
}
+i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout) {
+ i2c_status_t status = i2c_start(address | I2C_ACTION_WRITE, timeout);
+
+ for (uint16_t i = 0; i < tx_length && status >= 0; i++) {
+ status = i2c_write(tx_data[i], timeout);
+ }
+
+ for (uint16_t i = 0; i < (rx_length - 1) && status >= 0; i++) {
+ status = i2c_read_ack(timeout);
+ if (status >= 0) {
+ rx_data[i] = status;
+ }
+ }
+
+ if (status >= 0) {
+ status = i2c_read_nack(timeout);
+ if (status >= 0) {
+ rx_data[(rx_length - 1)] = status;
+ }
+ }
+
+ i2c_stop();
+
+ return status;
+}
+
i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
if (status >= 0) {
diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c
index 20850859b5..a44051b82a 100644
--- a/platforms/chibios/drivers/i2c_master.c
+++ b/platforms/chibios/drivers/i2c_master.c
@@ -160,6 +160,12 @@ i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16
return i2c_epilogue(status);
}
+i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout) {
+ i2cStart(&I2C_DRIVER, &i2cconfig);
+ msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (address >> 1), tx_data, tx_length, rx_data, rx_length, TIME_MS2I(timeout));
+ return i2c_epilogue(status);
+}
+
i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
i2cStart(&I2C_DRIVER, &i2cconfig);