~ruther/qmk_firmware

bc1f5ef38172bc77a802fb779e5da60f800c231b — Ryan 3 years ago 875e44f
i2c_master: Add support for reading/writing to 16-bit registers (#14289)

M docs/i2c_driver.md => docs/i2c_driver.md +46 -2
@@ 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.

M platforms/avr/drivers/i2c_master.c => platforms/avr/drivers/i2c_master.c +56 -0
@@ 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);

M platforms/avr/drivers/i2c_master.h => platforms/avr/drivers/i2c_master.h +2 -0
@@ 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);

M platforms/chibios/drivers/i2c_master.c => platforms/chibios/drivers/i2c_master.c +24 -1
@@ 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); }

M platforms/chibios/drivers/i2c_master.h => platforms/chibios/drivers/i2c_master.h +2 -0
@@ 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);