From 5931050b64f8cdc0dc590787fb7102db0edddfbc Mon Sep 17 00:00:00 2001 From: RyoheiHagimoto Date: Thu, 1 Oct 2020 13:42:57 +0900 Subject: [PATCH 1/2] Fixed I2C slave bugs on Renesas RZ/A series. Fixed following I2C slave bugs on Renesas RZ/A series: - Send an incorrect value during slave mode. - The behavior for the restart condition is wrong. --- .../TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c | 193 ++++++++++-------- .../TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c | 40 ++-- 2 files changed, 130 insertions(+), 103 deletions(-) diff --git a/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c b/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c index 90ed0b20f9..3deb1e38fe 100644 --- a/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c +++ b/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c @@ -53,6 +53,7 @@ volatile struct st_riic *RIIC[] = RIIC_ADDRESS_LIST; /* RIICnSR1 */ #define SR1_AAS0 (1 << 0) +#define SR1_GCA (1 << 3) /* RIICnSR2 */ #define SR2_START (1 << 2) @@ -64,11 +65,13 @@ volatile struct st_riic *RIIC[] = RIIC_ADDRESS_LIST; #define WAIT_TIMEOUT (3600000) /* Loop counter : Time-out is about 1s. By 3600000 loops, measured value is 969ms. */ -static inline int i2c_status(i2c_t *obj) { +static inline int i2c_status(i2c_t *obj) +{ return REG(SR2.UINT8[0]); } -static void i2c_reg_reset(i2c_t *obj) { +static void i2c_reg_reset(i2c_t *obj) +{ /* full reset */ REG(CR1.UINT8[0]) &= ~CR1_ICE; // CR1.ICE off REG(CR1.UINT8[0]) |= CR1_RST; // CR1.IICRST on @@ -91,9 +94,10 @@ static void i2c_reg_reset(i2c_t *obj) { REG(CR1.UINT32) &= ~CR1_RST; // CR1.IICRST negate reset } -static inline int i2c_wait_RDRF(i2c_t *obj) { +static inline int i2c_wait_RDRF(i2c_t *obj) +{ int timeout = 0; - + /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_RDRF) == 0) { timeout ++; @@ -105,7 +109,8 @@ static inline int i2c_wait_RDRF(i2c_t *obj) { return 0; } -static int i2c_wait_TDRE(i2c_t *obj) { +static int i2c_wait_TDRE(i2c_t *obj) +{ int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ @@ -119,9 +124,10 @@ static int i2c_wait_TDRE(i2c_t *obj) { return 0; } -static int i2c_wait_TEND(i2c_t *obj) { +static int i2c_wait_TEND(i2c_t *obj) +{ int timeout = 0; - + /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_TEND) == 0) { timeout ++; @@ -134,9 +140,10 @@ static int i2c_wait_TEND(i2c_t *obj) { } -static int i2c_wait_START(i2c_t *obj) { +static int i2c_wait_START(i2c_t *obj) +{ int timeout = 0; - + /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_START) == 0) { timeout ++; @@ -148,9 +155,10 @@ static int i2c_wait_START(i2c_t *obj) { return 0; } -static int i2c_wait_STOP(i2c_t *obj) { +static int i2c_wait_STOP(i2c_t *obj) +{ int timeout = 0; - + /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while ((i2c_status(obj) & SR2_STOP) == 0) { timeout ++; @@ -162,7 +170,8 @@ static int i2c_wait_STOP(i2c_t *obj) { return 0; } -static int i2c_set_STOP(i2c_t *obj) { +static int i2c_set_STOP(i2c_t *obj) +{ /* SR2.STOP = 0 */ REG(SR2.UINT32) &= ~SR2_STOP; /* Stop condition */ @@ -171,28 +180,32 @@ static int i2c_set_STOP(i2c_t *obj) { return 0; } -static void i2c_set_SR2_NACKF_STOP(i2c_t *obj) { +static void i2c_set_SR2_NACKF_STOP(i2c_t *obj) +{ /* SR2.NACKF = 0 */ REG(SR2.UINT32) &= ~SR2_NACKF; /* SR2.STOP = 0 */ REG(SR2.UINT32) &= ~SR2_STOP; } -static void i2c_set_MR3_NACK(i2c_t *obj) { +static void i2c_set_MR3_NACK(i2c_t *obj) +{ /* send a NOT ACK */ REG(MR3.UINT32) |= MR3_ACKWP; REG(MR3.UINT32) |= MR3_ACKBT; REG(MR3.UINT32) &= ~MR3_ACKWP; } -static void i2c_set_MR3_ACK(i2c_t *obj) { +static void i2c_set_MR3_ACK(i2c_t *obj) +{ /* send a ACK */ REG(MR3.UINT32) |= MR3_ACKWP; REG(MR3.UINT32) &= ~MR3_ACKBT; REG(MR3.UINT32) &= ~MR3_ACKWP; } -static inline void i2c_power_enable(i2c_t *obj) { +static inline void i2c_power_enable(i2c_t *obj) +{ volatile uint8_t dummy; switch ((int)obj->i2c.i2c) { case I2C_0: @@ -212,7 +225,8 @@ static inline void i2c_power_enable(i2c_t *obj) { (void)dummy; } -void i2c_init(i2c_t *obj, PinName sda, PinName scl) { +void i2c_init(i2c_t *obj, PinName sda, PinName scl) +{ /* determine the I2C to use */ I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); @@ -227,11 +241,12 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) { pinmap_pinout(sda, PinMap_I2C_SDA); pinmap_pinout(scl, PinMap_I2C_SCL); - + obj->i2c.last_stop_flag = 1; } -inline int i2c_start(i2c_t *obj) { +inline int i2c_start(i2c_t *obj) +{ int timeout = 0; while ((REG(CR2.UINT32) & CR2_BBSY) != 0) { @@ -246,7 +261,8 @@ inline int i2c_start(i2c_t *obj) { return 0; } -static inline int i2c_restart(i2c_t *obj) { +static inline int i2c_restart(i2c_t *obj) +{ /* SR2.START = 0 */ REG(SR2.UINT32) &= ~SR2_START; /* ReStart condition */ @@ -255,22 +271,25 @@ static inline int i2c_restart(i2c_t *obj) { return 0; } -inline int i2c_stop(i2c_t *obj) { +inline int i2c_stop(i2c_t *obj) +{ (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); - + return 0; } -static void i2c_set_err_noslave(i2c_t *obj) { +static void i2c_set_err_noslave(i2c_t *obj) +{ (void)i2c_set_STOP(obj); (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); obj->i2c.last_stop_flag = 1; } -static inline int i2c_do_write(i2c_t *obj, int value) { +static inline int i2c_do_write(i2c_t *obj, int value) +{ int timeout = 0; /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ @@ -286,20 +305,22 @@ static inline int i2c_do_write(i2c_t *obj, int value) { return 0; } -static inline int i2c_read_address_write(i2c_t *obj, int value) { +static inline int i2c_read_address_write(i2c_t *obj, int value) +{ int status; - + status = i2c_wait_TDRE(obj); if (status == 0) { /* write the data */ REG(DRT.UINT32) = value; } - + return status; } -static inline int i2c_do_read(i2c_t *obj, int last) { +static inline int i2c_do_read(i2c_t *obj, int last) +{ if (last == 2) { /* this time is befor last byte read */ /* Set MR3 WAIT bit is 1 */; @@ -314,7 +335,8 @@ static inline int i2c_do_read(i2c_t *obj, int last) { return (REG(DRR.UINT32) & 0xFF); } -void i2c_frequency(i2c_t *obj, int hz) { +void i2c_frequency(i2c_t *obj, int hz) +{ float64_t pclk_val; float64_t wait_utime; volatile float64_t bps; @@ -400,7 +422,8 @@ void i2c_frequency(i2c_t *obj, int hz) { i2c_reg_reset(obj); } -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) +{ int count = 0; int status; int value; @@ -523,7 +546,8 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { return length; } -int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { +int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) +{ int cnt; int status; @@ -550,9 +574,9 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { return I2C_ERROR_NO_SLAVE; } /* Send Write data */ - for (cnt=0; cnt> 4; - - switch(status) { - case 0x01: - /* the master is writing to this slave */ - retval = 3; - break; - case 0x02: - /* the master is writing to all slave */ - retval = 2; - break; - case 0x03: + /* detected general call address */ + if (0 != (REG(SR1.UINT8[0]) & SR1_GCA)) { + /* the master is writing to all slave */ + retval = 2; + } + /* detected slave address */ + else if (0 != (REG(SR1.UINT8[0]) & SR1_AAS0)) { + if (0 != (REG(CR2.UINT8[0]) & CR2_TRS)) { /* the master has requested a read from this slave */ retval = 1; - break; - default : - /* no data */ - retval = 0; - break; + } else { + /* the master is writing to this slave */ + retval = 3; + } + } + /* no data */ + else { + retval = 0; } return retval; } -int i2c_slave_read(i2c_t *obj, char *data, int length) { +int i2c_slave_read(i2c_t *obj, char *data, int length) +{ int timeout = 0; int count; int break_flg = 0; - if(length <= 0) { + if (length <= 0) { return 0; } for (count = 0; ((count < (length + 1)) && (break_flg == 0)); count++) { /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ - while (((i2c_status(obj) & SR2_STOP) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { - if ((i2c_status(obj) & SR2_STOP) != 0) { + while (((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { + if ((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) { break_flg = 1; break; } @@ -714,17 +741,18 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) { return (count - 1); } -int i2c_slave_write(i2c_t *obj, const char *data, int length) { +int i2c_slave_write(i2c_t *obj, const char *data, int length) +{ int count = 0; int status = 0; - if(length <= 0) { + if (length <= 0) { return 0; } while ((count < length) && (status == 0)) { status = i2c_do_write(obj, data[count]); - if(status == 0) { + if (status == 0) { /* Wait send end */ status = i2c_wait_TEND(obj); if ((status != 0) || ((count < (length - 1)) && ((REG(SR2.UINT32) & SR2_NACKF) != 0))) { @@ -742,7 +770,8 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) { return count; } -void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) { +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) +{ REG(SAR0.UINT32) = (address & 0xfffffffe); } @@ -836,10 +865,10 @@ static void i2c_tx_irq(IRQn_Type irq_num, uint32_t index) } if (obj->tx_buff.pos == obj->tx_buff.length) { /* All datas have tranferred */ - + /* Clear TEND */ REG(SR2.UINT32) &= ~(SR2_TEND); - + /* If not repeated start, send stop. */ if (i2c_data[index].shouldStop && obj->rx_buff.length == 0) { (void)i2c_set_STOP(obj); @@ -854,10 +883,10 @@ static void i2c_tx_irq(IRQn_Type irq_num, uint32_t index) if (obj->rx_buff.length) { /* Ready to read */ i2c_set_MR3_ACK(obj); - + /* Disable INTRIICTEI */ REG(IER.UINT8[0]) &= ~(1 << 6); - + /* Send Slave address */ if (i2c_read_address_write(obj, (i2c_data[index].address | 0x01)) != 0) { i2c_set_err_noslave(obj); @@ -896,7 +925,7 @@ static void i2c_rx_irq(IRQn_Type irq_num, uint32_t index) (void)i2c_wait_STOP(obj); i2c_set_SR2_NACKF_STOP(obj); obj->i2c.last_stop_flag = 1; - + i2c_data[index].event = I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK; i2c_abort_asynch(obj); ((void (*)())i2c_data[index].async_callback)(); @@ -946,20 +975,20 @@ static void i2c_rx_irq(IRQn_Type irq_num, uint32_t index) /* SR2.START = 0 */ REG(SR2.UINT32) &= ~SR2_START; } - + i2c_transfer_finished(obj); return; - + case 2: i2c_set_MR3_NACK(obj); break; - + case 3: /* this time is befor last byte read */ /* Set MR3 WAIT bit is 1 */ REG(MR3.UINT32) |= MR3_WAIT; break; - + default: i2c_set_MR3_ACK(obj); break; @@ -1094,7 +1123,7 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, MBED_ASSERT(tx ? tx_length : 1); MBED_ASSERT(rx ? rx_length : 1); MBED_ASSERT((REG(SER.UINT32) & SER_SAR0E) == 0); /* Slave mode */ - + obj->tx_buff.buffer = (void *)tx; obj->tx_buff.length = tx_length; obj->tx_buff.pos = 0; @@ -1109,7 +1138,7 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, i2c_data[obj->i2c.i2c].shouldStop = stop; i2c_data[obj->i2c.i2c].address = address; i2c_irqs_set(obj, 1); - + /* There is a STOP condition for last processing */ if (obj->i2c.last_stop_flag != 0) { if (i2c_start(obj) != 0) { @@ -1121,14 +1150,14 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, } } obj->i2c.last_stop_flag = stop; - + if (rx_length && tx_length == 0) { /* Ready to read */ i2c_set_MR3_ACK(obj); - + /* Disable INTRIICTEI */ REG(IER.UINT8[0]) &= ~(1 << 6); - + address |= 0x01; } /* Send Slave address */ diff --git a/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c b/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c index f295d751de..60ca9ea3f4 100644 --- a/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c +++ b/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c @@ -51,6 +51,7 @@ static const volatile struct st_riic *RIIC[] = { /* RIICnSR1 */ #define SR1_AAS0 (1 << 0) +#define SR1_GCA (1 << 3) /* RIICnSR2 */ #define SR2_START (1 << 2) @@ -666,29 +667,26 @@ void i2c_slave_mode(i2c_t *obj, int enable_slave) int i2c_slave_receive(i2c_t *obj) { - int status; int retval; - status = (obj->i2c.i2c->ICSR1.BYTE.LL & SR1_AAS0); - status |= (obj->i2c.i2c->ICCR2.BYTE.LL & CR2_TRS) >> 4; - - switch (status) { - case 0x01: - /* the master is writing to this slave */ - retval = 3; - break; - case 0x02: - /* the master is writing to all slave */ - retval = 2; - break; - case 0x03: + /* detected general call address */ + if (0 != (obj->i2c.i2c->ICSR1.BYTE.LL & SR1_GCA)) { + /* the master is writing to all slave */ + retval = 2; + } + /* detected slave address */ + else if (0 != (obj->i2c.i2c->ICSR1.BYTE.LL & SR1_AAS0)) { + if (0 != (obj->i2c.i2c->ICCR2.BYTE.LL & CR2_TRS)) { /* the master has requested a read from this slave */ retval = 1; - break; - default : - /* no data */ - retval = 0; - break; + } else { + /* the master is writing to this slave */ + retval = 3; + } + } + /* no data */ + else { + retval = 0; } return retval; @@ -705,8 +703,8 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) } for (count = 0; ((count < (length + 1)) && (break_flg == 0)); count++) { /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ - while (((i2c_status(obj) & SR2_STOP) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { - if ((i2c_status(obj) & SR2_STOP) != 0) { + while (((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { + if ((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) { break_flg = 1; break; } From e3fea114ec6e8d2114afc06db93b21323ccead4b Mon Sep 17 00:00:00 2001 From: RyoheiHagimoto Date: Thu, 1 Oct 2020 14:16:28 +0900 Subject: [PATCH 2/2] Fixed I2C slave bugs on Renesas RZ/A series: Added the register operation when received the slave address. --- .../TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c | 18 +++++++++++++++++- .../TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c b/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c index 3deb1e38fe..28f47119fa 100644 --- a/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c +++ b/targets/TARGET_RENESAS/TARGET_RZ_A1XX/i2c_api.c @@ -1,5 +1,5 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited + * Copyright (c) 2006-2020 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,10 +50,19 @@ volatile struct st_riic *RIIC[] = RIIC_ADDRESS_LIST; /* RIICnSER */ #define SER_SAR0E (1 << 0) +#define SER_SAR1E (1 << 1) +#define SER_SAR2E (1 << 2) +#define SER_GCE (1 << 3) +#define SER_DIDE (1 << 5) +#define SER_HOAE (1 << 7) /* RIICnSR1 */ #define SR1_AAS0 (1 << 0) +#define SR1_AAS1 (1 << 1) +#define SR1_AAS2 (1 << 2) #define SR1_GCA (1 << 3) +#define SR1_DID (1 << 5) +#define SR1_HOA (1 << 7) /* RIICnSR2 */ #define SR2_START (1 << 2) @@ -689,6 +698,12 @@ int i2c_slave_receive(i2c_t *obj) retval = 0; } + /* to detect restart-condition */ + if (0 != retval) { + /* SR2.START = 0 */ + REG(SR2.UINT32) &= ~SR2_START; + } + return retval; } @@ -704,6 +719,7 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) for (count = 0; ((count < (length + 1)) && (break_flg == 0)); count++) { /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while (((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { + /* received stop-condition or restart-condition */ if ((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) { break_flg = 1; break; diff --git a/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c b/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c index 60ca9ea3f4..2fec46a9dd 100644 --- a/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c +++ b/targets/TARGET_RENESAS/TARGET_RZ_A2XX/i2c_api.c @@ -48,10 +48,19 @@ static const volatile struct st_riic *RIIC[] = { /* RIICnSER */ #define SER_SAR0E (1 << 0) +#define SER_SAR1E (1 << 1) +#define SER_SAR2E (1 << 2) +#define SER_GCE (1 << 3) +#define SER_DIDE (1 << 5) +#define SER_HOAE (1 << 7) /* RIICnSR1 */ #define SR1_AAS0 (1 << 0) +#define SR1_AAS1 (1 << 1) +#define SR1_AAS2 (1 << 2) #define SR1_GCA (1 << 3) +#define SR1_DID (1 << 5) +#define SR1_HOA (1 << 7) /* RIICnSR2 */ #define SR2_START (1 << 2) @@ -689,6 +698,12 @@ int i2c_slave_receive(i2c_t *obj) retval = 0; } + /* to detect restart-condition */ + if (0 != retval) { + /* SR2.START = 0 */ + obj->i2c.i2c->ICSR2.LONG &= ~SR2_START; + } + return retval; } @@ -704,6 +719,7 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) for (count = 0; ((count < (length + 1)) && (break_flg == 0)); count++) { /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */ while (((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) { + /* received stop-condition or restart-condition */ if ((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) { break_flg = 1; break;