From 083b42068a284765c5dd18c2f04ed542d157ffc9 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Tue, 26 Jul 2022 21:40:14 +0200 Subject: Chibios: Stop I2C peripheral on transaction error (#17798) From the ChibiOS HAL I2C driver pages: After a timeout the driver must be stopped and restarted because the bus is in an uncertain state. This commit does that stopping explicitly on any error that occurred, not only timeouts. As all the i2c functions restart the peripheral if necessary it is safe to do so. Co-authored-by: Dasky <32983009+daskygit@users.noreply.github.com> Co-authored-by: Dasky <32983009+daskygit@users.noreply.github.com> --- platforms/chibios/drivers/i2c_master.c | 39 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'platforms/chibios/drivers/i2c_master.c') diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 21e064b1dc..bf8f1ee236 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -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(); + + return status == I2C_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR; } __attribute__((weak)) void i2c_init(void) { @@ -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) { @@ -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) { @@ -185,14 +194,14 @@ 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), ®addr, 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) { @@ -200,7 +209,7 @@ i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uin 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) { -- cgit v1.2.3 From 157ea964117de382b52229db87a55340830839c9 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 28 Jul 2022 03:02:10 +0200 Subject: ChibiOS: use correct status codes in i2c_master.c (#17808) msg_t is MSG_OK in the success case and either MSG_RESET or MSG_TIMEOUT in case of errors. So actually use them in the comparison. --- platforms/chibios/drivers/i2c_master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'platforms/chibios/drivers/i2c_master.c') diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index bf8f1ee236..4c7a5daa17 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -116,7 +116,7 @@ static const I2CConfig i2cconfig = { * @return i2c_status_t QMK specific I2C status code */ static i2c_status_t i2c_epilogue(const msg_t status) { - if (status == I2C_NO_ERROR) { + if (status == MSG_OK) { return I2C_STATUS_SUCCESS; } @@ -125,7 +125,7 @@ static i2c_status_t i2c_epilogue(const msg_t status) { // hard stop in case of any error. i2c_stop(); - return status == I2C_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR; + return status == MSG_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR; } __attribute__((weak)) void i2c_init(void) { -- cgit v1.2.3