Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Core] Chibios: Stop I2C peripheral on transaction error #17798

Merged
merged 1 commit into from
Jul 26, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions platforms/chibios/drivers/i2c_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,25 @@ static const I2CConfig i2cconfig = {
#endif
};

static i2c_status_t chibios_to_qmk(const msg_t* status) {
switch (*status) {
case I2C_NO_ERROR:
return I2C_STATUS_SUCCESS;
case I2C_TIMEOUT:
return I2C_STATUS_TIMEOUT;
// I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
default:
return I2C_STATUS_ERROR;
/**
* @brief Handles any I2C error condition by stopping the I2C peripheral and
* aborting any ongoing transactions. Furthermore ChibiOS status codes are
* converted into QMK codes.
*
* @param status ChibiOS specific I2C status code
* @return i2c_status_t QMK specific I2C status code
*/
static i2c_status_t i2c_epilogue(const msg_t status) {
if (status == I2C_NO_ERROR) {
return I2C_STATUS_SUCCESS;
}

// From ChibiOS HAL: "After a timeout the driver must be stopped and
// restarted because the bus is in an uncertain state." We also issue that
// hard stop in case of any error.
i2c_stop();
KarlK90 marked this conversation as resolved.
Show resolved Hide resolved

return status == I2C_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR;
}

__attribute__((weak)) void i2c_init(void) {
Expand Down Expand Up @@ -149,14 +158,14 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length,
i2c_address = address;
i2cStart(&I2C_DRIVER, &i2cconfig);
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout));
return chibios_to_qmk(&status);
return i2c_epilogue(status);
}

i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_address = address;
i2cStart(&I2C_DRIVER, &i2cconfig);
msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, TIME_MS2I(timeout));
return chibios_to_qmk(&status);
return i2c_epilogue(status);
}

i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
Expand All @@ -170,7 +179,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
complete_packet[0] = regaddr;

msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout));
return chibios_to_qmk(&status);
return i2c_epilogue(status);
}

i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
Expand All @@ -185,22 +194,22 @@ i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* da
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);
return i2c_epilogue(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);
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), &regaddr, 1, data, length, TIME_MS2I(timeout));
return chibios_to_qmk(&status);
return i2c_epilogue(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);
return i2c_epilogue(status);
}

void i2c_stop(void) {
Expand Down