소스 검색

i2c_master: Add support for reading/writing to 16-bit registers (#14289)

Ryan 3 년 전
부모
커밋
bc1f5ef381
5개의 변경된 파일130개의 추가작업 그리고 3개의 파일을 삭제
  1. 46 2
      docs/i2c_driver.md
  2. 56 0
      platforms/avr/drivers/i2c_master.c
  3. 2 0
      platforms/avr/drivers/i2c_master.h
  4. 24 1
      platforms/chibios/drivers/i2c_master.c
  5. 2 0
      platforms/chibios/drivers/i2c_master.h

+ 46 - 2
docs/i2c_driver.md

@@ -187,7 +187,7 @@ Receive multiple bytes from the selected SPI device.
 
 ### `i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
 
-Writes to a register on the I2C device.
+Writes to a register with an 8-bit address on the I2C device.
 
 #### Arguments
 
@@ -208,9 +208,32 @@ Writes to a register on the I2C device.
 
 ---
 
+### `i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
+
+Writes to a register with a 16-bit address (big endian) on the I2C device.
+
+#### Arguments
+
+ - `uint8_t devaddr`  
+   The 7-bit I2C address of the device.
+ - `uint16_t regaddr`  
+   The register address to write to.
+ - `uint8_t *data`  
+   A pointer to the data to transmit.
+ - `uint16_t length`  
+ The number of bytes to write. 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
+
+`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
+
+---
+
 ### `i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
 
-Reads from a register on the I2C device.
+Reads from a register with an 8-bit address on the I2C device.
 
 #### Arguments
 
@@ -229,6 +252,27 @@ Reads from a register on the I2C device.
 
 ---
 
+### `i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)`
+
+Reads from a register with a 16-bit address (big endian) on the I2C device.
+
+#### Arguments
+
+ - `uint8_t devaddr`  
+   The 7-bit I2C address of the device.
+ - `uint16_t regaddr`  
+   The register address to read from.
+ - `uint16_t 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
+
+`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
+
+---
+
 ### `i2c_status_t i2c_stop(void)`
 
 Stop the current I2C transaction.

+ 56 - 0
platforms/avr/drivers/i2c_master.c

@@ -202,6 +202,25 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
     return status;
 }
 
+i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
+    i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
+    if (status >= 0) {
+        status = i2c_write(regaddr >> 8, timeout);
+
+        if (status >= 0) {
+            status = i2c_write(regaddr & 0xFF, timeout);
+
+            for (uint16_t i = 0; i < length && status >= 0; i++) {
+                status = i2c_write(data[i], timeout);
+            }
+        }
+    }
+
+    i2c_stop();
+
+    return status;
+}
+
 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
     i2c_status_t status = i2c_start(devaddr, timeout);
     if (status < 0) {
@@ -235,6 +254,43 @@ error:
     return (status < 0) ? status : I2C_STATUS_SUCCESS;
 }
 
+i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
+    i2c_status_t status = i2c_start(devaddr, timeout);
+    if (status < 0) {
+        goto error;
+    }
+
+    status = i2c_write(regaddr >> 8, timeout);
+    if (status < 0) {
+        goto error;
+    }
+    status = i2c_write(regaddr & 0xFF, timeout);
+    if (status < 0) {
+        goto error;
+    }
+
+    status = i2c_start(devaddr | 0x01, timeout);
+
+    for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
+        status = i2c_read_ack(timeout);
+        if (status >= 0) {
+            data[i] = status;
+        }
+    }
+
+    if (status >= 0) {
+        status = i2c_read_nack(timeout);
+        if (status >= 0) {
+            data[(length - 1)] = status;
+        }
+    }
+
+error:
+    i2c_stop();
+
+    return (status < 0) ? status : I2C_STATUS_SUCCESS;
+}
+
 void i2c_stop(void) {
     // transmit STOP condition
     TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);

+ 2 - 0
platforms/avr/drivers/i2c_master.h

@@ -39,5 +39,7 @@ int16_t      i2c_read_nack(uint16_t timeout);
 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
+i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
+i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
 void         i2c_stop(void);

+ 24 - 1
platforms/chibios/drivers/i2c_master.c

@@ -102,7 +102,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
     i2cStart(&I2C_DRIVER, &i2cconfig);
 
     uint8_t complete_packet[length + 1];
-    for (uint8_t i = 0; i < length; i++) {
+    for (uint16_t i = 0; i < length; i++) {
         complete_packet[i + 1] = data[i];
     }
     complete_packet[0] = regaddr;
@@ -111,6 +111,21 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
     return chibios_to_qmk(&status);
 }
 
+i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
+    i2c_address = devaddr;
+    i2cStart(&I2C_DRIVER, &i2cconfig);
+
+    uint8_t complete_packet[length + 2];
+    for (uint16_t i = 0; i < length; i++) {
+        complete_packet[i + 2] = data[i];
+    }
+    complete_packet[0] = regaddr >> 8;
+    complete_packet[1] = regaddr & 0xFF;
+
+    msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout));
+    return chibios_to_qmk(&status);
+}
+
 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
     i2c_address = devaddr;
     i2cStart(&I2C_DRIVER, &i2cconfig);
@@ -118,4 +133,12 @@ i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16
     return chibios_to_qmk(&status);
 }
 
+i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
+    i2c_address = devaddr;
+    i2cStart(&I2C_DRIVER, &i2cconfig);
+    uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF};
+    msg_t   status             = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), &register_packet, 2, data, length, TIME_MS2I(timeout));
+    return chibios_to_qmk(&status);
+}
+
 void i2c_stop(void) { i2cStop(&I2C_DRIVER); }

+ 2 - 0
platforms/chibios/drivers/i2c_master.h

@@ -96,5 +96,7 @@ i2c_status_t i2c_start(uint8_t address);
 i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
+i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
 i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
+i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
 void         i2c_stop(void);