Checking in the fixes related to I2C issues.

Three main issues:
1) The 0x13 special case section in write data in ncs36510_i2c.c didn't have a write++ command.
2) In the same write function, the WDAT8 command was put before the 0x13 section and this is not correct
3) Needed to add wait_us(0) before and after the register writes for apparent clock domain crossing delay times until registers are stable in HW

There were also a handful of other tweaks related to general code maintenance and moving some status register checks to the proper locations.
pull/5452/head
danclement 2017-10-27 16:19:03 -06:00 committed by Martin Kojtal
parent 863b3fdcc1
commit 36d335baf4
3 changed files with 23 additions and 31 deletions

View File

@ -48,7 +48,6 @@
#define I2C_SPEED_400K_AT_8MHZ (uint8_t)0x03
#define I2C_SPEED_400K_AT_16MHZ (uint8_t)0x08
/* I2C commands */
#define I2C_CMD_NULL 0x00
#define I2C_CMD_WDAT0 0x10
@ -93,7 +92,10 @@
#define I2C_API_STATUS_SUCCESS 0
#define PAD_REG_ADRS_BYTE_SIZE 4
#define SEND_COMMAND(cmd) while(!I2C_FIFO_EMPTY); wait_us(1); obj->membase->CMD_REG = cmd;
// The wait_us(0) command is needed so the I2C state machines have enough
// time for data to settle across all clock domain crossings in their
// synchronizers, both directions.
#define SEND_COMMAND(cmd) wait_us(0); obj->membase->CMD_REG = cmd; wait_us(0);
/** Init I2C device.
* @details
@ -158,4 +160,4 @@ extern int32_t fI2cReadB(i2c_t *d, char *buf, int len);
*/
extern int32_t fI2cWriteB(i2c_t *d, const char *buf, int len);
#endif /* I2C_H_ */
#endif /* I2C_H_ */

View File

@ -169,9 +169,7 @@ int i2c_byte_write(i2c_t *obj, int data)
return Count;
}
while(obj->membase->STATUS.WORD & I2C_STATUS_CMD_FIFO_OFL_BIT); /* Wait till command overflow ends */
if(obj->membase->STATUS.WORD & I2C_STATUS_BUS_ERR_BIT) {
if(I2C_BUS_ERR_CHECK) {
/* Bus error means NAK received */
return 0;
} else {
@ -180,4 +178,4 @@ int i2c_byte_write(i2c_t *obj, int data)
}
}
#endif /* DEVICE_I2C */
#endif /* DEVICE_I2C */

View File

@ -65,7 +65,6 @@
/* See i2c.h for details */
void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
{
uint32_t clockDivisor;
/* 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);
@ -93,9 +92,7 @@ void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
obj->membase->CR.BITS.I2C_APB_CD_EN = True;
/* set default baud rate at 100k */
clockDivisor = ((fClockGetPeriphClockfrequency() / 100000) >> 2) - 2;
obj->membase->CR.BITS.CD_VAL = (clockDivisor & I2C_CLOCKDIVEDER_VAL_MASK);
obj->membase->PRE_SCALE_REG = (clockDivisor & I2C_APB_CLK_DIVIDER_VAL_MASK) >> 5; /**< Zero pre-scale value not allowed */
fI2cFrequency(obj, 100000);
/* Cross bar setting */
pinmap_pinout(sda, PinMap_I2C_SDA);
@ -110,8 +107,8 @@ void fI2cInit(i2c_t *obj,PinName sda,PinName scl)
PadReg_t *padRegScl = (PadReg_t*)(PADREG_BASE + (scl * PAD_REG_ADRS_BYTE_SIZE));
CLOCK_ENABLE(CLOCK_PAD);
padRegSda->PADIO0.BITS.POWER = 1; /* sda: Drive strength */
padRegScl->PADIO0.BITS.POWER = 1; /* scl: Drive strength */
padRegSda->PADIO0.BITS.POWER = 3; /* sda: Drive strength */
padRegScl->PADIO0.BITS.POWER = 3; /* scl: Drive strength */
CLOCK_DISABLE(CLOCK_PAD);
CLOCK_ENABLE(CLOCK_GPIO);
@ -160,7 +157,10 @@ int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
int32_t read = 0;
while (read < len) {
/* Send read command */
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
/* Send read command */
SEND_COMMAND(I2C_CMD_RDAT8);
while(!RD_DATA_READY) {
if (I2C_BUS_ERR_CHECK) {
@ -170,8 +170,8 @@ int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
}
buf[read++] = obj->membase->RD_FIFO_REG; /**< Reading 'read FIFO register' will clear status register */
if(!(read>=len)) { /* No ACK will be generated for the last read, upper level I2C protocol should generate */
SEND_COMMAND(I2C_CMD_WDAT0); /* TODO based on requirement generate ACK or NACK Based on the requirement. */
if(!(read>=len)) {
SEND_COMMAND(I2C_CMD_WDAT0);
} else {
/* No ack */
SEND_COMMAND(I2C_CMD_WDAT1);
@ -179,7 +179,7 @@ int32_t fI2cReadB(i2c_t *obj, char *buf, int len)
/* check for FIFO underflow */
if(I2C_UFL_CHECK) {
return I2C_ERROR_NO_SLAVE; /* TODO No error available for this in i2c_api.h */
return I2C_EVENT_ERROR;
}
if(I2C_BUS_ERR_CHECK) {
/* Bus error */
@ -196,8 +196,8 @@ int32_t fI2cWriteB(i2c_t *obj, const char *buf, int len)
int32_t write = 0;
while (write < len) {
/* Send write command */
SEND_COMMAND(I2C_CMD_WDAT8);
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
if(buf[write] == I2C_CMD_RDAT8) {
/* SW work around to counter FSM issue. If the only command in the CMD FIFO is the WDAT8 command (data of 0x13)
@ -205,35 +205,27 @@ int32_t fI2cWriteB(i2c_t *obj, const char *buf, int len)
RDAT8 command by the data FSM; resulting in an I2C bus error (NACK instead of an ACK). */
/* Send 0x13 bit wise */
SEND_COMMAND(I2C_CMD_WDAT0);
SEND_COMMAND(I2C_CMD_WDAT0);
SEND_COMMAND(I2C_CMD_WDAT0);
SEND_COMMAND(I2C_CMD_WDAT1);
SEND_COMMAND(I2C_CMD_WDAT0);
SEND_COMMAND(I2C_CMD_WDAT0);
SEND_COMMAND(I2C_CMD_WDAT1);
SEND_COMMAND(I2C_CMD_WDAT1);
write++;
} else {
/* Send data */
SEND_COMMAND(I2C_CMD_WDAT8);
SEND_COMMAND(buf[write++]);
}
SEND_COMMAND(I2C_CMD_VRFY_ACK); /* TODO Verify ACK based on requirement, Do we need? */
SEND_COMMAND(I2C_CMD_VRFY_ACK);
if (I2C_BUS_ERR_CHECK) {
/* Bus error */
return I2C_ERROR_BUS_BUSY;
}
while(FIFO_OFL_CHECK); /* Wait till command overflow ends */
}
return write;
}
#endif /* DEVICE_I2C */
#endif /* DEVICE_I2C */