From d15abe5171492f80efd559fc1b8b0dfff2fb81b2 Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Tue, 20 Aug 2019 17:08:20 +0800 Subject: [PATCH] M263: Fix I2C NACK error Fix logic error on replying NACK at the end of transfer. This is also to fix FPGA CI test mbed_hal_fpga_ci_test_shield-i2c/ i2c - test single byte read i2c API. --- targets/TARGET_NUVOTON/TARGET_M261/i2c_api.c | 34 ++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M261/i2c_api.c b/targets/TARGET_NUVOTON/TARGET_M261/i2c_api.c index 26affe8b90..b24c2bfbcb 100644 --- a/targets/TARGET_NUVOTON/TARGET_M261/i2c_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M261/i2c_api.c @@ -86,9 +86,10 @@ static void i2c_enable_vector_interrupt(i2c_t *obj, uint32_t handler, int enable static void i2c_rollback_vector_interrupt(i2c_t *obj); #endif -#define TRANCTRL_STARTED (1) -#define TRANCTRL_NAKLASTDATA (1 << 1) -#define TRANCTRL_LASTDATANAKED (1 << 2) +#define TRANCTRL_STARTED (1) // Guard I2C ISR from data transfer prematurely +#define TRANCTRL_NAKLASTDATA (1 << 1) // Request NACK on last data +#define TRANCTRL_LASTDATANAKED (1 << 2) // Last data NACKed +#define TRANCTRL_RECVDATA (1 << 3) // Receive data available uint32_t us_ticker_read(void); @@ -592,11 +593,17 @@ static void i2c_irq(i2c_t *obj) if ((obj->i2c.tran_ctrl & TRANCTRL_STARTED) && obj->i2c.tran_pos) { if (obj->i2c.tran_pos < obj->i2c.tran_end) { if (status == 0x50 || status == 0x58) { - *obj->i2c.tran_pos ++ = I2C_GET_DATA(i2c_base); + if (obj->i2c.tran_ctrl & TRANCTRL_RECVDATA) { + *obj->i2c.tran_pos ++ = I2C_GET_DATA(i2c_base); + obj->i2c.tran_ctrl &= ~TRANCTRL_RECVDATA; + } } if (status == 0x58) { i2c_fsm_tranfini(obj, 1); + } else if (obj->i2c.tran_pos == obj->i2c.tran_end) { + obj->i2c.tran_ctrl &= ~TRANCTRL_STARTED; + i2c_disable_int(obj); } else { uint32_t i2c_ctl = I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -605,6 +612,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL0_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { obj->i2c.tran_ctrl &= ~TRANCTRL_STARTED; @@ -659,12 +667,18 @@ static void i2c_irq(i2c_t *obj) if ((obj->i2c.tran_ctrl & TRANCTRL_STARTED) && obj->i2c.tran_pos) { if (obj->i2c.tran_pos < obj->i2c.tran_end) { if (status == 0x80 || status == 0x88) { - *obj->i2c.tran_pos ++ = I2C_GET_DATA(i2c_base); + if (obj->i2c.tran_ctrl & TRANCTRL_RECVDATA) { + *obj->i2c.tran_pos ++ = I2C_GET_DATA(i2c_base); + obj->i2c.tran_ctrl &= ~TRANCTRL_RECVDATA; + } } if (status == 0x88) { obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else if (obj->i2c.tran_pos == obj->i2c.tran_end) { + obj->i2c.tran_ctrl &= ~TRANCTRL_STARTED; + i2c_disable_int(obj); } else { uint32_t i2c_ctl = I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -673,6 +687,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL0_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { obj->i2c.tran_ctrl &= ~TRANCTRL_STARTED; @@ -695,12 +710,18 @@ static void i2c_irq(i2c_t *obj) if ((obj->i2c.tran_ctrl & TRANCTRL_STARTED) && obj->i2c.tran_pos) { if (obj->i2c.tran_pos < obj->i2c.tran_end) { if (status == 0x90 || status == 0x98) { - *obj->i2c.tran_pos ++ = I2C_GET_DATA(i2c_base); + if (obj->i2c.tran_ctrl & TRANCTRL_RECVDATA) { + *obj->i2c.tran_pos ++ = I2C_GET_DATA(i2c_base); + obj->i2c.tran_ctrl &= ~TRANCTRL_RECVDATA; + } } if (status == 0x98) { obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else if (obj->i2c.tran_pos == obj->i2c.tran_end) { + obj->i2c.tran_ctrl &= ~TRANCTRL_STARTED; + i2c_disable_int(obj); } else { uint32_t i2c_ctl = I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -709,6 +730,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL0_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { obj->i2c.tran_ctrl &= ~TRANCTRL_STARTED;