mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			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
							parent
							
								
									863b3fdcc1
								
							
						
					
					
						commit
						36d335baf4
					
				| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue