diff --git a/cpu/esp32/periph/i2c_hw.c b/cpu/esp32/periph/i2c_hw.c index c176d57bfc..92e8c47565 100644 --- a/cpu/esp32/periph/i2c_hw.c +++ b/cpu/esp32/periph/i2c_hw.c @@ -288,23 +288,68 @@ int i2c_release(i2c_t dev) return 0; } -#define _i2c_return_on_error(dev) \ +/* + * This macro checks the result of a read transfer. In case of an error, + * the hardware is reset and returned with a corresponding error code. + * + * @note: + * In a read transfer, an ACK is only expected for the address field. Thus, + * an ACK error can only happen for the address field. Therefore, we always + * return -ENXIO in case of an ACK error. + */ +#define _i2c_return_on_error_read(dev) \ if (_i2c_bus[dev].results & I2C_ARBITRATION_LOST_INT_ENA) { \ - LOG_TAG_ERROR("i2c", "arbitration lost dev=%u\n", dev); \ + LOG_TAG_DEBUG("i2c", "arbitration lost dev=%u\n", dev); \ _i2c_reset_hw (dev); \ -__asm__ volatile ("isync"); \ + __asm__ volatile ("isync"); \ return -EAGAIN; \ } \ else if (_i2c_bus[dev].results & I2C_ACK_ERR_INT_ENA) { \ - LOG_TAG_ERROR("i2c", "ack error dev=%u\n", dev); \ + LOG_TAG_DEBUG("i2c", "ack error dev=%u\n", dev); \ _i2c_reset_hw (dev); \ -__asm__ volatile ("isync"); \ - return -EIO; \ + __asm__ volatile ("isync"); \ + return -ENXIO; \ } \ else if (_i2c_bus[dev].results & I2C_TIME_OUT_INT_ENA) { \ - LOG_TAG_ERROR("i2c", "bus timeout dev=%u\n", dev); \ + LOG_TAG_DEBUG("i2c", "bus timeout dev=%u\n", dev); \ _i2c_reset_hw (dev); \ -__asm__ volatile ("isync"); \ + __asm__ volatile ("isync"); \ + return -ETIMEDOUT; \ + } + +/* + * This macro checks the result of a write transfer. In case of an error, + * the hardware is reset and returned with a corresponding error code. + * + * @note: + * In a write transfer, an ACK error can happen for the address field + * as well as for data. If the FIFO still contains all data bytes, + * (i.e. _i2c_hw[dev].regs->status_reg.tx_fifo_cnt >= len), the ACK error + * happened in address field and we have to returen -ENXIO. Otherwise, the + * ACK error happened in data field and we have to return -EIO. + */ +#define _i2c_return_on_error_write(dev) \ + if (_i2c_bus[dev].results & I2C_ARBITRATION_LOST_INT_ENA) { \ + LOG_TAG_DEBUG("i2c", "arbitration lost dev=%u\n", dev); \ + _i2c_reset_hw (dev); \ + __asm__ volatile ("isync"); \ + return -EAGAIN; \ + } \ + else if (_i2c_bus[dev].results & I2C_ACK_ERR_INT_ENA) { \ + LOG_TAG_DEBUG("i2c", "ack error dev=%u\n", dev); \ + _i2c_reset_hw (dev); \ + __asm__ volatile ("isync"); \ + if (_i2c_hw[dev].regs->status_reg.tx_fifo_cnt >= len) { \ + return -ENXIO; \ + } \ + else { \ + return -EIO; \ + } \ + } \ + else if (_i2c_bus[dev].results & I2C_TIME_OUT_INT_ENA) { \ + LOG_TAG_DEBUG("i2c", "bus timeout dev=%u\n", dev); \ + _i2c_reset_hw (dev); \ + __asm__ volatile ("isync"); \ return -ETIMEDOUT; \ } @@ -350,7 +395,7 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t fla _i2c_read_cmd (dev, data, I2C_MAX_DATA, false); _i2c_end_cmd (dev); _i2c_transfer (dev); - _i2c_return_on_error (dev); + _i2c_return_on_error_read (dev); /* if transfer was successful, fetch the data from I2C RAM */ for (unsigned i = 0; i < I2C_MAX_DATA; i++) { @@ -380,7 +425,7 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t fla /* finish operation by executing the command pipeline */ _i2c_transfer (dev); - _i2c_return_on_error (dev); + _i2c_return_on_error_read (dev); /* if transfer was successful, fetch data from I2C RAM */ for (unsigned i = 0; i < len; i++) { @@ -437,7 +482,7 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint _i2c_write_cmd (dev, ((uint8_t*)data) + off, I2C_MAX_DATA); _i2c_end_cmd (dev); _i2c_transfer (dev); - _i2c_return_on_error (dev); + _i2c_return_on_error_write (dev); len -= I2C_MAX_DATA; off += I2C_MAX_DATA; @@ -458,7 +503,7 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint /* finish operation by executing the command pipeline */ _i2c_transfer (dev); - _i2c_return_on_error (dev); + _i2c_return_on_error_write (dev); /* return 0 on success */ return 0; diff --git a/cpu/esp32/periph/i2c_sw.c b/cpu/esp32/periph/i2c_sw.c index 1209898411..82e201a929 100644 --- a/cpu/esp32/periph/i2c_sw.c +++ b/cpu/esp32/periph/i2c_sw.c @@ -225,7 +225,7 @@ int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, (res = _i2c_write_byte (bus, addr2)) != 0) { /* abort transfer */ _i2c_abort (bus, __func__); - return res; + return -ENXIO; } } else { @@ -233,7 +233,7 @@ int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, if ((res = _i2c_write_byte (bus, (addr << 1 | I2C_READ))) != 0) { /* abort transfer */ _i2c_abort (bus, __func__); - return res; + return -ENXIO; } } } @@ -286,7 +286,7 @@ int /* IRAM */ i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_ (res = _i2c_write_byte (bus, addr2)) != 0) { /* abort transfer */ _i2c_abort (bus, __func__); - return res; + return -ENXIO; } } else { @@ -294,7 +294,7 @@ int /* IRAM */ i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_ if ((res = _i2c_write_byte (bus, addr << 1)) != 0) { /* abort transfer */ _i2c_abort (bus, __func__); - return res; + return -ENXIO; } } }