From 5230bcaf6f2aebc754f7ba76eb537a8bd86b7318 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 9 Mar 2018 08:32:22 -0600 Subject: [PATCH] MCUXpresso: Update the I2C implmentation for byte read and write 1. Start function: Issue repeat start when bus is busy 2. Byte write function: Do not call SDK function as this does not work for some of the Kinetis device 3. Byte read function: Do not call SDK function as this would issue a START and STOP signal which is not required for I2C byte functions Signed-off-by: Mahesh Mahadevan --- .../TARGET_MCUXpresso_MCUS/api/i2c_api.c | 82 ++++++++++++------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c index a731d5b193..452faf781d 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c @@ -67,12 +67,14 @@ int i2c_start(i2c_t *obj) I2C_Type *base = i2c_addrs[obj->instance]; uint32_t statusFlags = I2C_MasterGetStatusFlags(base); - /* Return an error if the bus is already in use. */ + /* Check if the bus is already in use. */ if (statusFlags & kI2C_BusBusyFlag) { - return 1; + /* Send a repeat START signal. */ + base->C1 |= I2C_C1_RSTA_MASK; + } else { + /* Send the START signal. */ + base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK; } - /* Send the START signal. */ - base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK; #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING while (!(base->S2 & I2C_S2_EMPTY_MASK)) @@ -85,7 +87,6 @@ int i2c_start(i2c_t *obj) int i2c_stop(i2c_t *obj) { - obj->next_repeated_start = 0; if (I2C_MasterStop(i2c_addrs[obj->instance]) != kStatus_Success) { return 1; } @@ -183,39 +184,64 @@ int i2c_byte_read(i2c_t *obj, int last) { uint8_t data; I2C_Type *base = i2c_addrs[obj->instance]; - i2c_master_transfer_t master_xfer; - memset(&master_xfer, 0, sizeof(master_xfer)); - master_xfer.slaveAddress = i2c_address; - master_xfer.direction = kI2C_Read; - master_xfer.data = &data; - master_xfer.dataSize = 1; + /* Setup the I2C peripheral to receive data. */ + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); - /* The below function will issue a STOP signal at the end of the transfer. - * This is required by the hardware in order to receive the last byte - */ - if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) { - return I2C_ERROR_NO_SLAVE; + if (last) { + base->C1 |= I2C_C1_TXAK_MASK; // NACK } + + data = (base->D & 0xFF); + + /* Change direction to Tx to avoid extra clocks. */ + base->C1 |= I2C_C1_TX_MASK; + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; + return data; } int i2c_byte_write(i2c_t *obj, int data) { - status_t ret_value; -#if FSL_I2C_DRIVER_VERSION > MAKE_VERSION(2, 0, 1) - ret_value = I2C_MasterWriteBlocking(i2c_addrs[obj->instance], (uint8_t *)(&data), 1, kI2C_TransferNoStopFlag); -#else - ret_value = I2C_MasterWriteBlocking(i2c_addrs[obj->instance], (uint8_t *)(&data), 1); -#endif + int ret_value = 1; + uint8_t statusFlags = 0; + I2C_Type *base = i2c_addrs[obj->instance]; - if (ret_value == kStatus_Success) { - return 1; - } else if (ret_value == kStatus_I2C_Nak) { - return 0; - } else { - return 2; + /* Setup the I2C peripheral to transmit data. */ + base->C1 |= I2C_C1_TX_MASK; + + /* Send a byte of data. */ + base->D = data; + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) { } + + statusFlags = base->S; + + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; + + /* Check if arbitration lost */ + if (statusFlags & kI2C_ArbitrationLostFlag) { + base->S = kI2C_ArbitrationLostFlag; + ret_value = 2; + } + + /* Check if no acknowledgement (NAK) */ + if (statusFlags & kI2C_ReceiveNakFlag) { + base->S = kI2C_ReceiveNakFlag; + ret_value = 0; + } + + return ret_value; }