From 80c21aeff545be5422b92af8fb190209c2fd369c Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Thu, 18 Jul 2019 18:11:11 +0800 Subject: [PATCH] [Nuvoton] 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_M2351/i2c_api.c | 34 ++++++++++++++--- targets/TARGET_NUVOTON/TARGET_M451/i2c_api.c | 37 ++++++++++++++++--- targets/TARGET_NUVOTON/TARGET_M480/i2c_api.c | 34 ++++++++++++++--- .../TARGET_NUVOTON/TARGET_NANO100/i2c_api.c | 37 ++++++++++++++++--- .../TARGET_NUVOTON/TARGET_NUC472/i2c_api.c | 37 ++++++++++++++++--- 5 files changed, 149 insertions(+), 30 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/i2c_api.c b/targets/TARGET_NUVOTON/TARGET_M2351/i2c_api.c index f428e513b8..ad4ee37a4a 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/i2c_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M2351/i2c_api.c @@ -85,9 +85,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); @@ -597,11 +598,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 && @@ -610,6 +617,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; @@ -664,12 +672,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 && @@ -678,6 +692,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; @@ -700,12 +715,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 && @@ -714,6 +735,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; diff --git a/targets/TARGET_NUVOTON/TARGET_M451/i2c_api.c b/targets/TARGET_NUVOTON/TARGET_M451/i2c_api.c index 5afd984615..89057fe41f 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/i2c_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/i2c_api.c @@ -94,9 +94,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); @@ -641,7 +642,10 @@ 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) { @@ -653,6 +657,10 @@ static void i2c_irq(i2c_t *obj) #endif 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_CTL_SI_Msk | I2C_CTL_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -661,6 +669,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { @@ -719,7 +728,10 @@ 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) { @@ -732,6 +744,10 @@ static void i2c_irq(i2c_t *obj) obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CTL_SI_Msk | I2C_CTL_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_CTL_SI_Msk | I2C_CTL_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -740,6 +756,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { @@ -764,7 +781,10 @@ 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) { @@ -777,6 +797,10 @@ static void i2c_irq(i2c_t *obj) obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CTL_SI_Msk | I2C_CTL_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_CTL_SI_Msk | I2C_CTL_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -785,6 +809,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { diff --git a/targets/TARGET_NUVOTON/TARGET_M480/i2c_api.c b/targets/TARGET_NUVOTON/TARGET_M480/i2c_api.c index 12e64ee8cb..c373abc1dd 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/i2c_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/i2c_api.c @@ -85,9 +85,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); @@ -591,11 +592,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 && @@ -604,6 +611,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; @@ -658,12 +666,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 && @@ -672,6 +686,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; @@ -694,12 +709,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 && @@ -708,6 +729,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; diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/i2c_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/i2c_api.c index 4ea605f856..cbc7af8b84 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/i2c_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/i2c_api.c @@ -109,9 +109,10 @@ static void i2c_enable_vector_interrupt(i2c_t *obj, uint32_t handler, int enable static void i2c_teardown_async(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); @@ -653,7 +654,10 @@ 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) { @@ -665,6 +669,10 @@ static void i2c_irq(i2c_t *obj) #endif 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_CON_I2C_STS_Msk | I2C_CON_ACK_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -673,6 +681,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CON_ACK_Msk; } i2c_set_control_reg(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { @@ -731,7 +740,10 @@ 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) { @@ -744,6 +756,10 @@ static void i2c_irq(i2c_t *obj) obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CON_I2C_STS_Msk | I2C_CON_ACK_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_CON_I2C_STS_Msk | I2C_CON_ACK_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -752,6 +768,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CON_ACK_Msk; } i2c_set_control_reg(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { @@ -776,7 +793,10 @@ 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) { @@ -789,6 +809,10 @@ static void i2c_irq(i2c_t *obj) obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CON_I2C_STS_Msk | I2C_CON_ACK_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_CON_I2C_STS_Msk | I2C_CON_ACK_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -797,6 +821,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CON_ACK_Msk; } i2c_set_control_reg(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/i2c_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/i2c_api.c index 0c1c8ac9a0..a5e3bad7c3 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/i2c_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/i2c_api.c @@ -111,9 +111,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); @@ -671,7 +672,10 @@ 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) { @@ -683,6 +687,10 @@ static void i2c_irq(i2c_t *obj) #endif 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_CTL_SI_Msk | I2C_CTL_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -691,6 +699,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { @@ -749,7 +758,10 @@ 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) { @@ -762,6 +774,10 @@ static void i2c_irq(i2c_t *obj) obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CTL_SI_Msk | I2C_CTL_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_CTL_SI_Msk | I2C_CTL_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -770,6 +786,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else { @@ -794,7 +811,10 @@ 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) { @@ -807,6 +827,10 @@ static void i2c_irq(i2c_t *obj) obj->i2c.slaveaddr_state = NoData; i2c_fsm_reset(obj, I2C_CTL_SI_Msk | I2C_CTL_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_CTL_SI_Msk | I2C_CTL_AA_Msk; if ((obj->i2c.tran_end - obj->i2c.tran_pos) == 1 && @@ -815,6 +839,7 @@ static void i2c_irq(i2c_t *obj) i2c_ctl &= ~I2C_CTL_AA_Msk; } I2C_SET_CONTROL_REG(i2c_base, i2c_ctl); + obj->i2c.tran_ctrl |= TRANCTRL_RECVDATA; } } else {