mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #13692 from RyoheiHagimoto/gr_i2c_slave
Fix I2C slave bugs on Renesas RZ/A series.pull/13828/head
commit
f9e62fe615
|
@ -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,9 +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)
|
||||
|
@ -64,11 +74,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,7 +103,8 @@ 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. */
|
||||
|
@ -105,7 +118,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,7 +133,8 @@ 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. */
|
||||
|
@ -134,7 +149,8 @@ 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. */
|
||||
|
@ -148,7 +164,8 @@ 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. */
|
||||
|
@ -162,7 +179,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 +189,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 +234,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);
|
||||
|
@ -231,7 +254,8 @@ void i2c_init(i2c_t *obj, PinName sda, PinName 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 +270,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,7 +280,8 @@ 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);
|
||||
|
@ -263,14 +289,16 @@ inline int i2c_stop(i2c_t *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,7 +314,8 @@ 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);
|
||||
|
@ -299,7 +328,8 @@ static inline int i2c_read_address_write(i2c_t *obj, int value) {
|
|||
|
||||
}
|
||||
|
||||
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 +344,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 +431,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 +555,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 +583,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<length; cnt++) {
|
||||
for (cnt = 0; cnt < length; cnt++) {
|
||||
status = i2c_do_write(obj, data[cnt]);
|
||||
if(status != 0) {
|
||||
if (status != 0) {
|
||||
i2c_set_err_noslave(obj);
|
||||
return cnt;
|
||||
} else {
|
||||
|
@ -581,13 +614,15 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
|
|||
return length;
|
||||
}
|
||||
|
||||
void i2c_reset(i2c_t *obj) {
|
||||
void i2c_reset(i2c_t *obj)
|
||||
{
|
||||
(void)i2c_set_STOP(obj);
|
||||
(void)i2c_wait_STOP(obj);
|
||||
i2c_set_SR2_NACKF_STOP(obj);
|
||||
}
|
||||
|
||||
int i2c_byte_read(i2c_t *obj, int last) {
|
||||
int i2c_byte_read(i2c_t *obj, int last)
|
||||
{
|
||||
int status;
|
||||
int data;
|
||||
|
||||
|
@ -602,7 +637,8 @@ int i2c_byte_read(i2c_t *obj, int last) {
|
|||
return data;
|
||||
}
|
||||
|
||||
int i2c_byte_write(i2c_t *obj, int data) {
|
||||
int i2c_byte_write(i2c_t *obj, int data)
|
||||
{
|
||||
int ack = 0;
|
||||
int status;
|
||||
int timeout = 0;
|
||||
|
@ -629,7 +665,8 @@ int i2c_byte_write(i2c_t *obj, int data) {
|
|||
return ack;
|
||||
}
|
||||
|
||||
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
|
||||
void i2c_slave_mode(i2c_t *obj, int enable_slave)
|
||||
{
|
||||
if (enable_slave != 0) {
|
||||
REG(SER.UINT32) |= SER_SAR0E; // only slave addr 0 is enabled
|
||||
} else {
|
||||
|
@ -637,47 +674,53 @@ void i2c_slave_mode(i2c_t *obj, int enable_slave) {
|
|||
}
|
||||
}
|
||||
|
||||
int i2c_slave_receive(i2c_t *obj) {
|
||||
int status;
|
||||
int i2c_slave_receive(i2c_t *obj)
|
||||
{
|
||||
int retval;
|
||||
|
||||
status = (REG(SR1.UINT8[0]) & SR1_AAS0);
|
||||
status |= (REG(CR2.UINT8[0]) & 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 != (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;
|
||||
}
|
||||
|
||||
/* to detect restart-condition */
|
||||
if (0 != retval) {
|
||||
/* SR2.START = 0 */
|
||||
REG(SR2.UINT32) &= ~SR2_START;
|
||||
}
|
||||
|
||||
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)) {
|
||||
/* received stop-condition or restart-condition */
|
||||
if ((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) {
|
||||
break_flg = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -714,17 +757,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 +786,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,9 +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)
|
||||
|
@ -666,29 +676,32 @@ 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;
|
||||
}
|
||||
|
||||
/* to detect restart-condition */
|
||||
if (0 != retval) {
|
||||
/* SR2.START = 0 */
|
||||
obj->i2c.i2c->ICSR2.LONG &= ~SR2_START;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -705,8 +718,9 @@ 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)) {
|
||||
/* received stop-condition or restart-condition */
|
||||
if ((i2c_status(obj) & (SR2_STOP | SR2_START)) != 0) {
|
||||
break_flg = 1;
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue