From d29c12d233396506b704c8b1c164351a9a66c58b Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 9 Mar 2018 08:04:54 -0600 Subject: [PATCH 1/3] K82F: Fix I2C test failures seen with ci-test shield I2C3 clock define was missing. I2C3 is connected to the Arduino connector which is used by the ci-test shield Signed-off-by: Mahesh Mahadevan --- .../TARGET_K82F/peripheral_clock_defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/peripheral_clock_defines.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/peripheral_clock_defines.h index f65b2d9e4d..115b5975c4 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/peripheral_clock_defines.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/peripheral_clock_defines.h @@ -36,7 +36,7 @@ /* Array for I2C module clocks */ #define I2C_CLOCK_FREQS \ { \ - I2C0_CLK_SRC, I2C1_CLK_SRC, I2C2_CLK_SRC \ + I2C0_CLK_SRC, I2C1_CLK_SRC, I2C2_CLK_SRC, I2C3_CLK_SRC \ } /* Array for DSPI module clocks */ From 53fa4e5fc462187a2f86d6806d108376100258d4 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 9 Mar 2018 08:18:21 -0600 Subject: [PATCH 2/3] MCUXpresso: Enable I2C SDA & SCL pins internal pullup resistors Signed-off-by: Mahesh Mahadevan --- .../TARGET_MCUXpresso_MCUS/api/i2c_api.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 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 7ff72f3881..a731d5b193 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c @@ -36,6 +36,9 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) { uint32_t i2c_sda = pinmap_peripheral(sda, PinMap_I2C_SDA); uint32_t i2c_scl = pinmap_peripheral(scl, PinMap_I2C_SCL); + PORT_Type *port_addrs[] = PORT_BASE_PTRS; + PORT_Type *base = port_addrs[sda >> GPIO_PORT_SHIFT]; + obj->instance = pinmap_merge(i2c_sda, i2c_scl); obj->next_repeated_start = 0; MBED_ASSERT((int)obj->instance != NC); @@ -49,10 +52,11 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) pinmap_pinout(sda, PinMap_I2C_SDA); pinmap_pinout(scl, PinMap_I2C_SCL); -#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN - PORT_Type *port_addrs[] = PORT_BASE_PTRS; - PORT_Type *base = port_addrs[sda >> GPIO_PORT_SHIFT]; + /* Enable internal pullup resistor */ + base->PCR[sda & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK); + base->PCR[scl & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK); +#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN base->PCR[sda & 0xFF] |= PORT_PCR_ODE_MASK; base->PCR[scl & 0xFF] |= PORT_PCR_ODE_MASK; #endif From 5230bcaf6f2aebc754f7ba76eb537a8bd86b7318 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Fri, 9 Mar 2018 08:32:22 -0600 Subject: [PATCH 3/3] 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; }