diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.c index b51fc07a15..6c9770af25 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -75,6 +75,19 @@ typedef void (*i2c_isr_t)(I2C_Type *base, void *i2cHandle); */ uint32_t I2C_GetInstance(I2C_Type *base); +/*! +* @brief Set SCL/SDA hold time, this API receives SCL stop hold time, calculate the +* closest SCL divider and MULT value for the SDA hold time, SCL start and SCL stop +* hold time. To reduce the ROM size, SDA/SCL hold value mapping table is not provided, +* assume SCL divider = SCL stop hold value *2 to get the closest SCL divider value and MULT +* value, then the related SDA hold time, SCL start and SCL stop hold time is used. +* +* @param base I2C peripheral base address. +* @param sourceClock_Hz I2C functional clock frequency in Hertz. +* @param sclStopHoldTime_ns SCL stop hold time in ns. +*/ +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz); + /*! * @brief Set up master transfer, send slave address and decide the initial * transfer state. @@ -137,8 +150,10 @@ static I2C_Type *const s_i2cBases[] = I2C_BASE_PTRS; /*! @brief Pointers to i2c IRQ number for each instance. */ static const IRQn_Type s_i2cIrqs[] = I2C_IRQS; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to i2c clocks for each instance. */ static const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief Pointer to master IRQ handler for each instance. */ static i2c_isr_t s_i2cMasterIsr; @@ -155,7 +170,7 @@ uint32_t I2C_GetInstance(I2C_Type *base) uint32_t instance; /* Find the instance index from base address mappings. */ - for (instance = 0; instance < FSL_FEATURE_SOC_I2C_COUNT; instance++) + for (instance = 0; instance < ARRAY_SIZE(s_i2cBases); instance++) { if (s_i2cBases[instance] == base) { @@ -163,16 +178,63 @@ uint32_t I2C_GetInstance(I2C_Type *base) } } - assert(instance < FSL_FEATURE_SOC_I2C_COUNT); + assert(instance < ARRAY_SIZE(s_i2cBases)); return instance; } +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz) +{ + uint32_t multiplier; + uint32_t computedSclHoldTime; + uint32_t absError; + uint32_t bestError = UINT32_MAX; + uint32_t bestMult = 0u; + uint32_t bestIcr = 0u; + uint8_t mult; + uint8_t i; + + /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register, + * and ranges from 0-2. It selects the multiplier factor for the divider. */ + /* SDA hold time = bus period (s) * mul * SDA hold value. */ + /* SCL start hold time = bus period (s) * mul * SCL start hold value. */ + /* SCL stop hold time = bus period (s) * mul * SCL stop hold value. */ + + for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult) + { + multiplier = 1u << mult; + + /* Scan table to find best match. */ + for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(s_i2cDividerTable[0]); ++i) + { + /* Assume SCL hold(stop) value = s_i2cDividerTable[i]/2. */ + computedSclHoldTime = ((multiplier * s_i2cDividerTable[i]) * 500000000U) / sourceClock_Hz; + absError = sclStopHoldTime_ns > computedSclHoldTime ? (sclStopHoldTime_ns - computedSclHoldTime) : + (computedSclHoldTime - sclStopHoldTime_ns); + + if (absError < bestError) + { + bestMult = mult; + bestIcr = i; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0) + { + break; + } + } + } + } + + /* Set frequency register based on best settings. */ + base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr); +} + static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer) { status_t result = kStatus_Success; i2c_direction_t direction = xfer->direction; - uint16_t timeout = UINT16_MAX; /* Initialize the handle transfer information. */ handle->transfer = *xfer; @@ -183,27 +245,13 @@ static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t /* Initial transfer state. */ if (handle->transfer.subaddressSize > 0) { - handle->state = kSendCommandState; if (xfer->direction == kI2C_Read) { direction = kI2C_Write; } } - else - { - handle->state = kCheckAddressState; - } - /* Wait until the data register is ready for transmit. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } + handle->state = kCheckAddressState; /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -265,34 +313,41 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han result = kStatus_Success; } - if (result) - { - return result; - } - /* Handle Check address state to check the slave address is Acked in slave probe application. */ if (handle->state == kCheckAddressState) { if (statusFlags & kI2C_ReceiveNakFlag) { - return kStatus_I2C_Nak; + result = kStatus_I2C_Addr_Nak; } else { - if (handle->transfer.direction == kI2C_Write) + if (handle->transfer.subaddressSize > 0) { - /* Next state, send data. */ - handle->state = kSendDataState; + handle->state = kSendCommandState; } else { - /* Next state, receive data begin. */ - handle->state = kReceiveDataBeginState; + if (handle->transfer.direction == kI2C_Write) + { + /* Next state, send data. */ + handle->state = kSendDataState; + } + else + { + /* Next state, receive data begin. */ + handle->state = kReceiveDataBeginState; + } } } } + if (result) + { + return result; + } + /* Run state machine. */ switch (handle->state) { @@ -375,6 +430,10 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han { result = I2C_MasterStop(base); } + else + { + base->C1 |= I2C_C1_TX_MASK; + } } /* Send NAK at the last receive byte. */ @@ -407,6 +466,7 @@ static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle) { s_i2cSlaveIsr(base, handle); } + __DSB(); } void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz) @@ -415,14 +475,26 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Temporary register for filter read. */ uint8_t fltReg; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - uint8_t c2Reg; -#endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE uint8_t s2Reg; #endif +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Enable I2C clock. */ CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Disable I2C prior to configuring it. */ base->C1 &= ~(I2C_C1_IICEN_MASK); @@ -433,14 +505,6 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Configure baud rate. */ I2C_MasterSetBaudRate(base, masterConfig->baudRate_Bps, srcClock_Hz); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Configure high drive feature. */ - c2Reg = base->C2; - c2Reg &= ~(I2C_C2_HDRS_MASK); - c2Reg |= I2C_C2_HDRS(masterConfig->enableHighDrive); - base->C2 = c2Reg; -#endif - /* Read out the FLT register. */ fltReg = base->FLT; @@ -472,8 +536,10 @@ void I2C_MasterDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) @@ -483,11 +549,6 @@ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) /* Default baud rate at 100kbps. */ masterConfig->baudRate_Bps = 100000U; -/* Default pin high drive is disabled. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - masterConfig->enableHighDrive = false; -#endif - /* Default stop hold enable is disabled. */ #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF masterConfig->enableStopHold = false; @@ -654,7 +715,7 @@ status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_ base->F = savedMult & (~I2C_F_MULT_MASK); /* We are already in a transfer, so send a repeated start. */ - base->C1 |= I2C_C1_RSTA_MASK; + base->C1 |= I2C_C1_RSTA_MASK | I2C_C1_TX_MASK; /* Restore the multiplier factor. */ base->F = savedMult; @@ -721,7 +782,7 @@ uint32_t I2C_MasterGetStatusFlags(I2C_Type *base) return statusFlags; } -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize) +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags) { status_t result = kStatus_Success; uint8_t statusFlags = 0; @@ -772,10 +833,19 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t } } + if (((result == kStatus_Success) && (!(flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) + { + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send stop. */ + result = I2C_MasterStop(base); + } + return result; } -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags) { status_t result = kStatus_Success; volatile uint8_t dummy = 0; @@ -817,8 +887,16 @@ status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) /* Single byte use case. */ if (rxSize == 0) { - /* Read the final byte. */ - result = I2C_MasterStop(base); + if (!(flags & kI2C_TransferNoStopFlag)) + { + /* Issue STOP command before reading last byte. */ + result = I2C_MasterStop(base); + } + else + { + /* Change direction to Tx to avoid extra clocks. */ + base->C1 |= I2C_C1_TX_MASK; + } } if (rxSize == 1) @@ -871,72 +949,6 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) return result; } - /* Send subaddress. */ - if (xfer->subaddressSize) - { - do - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear interrupt pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - xfer->subaddressSize--; - base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); - - } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); - - if (xfer->direction == kI2C_Read) - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - /* Send repeated start and slave address. */ - result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); - - /* Return if error. */ - if (result) - { - return result; - } - } - } - - /* Wait until address + command transfer complete. */ while (!(base->S & kI2C_IntPendingFlag)) { } @@ -949,32 +961,92 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) { if (result == kStatus_I2C_Nak) { + result = kStatus_I2C_Addr_Nak; + I2C_MasterStop(base); } return result; } + /* Send subaddress. */ + if (xfer->subaddressSize) + { + do + { + /* Clear interrupt pending flag. */ + base->S = kI2C_IntPendingFlag; + + xfer->subaddressSize--; + base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + I2C_MasterStop(base); + } + + return result; + } + + } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); + + if (xfer->direction == kI2C_Read) + { + /* Clear pending flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send repeated start and slave address. */ + result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); + + /* Return if error. */ + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + I2C_MasterStop(base); + } + + return result; + } + } + } + /* Transmit data. */ if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)) { /* Send Data. */ - result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize); - - if (((result == kStatus_Success) && (!(xfer->flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) - { - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; - - /* Send stop. */ - result = I2C_MasterStop(base); - } + result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } /* Receive Data. */ if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)) { - result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize); + result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } return result; @@ -1037,11 +1109,37 @@ void I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle) { assert(handle); + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + /* Disable interrupt. */ I2C_DisableInterrupts(base, kI2C_GlobalInterruptEnable); /* Reset the state to idle. */ handle->state = kIdleState; + + /* Send STOP signal. */ + if (handle->transfer.direction == kI2C_Read) + { + base->C1 |= I2C_C1_TXAK_MASK; + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + dummy = base->D; + } + else + { + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + } } status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count) @@ -1075,7 +1173,8 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) if (isDone || result) { /* Send stop command if transfer done or received Nak. */ - if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak)) + if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak) || + (result == kStatus_I2C_Addr_Nak)) { /* Ensure stop command is a need. */ if ((base->C1 & I2C_C1_MST_MASK)) @@ -1101,13 +1200,28 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz) { assert(slaveConfig); uint8_t tmpReg; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Configure addressing mode. */ switch (slaveConfig->addressingMode) @@ -1132,14 +1246,10 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg &= ~I2C_C1_WUEN_MASK; base->C1 = tmpReg | I2C_C1_WUEN(slaveConfig->enableWakeUp) | I2C_C1_IICEN(slaveConfig->enableSlave); - /* Configure general call & baud rate control & high drive feature. */ + /* Configure general call & baud rate control. */ tmpReg = base->C2; tmpReg &= ~(I2C_C2_SBRC_MASK | I2C_C2_GCAEN_MASK); tmpReg |= I2C_C2_SBRC(slaveConfig->enableBaudRateCtl) | I2C_C2_GCAEN(slaveConfig->enableGeneralCall); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - tmpReg &= ~I2C_C2_HDRS_MASK; - tmpReg |= I2C_C2_HDRS(slaveConfig->enableHighDrive); -#endif base->C2 = tmpReg; /* Enable/Disable double buffering. */ @@ -1147,6 +1257,9 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg = base->S2 & (~I2C_S2_DFEN_MASK); base->S2 = tmpReg | I2C_S2_DFEN(slaveConfig->enableDoubleBuffering); #endif + + /* Set hold time. */ + I2C_SetHoldTime(base, slaveConfig->sclStopHoldTime_ns, srcClock_Hz); } void I2C_SlaveDeinit(I2C_Type *base) @@ -1154,8 +1267,10 @@ void I2C_SlaveDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) @@ -1171,11 +1286,6 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) /* Slave address match waking up MCU from low power mode is disabled. */ slaveConfig->enableWakeUp = false; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Default pin high drive is disabled. */ - slaveConfig->enableHighDrive = false; -#endif - /* Independent slave mode baud rate at maximum frequency is disabled. */ slaveConfig->enableBaudRateCtl = false; @@ -1184,6 +1294,9 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) slaveConfig->enableDoubleBuffering = true; #endif + /* Set default SCL stop hold time to 4us which is minimum requirement in I2C spec. */ + slaveConfig->sclStopHoldTime_ns = 4000; + /* Enable the I2C peripheral. */ slaveConfig->enableSlave = true; } @@ -1215,7 +1328,7 @@ status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t tx /* Read dummy to release bus. */ dummy = base->D; - result = I2C_MasterWriteBlocking(base, txBuff, txSize); + result = I2C_MasterWriteBlocking(base, txBuff, txSize, kI2C_TransferDefaultFlag); /* Switch to receive mode. */ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); @@ -1323,7 +1436,7 @@ status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle handle->isBusy = true; /* Set up event mask. tx and rx are always enabled. */ - handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent; + handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | kI2C_SlaveGenaralcallEvent; /* Clear all flags. */ I2C_SlaveClearStatusFlags(base, kClearFlags); @@ -1412,7 +1525,10 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } - return; + if (!(status & kI2C_AddressMatchFlag)) + { + return; + } } #endif /* I2C_HAS_STOP_DETECT */ @@ -1482,11 +1598,6 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) handle->isBusy = true; xfer->event = kI2C_SlaveAddressMatchEvent; - if ((handle->eventMask & xfer->event) && (handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - /* Slave transmit, master reading from slave. */ if (status & kI2C_TransferDirectionFlag) { @@ -1502,6 +1613,16 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) /* Read dummy to release the bus. */ dummy = base->D; + + if (dummy == 0) + { + xfer->event = kI2C_SlaveGenaralcallEvent; + } + } + + if ((handle->eventMask & xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); } } /* Check transfer complete flag. */ @@ -1607,27 +1728,30 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } +#if defined(I2C0) void I2C0_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C0, s_i2cHandle[0]); } +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 1) +#if defined(I2C1) void I2C1_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C1, s_i2cHandle[1]); } -#endif /* I2C COUNT > 1 */ +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 2) +#if defined(I2C2) void I2C2_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C2, s_i2cHandle[2]); } -#endif /* I2C COUNT > 2 */ -#if (FSL_FEATURE_SOC_I2C_COUNT > 3) +#endif + +#if defined(I2C3) void I2C3_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C3, s_i2cHandle[3]); } -#endif /* I2C COUNT > 3 */ +#endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.h index 7117fd5753..d55fd1d8ea 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -37,15 +37,14 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ /*! @name Driver version */ /*@{*/ -/*! @brief I2C driver version 2.0.1. */ -#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) +/*! @brief I2C driver version 2.0.3. */ +#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 3)) /*@}*/ #if (defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT || \ @@ -61,6 +60,7 @@ enum _i2c_status kStatus_I2C_Nak = MAKE_STATUS(kStatusGroup_I2C, 2), /*!< NAK received during transfer. */ kStatus_I2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_I2C, 3), /*!< Arbitration lost during transfer. */ kStatus_I2C_Timeout = MAKE_STATUS(kStatusGroup_I2C, 4), /*!< Wait event timeout. */ + kStatus_I2C_Addr_Nak = MAKE_STATUS(kStatusGroup_I2C, 5), /*!< NAK received during the address probe. */ }; /*! @@ -108,11 +108,11 @@ enum _i2c_interrupt_enable #endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ }; -/*! @brief Direction of master and slave transfers. */ +/*! @brief The direction of master and slave transfers. */ typedef enum _i2c_direction { - kI2C_Write = 0x0U, /*!< Master transmit to slave. */ - kI2C_Read = 0x1U, /*!< Master receive from slave. */ + kI2C_Write = 0x0U, /*!< Master transmits to the slave. */ + kI2C_Read = 0x1U, /*!< Master receives from the slave. */ } i2c_direction_t; /*! @brief Addressing mode. */ @@ -125,17 +125,17 @@ typedef enum _i2c_slave_address_mode /*! @brief I2C transfer control flag. */ enum _i2c_master_transfer_flags { - kI2C_TransferDefaultFlag = 0x0U, /*!< Transfer starts with a start signal, stops with a stop signal. */ - kI2C_TransferNoStartFlag = 0x1U, /*!< Transfer starts without a start signal. */ - kI2C_TransferRepeatedStartFlag = 0x2U, /*!< Transfer starts with a repeated start signal. */ - kI2C_TransferNoStopFlag = 0x4U, /*!< Transfer ends without a stop signal. */ + kI2C_TransferDefaultFlag = 0x0U, /*!< A transfer starts with a start signal, stops with a stop signal. */ + kI2C_TransferNoStartFlag = 0x1U, /*!< A transfer starts without a start signal. */ + kI2C_TransferRepeatedStartFlag = 0x2U, /*!< A transfer starts with a repeated start signal. */ + kI2C_TransferNoStopFlag = 0x4U, /*!< A transfer ends without a stop signal. */ }; /*! * @brief Set of events sent to the callback for nonblocking slave transfers. * * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together - * events is passed to I2C_SlaveTransferNonBlocking() in order to specify which events to enable. + * events is passed to I2C_SlaveTransferNonBlocking() to specify which events to enable. * Then, when the slave callback is invoked, it is passed the current event through its @a transfer * parameter. * @@ -144,36 +144,34 @@ enum _i2c_master_transfer_flags typedef enum _i2c_slave_transfer_event { kI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */ - kI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit + kI2C_SlaveTransmitEvent = 0x02U, /*!< A callback is requested to provide data to transmit (slave-transmitter role). */ - kI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received + kI2C_SlaveReceiveEvent = 0x04U, /*!< A callback is requested to provide a buffer in which to place received data (slave-receiver role). */ - kI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */ + kI2C_SlaveTransmitAckEvent = 0x08U, /*!< A callback needs to either transmit an ACK or NACK. */ #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT kI2C_SlaveStartEvent = 0x10U, /*!< A start/repeated start was detected. */ #endif - kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveGenaralcallEvent = 0x40U, /*!< Received the general call address after a start or repeated start. */ - /*! Bit mask of all available events. */ + /*! A bit mask of all available events. */ kI2C_SlaveAllEvents = kI2C_SlaveAddressMatchEvent | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT kI2C_SlaveStartEvent | #endif - kI2C_SlaveCompletionEvent, + kI2C_SlaveCompletionEvent | kI2C_SlaveGenaralcallEvent, } i2c_slave_transfer_event_t; /*! @brief I2C master user configuration. */ typedef struct _i2c_master_config { bool enableMaster; /*!< Enables the I2C peripheral at initialization time. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF bool enableStopHold; /*!< Controls the stop hold enable. */ #endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE - bool enableDoubleBuffering; /*!< Controls double buffer enable, notice that + bool enableDoubleBuffering; /*!< Controls double buffer enable; notice that enabling the double buffer disables the clock stretch. */ #endif uint32_t baudRate_Bps; /*!< Baud rate configuration of I2C peripheral. */ @@ -184,19 +182,20 @@ typedef struct _i2c_master_config typedef struct _i2c_slave_config { bool enableSlave; /*!< Enables the I2C peripheral at initialization time. */ - bool enableGeneralCall; /*!< Enable general call addressing mode. */ + bool enableGeneralCall; /*!< Enables the general call addressing mode. */ bool enableWakeUp; /*!< Enables/disables waking up MCU from low-power mode. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE - bool enableDoubleBuffering; /*!< Controls double buffer enable, notice that + bool enableDoubleBuffering; /*!< Controls a double buffer enable; notice that enabling the double buffer disables the clock stretch. */ #endif bool enableBaudRateCtl; /*!< Enables/disables independent slave baud rate on SCL in very fast I2C modes. */ - uint16_t slaveAddress; /*!< Slave address configuration. */ - uint16_t upperAddress; /*!< Maximum boundary slave address used in range matching mode. */ - i2c_slave_address_mode_t addressingMode; /*!< Addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint16_t slaveAddress; /*!< A slave address configuration. */ + uint16_t upperAddress; /*!< A maximum boundary slave address used in a range matching mode. */ + i2c_slave_address_mode_t + addressingMode; /*!< An addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint32_t sclStopHoldTime_ns; /*!< the delay from the rising edge of SCL (I2C clock) to the rising edge of SDA (I2C + data) while SCL is high (stop condition), SDA hold time and SCL start hold time + are also configured according to the SCL stop hold time. */ } i2c_slave_config_t; /*! @brief I2C master handle typedef. */ @@ -214,13 +213,13 @@ typedef struct _i2c_slave_handle i2c_slave_handle_t; /*! @brief I2C master transfer structure. */ typedef struct _i2c_master_transfer { - uint32_t flags; /*!< Transfer flag which controls the transfer. */ + uint32_t flags; /*!< A transfer flag which controls the transfer. */ uint8_t slaveAddress; /*!< 7-bit slave address. */ - i2c_direction_t direction; /*!< Transfer direction, read or write. */ - uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ - uint8_t subaddressSize; /*!< Size of command buffer. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_direction_t direction; /*!< A transfer direction, read or write. */ + uint32_t subaddress; /*!< A sub address. Transferred MSB first. */ + uint8_t subaddressSize; /*!< A size of the command buffer. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ } i2c_master_transfer_t; /*! @brief I2C master handle structure. */ @@ -228,20 +227,21 @@ struct _i2c_master_handle { i2c_master_transfer_t transfer; /*!< I2C master transfer copy. */ size_t transferSize; /*!< Total bytes to be transferred. */ - uint8_t state; /*!< Transfer state maintained during transfer. */ - i2c_master_transfer_callback_t completionCallback; /*!< Callback function called when transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + uint8_t state; /*!< A transfer state maintained during transfer. */ + i2c_master_transfer_callback_t completionCallback; /*!< A callback function called when the transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /*! @brief I2C slave transfer structure. */ typedef struct _i2c_slave_transfer { - i2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_slave_transfer_event_t event; /*!< A reason that the callback is invoked. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for #kI2C_SlaveCompletionEvent. */ - size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */ + size_t transferredCount; /*!< A number of bytes actually transferred since the start or since the last repeated + start. */ } i2c_slave_transfer_t; /*! @brief I2C slave transfer callback typedef. */ @@ -250,11 +250,11 @@ typedef void (*i2c_slave_transfer_callback_t)(I2C_Type *base, i2c_slave_transfer /*! @brief I2C slave handle structure. */ struct _i2c_slave_handle { - bool isBusy; /*!< Whether transfer is busy. */ + volatile bool isBusy; /*!< Indicates whether a transfer is busy. */ i2c_slave_transfer_t transfer; /*!< I2C slave transfer copy. */ - uint32_t eventMask; /*!< Mask of enabled events. */ - i2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */ - void *userData; /*!< Callback parameter passed to callback. */ + uint32_t eventMask; /*!< A mask of enabled events. */ + i2c_slave_transfer_callback_t callback; /*!< A callback function called at the transfer event. */ + void *userData; /*!< A callback parameter passed to the callback. */ }; /******************************************************************************* @@ -274,12 +274,12 @@ extern "C" { * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock * and configure the I2C with master configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module may cause a hard fault - * because clock is not enabled. The configuration structure can be filled by user - * from scratch, or be set with default values by I2C_MasterGetDefaultConfig(). + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can be custom filled + * or it can be set with default values by using the I2C_MasterGetDefaultConfig(). * After calling this API, the master is ready to transfer. - * Example: + * This is an example. * @code * i2c_master_config_t config = { * .enableMaster = true, @@ -292,20 +292,20 @@ extern "C" { * @endcode * * @param base I2C base pointer - * @param masterConfig pointer to master configuration structure + * @param masterConfig A pointer to the master configuration structure * @param srcClock_Hz I2C peripheral clock frequency in Hz */ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz); /*! * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock - * and initializes the I2C with slave configuration. + * and initialize the I2C with the slave configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module can cause a hard fault + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault * because the clock is not enabled. The configuration structure can partly be set - * with default values by I2C_SlaveGetDefaultConfig(), or can be filled by the user. - * Example + * with default values by I2C_SlaveGetDefaultConfig() or it can be custom filled by the user. + * This is an example. * @code * i2c_slave_config_t config = { * .enableSlave = true, @@ -314,15 +314,17 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin * .slaveAddress = 0x1DU, * .enableWakeUp = false, * .enablehighDrive = false, - * .enableBaudRateCtl = false + * .enableBaudRateCtl = false, + * .sclStopHoldTime_ns = 4000 * }; - * I2C_SlaveInit(I2C0, &config); + * I2C_SlaveInit(I2C0, &config, 12000000U); * @endcode * * @param base I2C base pointer - * @param slaveConfig pointer to slave configuration structure + * @param slaveConfig A pointer to the slave configuration structure + * @param srcClock_Hz I2C peripheral clock frequency in Hz */ -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig); +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz); /*! * @brief De-initializes the I2C master peripheral. Call this API to gate the I2C clock. @@ -342,28 +344,28 @@ void I2C_SlaveDeinit(I2C_Type *base); * @brief Sets the I2C master configuration structure to default values. * * The purpose of this API is to get the configuration structure initialized for use in the I2C_MasterConfigure(). - * Use the initialized structure unchanged in I2C_MasterConfigure(), or modify some fields of - * the structure before calling I2C_MasterConfigure(). - * Example: + * Use the initialized structure unchanged in the I2C_MasterConfigure() or modify + * the structure before calling the I2C_MasterConfigure(). + * This is an example. * @code * i2c_master_config_t config; * I2C_MasterGetDefaultConfig(&config); * @endcode - * @param masterConfig Pointer to the master configuration structure. + * @param masterConfig A pointer to the master configuration structure. */ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig); /*! * @brief Sets the I2C slave configuration structure to default values. * - * The purpose of this API is to get the configuration structure initialized for use in I2C_SlaveConfigure(). + * The purpose of this API is to get the configuration structure initialized for use in the I2C_SlaveConfigure(). * Modify fields of the structure before calling the I2C_SlaveConfigure(). - * Example: + * This is an example. * @code * i2c_slave_config_t config; * I2C_SlaveGetDefaultConfig(&config); * @endcode - * @param slaveConfig Pointer to the slave configuration structure. + * @param slaveConfig A pointer to the slave configuration structure. */ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); @@ -371,7 +373,7 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); * @brief Enables or disabless the I2C peripheral operation. * * @param base I2C base pointer - * @param enable pass true to enable module, false to disable module + * @param enable Pass true to enable and false to disable the module. */ static inline void I2C_Enable(I2C_Type *base, bool enable) { @@ -414,7 +416,7 @@ static inline uint32_t I2C_SlaveGetStatusFlags(I2C_Type *base) /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag. * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. @@ -449,7 +451,7 @@ static inline void I2C_MasterClearStatusFlags(I2C_Type *base, uint32_t statusMas /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. @@ -581,19 +583,21 @@ status_t I2C_MasterStop(I2C_Type *base); status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction); /*! - * @brief Performs a polling send transaction on the I2C bus without a STOP signal. + * @brief Performs a polling send transaction on the I2C bus. * * @param base The I2C peripheral base pointer. * @param txBuff The pointer to the data to be transferred. * @param txSize The length in bytes of the data to be transferred. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize); +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags); /*! - * @brief Performs a polling receive transaction on the I2C bus with a STOP signal. + * @brief Performs a polling receive transaction on the I2C bus. * * @note The I2C_MasterReadBlocking function stops the bus before reading the final byte. * Without stopping the bus prior for the final read, the bus issues another read, resulting @@ -602,10 +606,12 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t * @param base I2C peripheral base pointer. * @param rxBuff The pointer to the data to store the received data. * @param rxSize The length in bytes of the data to be received. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_Timeout Send stop signal failed, timeout. */ -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize); +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags); /*! * @brief Performs a polling send transaction on the I2C bus. diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.c index c8f7c20629..28a415e075 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -162,6 +162,26 @@ static void I2C_MasterTransferCallbackEDMA(edma_handle_t *handle, void *userData result = I2C_MasterStop(i2cPrivateHandle->base); } } + else + { + if (i2cPrivateHandle->handle->transfer.direction == kI2C_Read) + { + /* Change to send NAK at the last byte. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TXAK_MASK; + + /* Wait the last data to be received. */ + while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag)) + { + } + + /* Change direction to send. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TX_MASK; + + /* Read the last data byte. */ + *(i2cPrivateHandle->handle->transfer.data + i2cPrivateHandle->handle->transfer.dataSize - 1) = + i2cPrivateHandle->base->D; + } + } i2cPrivateHandle->handle->state = kIdleState; @@ -203,7 +223,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, assert(xfer); status_t result = kStatus_Success; - uint16_t timeout = UINT16_MAX; if (handle->state != kIdleState) { @@ -221,16 +240,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, handle->state = kTransferDataState; - /* Wait until ready to complete. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -250,22 +259,55 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction); } + if (result) + { + return result; + } + + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + /* Return if error. */ + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + if (I2C_MasterStop(base) != kStatus_Success) + { + result = kStatus_I2C_Timeout; + } + + if (handle->completionCallback) + { + (handle->completionCallback)(base, handle, result, handle->userData); + } + } + + return result; + } + /* Send subaddress. */ if (handle->transfer.subaddressSize) { do { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear interrupt pending flag. */ base->S = kI2C_IntPendingFlag; handle->transfer.subaddressSize--; base->D = ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize)); + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + /* Check if there's transfer error. */ result = I2C_CheckAndClearError(base, base->S); @@ -278,34 +320,34 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, if (handle->transfer.direction == kI2C_Read) { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; /* Send repeated start and slave address. */ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read); + + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + return result; + } } } - if (result) - { - return result; - } - - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); } return result; @@ -319,17 +361,7 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ { transfer_config.srcAddr = (uint32_t)I2C_GetDataRegAddr(base); transfer_config.destAddr = (uint32_t)(handle->transfer.data); - - /* Send stop if kI2C_TransferNoStop flag is not asserted. */ - if (!(handle->transfer.flags & kI2C_TransferNoStopFlag)) - { - transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); - } - else - { - transfer_config.majorLoopCounts = handle->transfer.dataSize; - } - + transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); transfer_config.srcTransferSize = kEDMA_TransferSize1Bytes; transfer_config.srcOffset = 0; transfer_config.destTransferSize = kEDMA_TransferSize1Bytes; @@ -348,6 +380,9 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ transfer_config.minorLoopBytes = 1; } + /* Store the initially configured eDMA minor byte transfer count into the I2C handle */ + handle->nbytes = transfer_config.minorLoopBytes; + EDMA_SubmitTransfer(handle->dmaHandle, &transfer_config); EDMA_StartTransfer(handle->dmaHandle); } @@ -427,7 +462,7 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle if (handle->transfer.direction == kI2C_Read) { /* Change direction for receive. */ - base->C1 &= ~I2C_C1_TX_MASK; + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); /* Read dummy to release the bus. */ dummy = base->D; @@ -479,6 +514,11 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle { result = I2C_MasterStop(base); } + else + { + /* Change direction to send. */ + base->C1 |= I2C_C1_TX_MASK; + } /* Read the last byte of data. */ if (handle->transfer.direction == kI2C_Read) @@ -504,7 +544,9 @@ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t if (kIdleState != handle->state) { - *count = (handle->transferSize - EDMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel)); + *count = (handle->transferSize - + (uint32_t)handle->nbytes * + EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel)); } else { diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.h index c95d6adeee..40cb648ea9 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL82Z/drivers/fsl_i2c_edma.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -39,7 +39,6 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ @@ -56,13 +55,14 @@ typedef void (*i2c_master_edma_transfer_callback_t)(I2C_Type *base, /*! @brief I2C master eDMA transfer structure. */ struct _i2c_master_edma_handle { - i2c_master_transfer_t transfer; /*!< I2C master transfer struct. */ + i2c_master_transfer_t transfer; /*!< I2C master transfer structure. */ size_t transferSize; /*!< Total bytes to be transferred. */ + uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */ uint8_t state; /*!< I2C master transfer status. */ edma_handle_t *dmaHandle; /*!< The eDMA handler used. */ i2c_master_edma_transfer_callback_t - completionCallback; /*!< Callback function called after eDMA transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + completionCallback; /*!< A callback function called after the eDMA transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /******************************************************************************* @@ -79,12 +79,12 @@ extern "C" { */ /*! - * @brief Init the I2C handle which is used in transcational functions. + * @brief Initializes the I2C handle which is used in transcational functions. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param callback pointer to user callback function. - * @param userData user param passed to the callback function. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param callback A pointer to the user callback function. + * @param userData A user parameter passed to the callback function. * @param edmaHandle eDMA handle pointer. */ void I2C_MasterCreateEDMAHandle(I2C_Type *base, @@ -97,30 +97,30 @@ void I2C_MasterCreateEDMAHandle(I2C_Type *base, * @brief Performs a master eDMA non-blocking transfer on the I2C bus. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param xfer pointer to transfer structure of i2c_master_transfer_t. - * @retval kStatus_Success Sucessully complete the data transmission. - * @retval kStatus_I2C_Busy Previous transmission still not finished. - * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param xfer A pointer to the transfer structure of i2c_master_transfer_t. + * @retval kStatus_Success Sucessfully completed the data transmission. + * @retval kStatus_I2C_Busy A previous transmission is still not finished. + * @retval kStatus_I2C_Timeout Transfer error, waits for a signal timeout. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. - * @retval kStataus_I2C_Nak Transfer error, receive Nak during transfer. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, i2c_master_transfer_t *xfer); /*! - * @brief Get master transfer status during a eDMA non-blocking transfer. + * @brief Gets a master transfer status during the eDMA non-blocking transfer. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param count Number of bytes transferred so far by the non-blocking transaction. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param count A number of bytes transferred by the non-blocking transaction. */ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, size_t *count); /*! - * @brief Abort a master eDMA non-blocking transfer in a early time. + * @brief Aborts a master eDMA non-blocking transfer early. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. + * @param handle A pointer to the i2c_master_edma_handle_t structure. */ void I2C_MasterTransferAbortEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle); diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.c index b51fc07a15..6c9770af25 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -75,6 +75,19 @@ typedef void (*i2c_isr_t)(I2C_Type *base, void *i2cHandle); */ uint32_t I2C_GetInstance(I2C_Type *base); +/*! +* @brief Set SCL/SDA hold time, this API receives SCL stop hold time, calculate the +* closest SCL divider and MULT value for the SDA hold time, SCL start and SCL stop +* hold time. To reduce the ROM size, SDA/SCL hold value mapping table is not provided, +* assume SCL divider = SCL stop hold value *2 to get the closest SCL divider value and MULT +* value, then the related SDA hold time, SCL start and SCL stop hold time is used. +* +* @param base I2C peripheral base address. +* @param sourceClock_Hz I2C functional clock frequency in Hertz. +* @param sclStopHoldTime_ns SCL stop hold time in ns. +*/ +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz); + /*! * @brief Set up master transfer, send slave address and decide the initial * transfer state. @@ -137,8 +150,10 @@ static I2C_Type *const s_i2cBases[] = I2C_BASE_PTRS; /*! @brief Pointers to i2c IRQ number for each instance. */ static const IRQn_Type s_i2cIrqs[] = I2C_IRQS; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to i2c clocks for each instance. */ static const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief Pointer to master IRQ handler for each instance. */ static i2c_isr_t s_i2cMasterIsr; @@ -155,7 +170,7 @@ uint32_t I2C_GetInstance(I2C_Type *base) uint32_t instance; /* Find the instance index from base address mappings. */ - for (instance = 0; instance < FSL_FEATURE_SOC_I2C_COUNT; instance++) + for (instance = 0; instance < ARRAY_SIZE(s_i2cBases); instance++) { if (s_i2cBases[instance] == base) { @@ -163,16 +178,63 @@ uint32_t I2C_GetInstance(I2C_Type *base) } } - assert(instance < FSL_FEATURE_SOC_I2C_COUNT); + assert(instance < ARRAY_SIZE(s_i2cBases)); return instance; } +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz) +{ + uint32_t multiplier; + uint32_t computedSclHoldTime; + uint32_t absError; + uint32_t bestError = UINT32_MAX; + uint32_t bestMult = 0u; + uint32_t bestIcr = 0u; + uint8_t mult; + uint8_t i; + + /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register, + * and ranges from 0-2. It selects the multiplier factor for the divider. */ + /* SDA hold time = bus period (s) * mul * SDA hold value. */ + /* SCL start hold time = bus period (s) * mul * SCL start hold value. */ + /* SCL stop hold time = bus period (s) * mul * SCL stop hold value. */ + + for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult) + { + multiplier = 1u << mult; + + /* Scan table to find best match. */ + for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(s_i2cDividerTable[0]); ++i) + { + /* Assume SCL hold(stop) value = s_i2cDividerTable[i]/2. */ + computedSclHoldTime = ((multiplier * s_i2cDividerTable[i]) * 500000000U) / sourceClock_Hz; + absError = sclStopHoldTime_ns > computedSclHoldTime ? (sclStopHoldTime_ns - computedSclHoldTime) : + (computedSclHoldTime - sclStopHoldTime_ns); + + if (absError < bestError) + { + bestMult = mult; + bestIcr = i; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0) + { + break; + } + } + } + } + + /* Set frequency register based on best settings. */ + base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr); +} + static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer) { status_t result = kStatus_Success; i2c_direction_t direction = xfer->direction; - uint16_t timeout = UINT16_MAX; /* Initialize the handle transfer information. */ handle->transfer = *xfer; @@ -183,27 +245,13 @@ static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t /* Initial transfer state. */ if (handle->transfer.subaddressSize > 0) { - handle->state = kSendCommandState; if (xfer->direction == kI2C_Read) { direction = kI2C_Write; } } - else - { - handle->state = kCheckAddressState; - } - /* Wait until the data register is ready for transmit. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } + handle->state = kCheckAddressState; /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -265,34 +313,41 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han result = kStatus_Success; } - if (result) - { - return result; - } - /* Handle Check address state to check the slave address is Acked in slave probe application. */ if (handle->state == kCheckAddressState) { if (statusFlags & kI2C_ReceiveNakFlag) { - return kStatus_I2C_Nak; + result = kStatus_I2C_Addr_Nak; } else { - if (handle->transfer.direction == kI2C_Write) + if (handle->transfer.subaddressSize > 0) { - /* Next state, send data. */ - handle->state = kSendDataState; + handle->state = kSendCommandState; } else { - /* Next state, receive data begin. */ - handle->state = kReceiveDataBeginState; + if (handle->transfer.direction == kI2C_Write) + { + /* Next state, send data. */ + handle->state = kSendDataState; + } + else + { + /* Next state, receive data begin. */ + handle->state = kReceiveDataBeginState; + } } } } + if (result) + { + return result; + } + /* Run state machine. */ switch (handle->state) { @@ -375,6 +430,10 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han { result = I2C_MasterStop(base); } + else + { + base->C1 |= I2C_C1_TX_MASK; + } } /* Send NAK at the last receive byte. */ @@ -407,6 +466,7 @@ static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle) { s_i2cSlaveIsr(base, handle); } + __DSB(); } void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz) @@ -415,14 +475,26 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Temporary register for filter read. */ uint8_t fltReg; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - uint8_t c2Reg; -#endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE uint8_t s2Reg; #endif +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Enable I2C clock. */ CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Disable I2C prior to configuring it. */ base->C1 &= ~(I2C_C1_IICEN_MASK); @@ -433,14 +505,6 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Configure baud rate. */ I2C_MasterSetBaudRate(base, masterConfig->baudRate_Bps, srcClock_Hz); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Configure high drive feature. */ - c2Reg = base->C2; - c2Reg &= ~(I2C_C2_HDRS_MASK); - c2Reg |= I2C_C2_HDRS(masterConfig->enableHighDrive); - base->C2 = c2Reg; -#endif - /* Read out the FLT register. */ fltReg = base->FLT; @@ -472,8 +536,10 @@ void I2C_MasterDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) @@ -483,11 +549,6 @@ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) /* Default baud rate at 100kbps. */ masterConfig->baudRate_Bps = 100000U; -/* Default pin high drive is disabled. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - masterConfig->enableHighDrive = false; -#endif - /* Default stop hold enable is disabled. */ #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF masterConfig->enableStopHold = false; @@ -654,7 +715,7 @@ status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_ base->F = savedMult & (~I2C_F_MULT_MASK); /* We are already in a transfer, so send a repeated start. */ - base->C1 |= I2C_C1_RSTA_MASK; + base->C1 |= I2C_C1_RSTA_MASK | I2C_C1_TX_MASK; /* Restore the multiplier factor. */ base->F = savedMult; @@ -721,7 +782,7 @@ uint32_t I2C_MasterGetStatusFlags(I2C_Type *base) return statusFlags; } -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize) +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags) { status_t result = kStatus_Success; uint8_t statusFlags = 0; @@ -772,10 +833,19 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t } } + if (((result == kStatus_Success) && (!(flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) + { + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send stop. */ + result = I2C_MasterStop(base); + } + return result; } -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags) { status_t result = kStatus_Success; volatile uint8_t dummy = 0; @@ -817,8 +887,16 @@ status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) /* Single byte use case. */ if (rxSize == 0) { - /* Read the final byte. */ - result = I2C_MasterStop(base); + if (!(flags & kI2C_TransferNoStopFlag)) + { + /* Issue STOP command before reading last byte. */ + result = I2C_MasterStop(base); + } + else + { + /* Change direction to Tx to avoid extra clocks. */ + base->C1 |= I2C_C1_TX_MASK; + } } if (rxSize == 1) @@ -871,72 +949,6 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) return result; } - /* Send subaddress. */ - if (xfer->subaddressSize) - { - do - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear interrupt pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - xfer->subaddressSize--; - base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); - - } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); - - if (xfer->direction == kI2C_Read) - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - /* Send repeated start and slave address. */ - result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); - - /* Return if error. */ - if (result) - { - return result; - } - } - } - - /* Wait until address + command transfer complete. */ while (!(base->S & kI2C_IntPendingFlag)) { } @@ -949,32 +961,92 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) { if (result == kStatus_I2C_Nak) { + result = kStatus_I2C_Addr_Nak; + I2C_MasterStop(base); } return result; } + /* Send subaddress. */ + if (xfer->subaddressSize) + { + do + { + /* Clear interrupt pending flag. */ + base->S = kI2C_IntPendingFlag; + + xfer->subaddressSize--; + base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + I2C_MasterStop(base); + } + + return result; + } + + } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); + + if (xfer->direction == kI2C_Read) + { + /* Clear pending flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send repeated start and slave address. */ + result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); + + /* Return if error. */ + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + I2C_MasterStop(base); + } + + return result; + } + } + } + /* Transmit data. */ if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)) { /* Send Data. */ - result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize); - - if (((result == kStatus_Success) && (!(xfer->flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) - { - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; - - /* Send stop. */ - result = I2C_MasterStop(base); - } + result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } /* Receive Data. */ if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)) { - result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize); + result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } return result; @@ -1037,11 +1109,37 @@ void I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle) { assert(handle); + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + /* Disable interrupt. */ I2C_DisableInterrupts(base, kI2C_GlobalInterruptEnable); /* Reset the state to idle. */ handle->state = kIdleState; + + /* Send STOP signal. */ + if (handle->transfer.direction == kI2C_Read) + { + base->C1 |= I2C_C1_TXAK_MASK; + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + dummy = base->D; + } + else + { + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + } } status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count) @@ -1075,7 +1173,8 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) if (isDone || result) { /* Send stop command if transfer done or received Nak. */ - if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak)) + if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak) || + (result == kStatus_I2C_Addr_Nak)) { /* Ensure stop command is a need. */ if ((base->C1 & I2C_C1_MST_MASK)) @@ -1101,13 +1200,28 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz) { assert(slaveConfig); uint8_t tmpReg; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Configure addressing mode. */ switch (slaveConfig->addressingMode) @@ -1132,14 +1246,10 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg &= ~I2C_C1_WUEN_MASK; base->C1 = tmpReg | I2C_C1_WUEN(slaveConfig->enableWakeUp) | I2C_C1_IICEN(slaveConfig->enableSlave); - /* Configure general call & baud rate control & high drive feature. */ + /* Configure general call & baud rate control. */ tmpReg = base->C2; tmpReg &= ~(I2C_C2_SBRC_MASK | I2C_C2_GCAEN_MASK); tmpReg |= I2C_C2_SBRC(slaveConfig->enableBaudRateCtl) | I2C_C2_GCAEN(slaveConfig->enableGeneralCall); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - tmpReg &= ~I2C_C2_HDRS_MASK; - tmpReg |= I2C_C2_HDRS(slaveConfig->enableHighDrive); -#endif base->C2 = tmpReg; /* Enable/Disable double buffering. */ @@ -1147,6 +1257,9 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg = base->S2 & (~I2C_S2_DFEN_MASK); base->S2 = tmpReg | I2C_S2_DFEN(slaveConfig->enableDoubleBuffering); #endif + + /* Set hold time. */ + I2C_SetHoldTime(base, slaveConfig->sclStopHoldTime_ns, srcClock_Hz); } void I2C_SlaveDeinit(I2C_Type *base) @@ -1154,8 +1267,10 @@ void I2C_SlaveDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) @@ -1171,11 +1286,6 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) /* Slave address match waking up MCU from low power mode is disabled. */ slaveConfig->enableWakeUp = false; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Default pin high drive is disabled. */ - slaveConfig->enableHighDrive = false; -#endif - /* Independent slave mode baud rate at maximum frequency is disabled. */ slaveConfig->enableBaudRateCtl = false; @@ -1184,6 +1294,9 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) slaveConfig->enableDoubleBuffering = true; #endif + /* Set default SCL stop hold time to 4us which is minimum requirement in I2C spec. */ + slaveConfig->sclStopHoldTime_ns = 4000; + /* Enable the I2C peripheral. */ slaveConfig->enableSlave = true; } @@ -1215,7 +1328,7 @@ status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t tx /* Read dummy to release bus. */ dummy = base->D; - result = I2C_MasterWriteBlocking(base, txBuff, txSize); + result = I2C_MasterWriteBlocking(base, txBuff, txSize, kI2C_TransferDefaultFlag); /* Switch to receive mode. */ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); @@ -1323,7 +1436,7 @@ status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle handle->isBusy = true; /* Set up event mask. tx and rx are always enabled. */ - handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent; + handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | kI2C_SlaveGenaralcallEvent; /* Clear all flags. */ I2C_SlaveClearStatusFlags(base, kClearFlags); @@ -1412,7 +1525,10 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } - return; + if (!(status & kI2C_AddressMatchFlag)) + { + return; + } } #endif /* I2C_HAS_STOP_DETECT */ @@ -1482,11 +1598,6 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) handle->isBusy = true; xfer->event = kI2C_SlaveAddressMatchEvent; - if ((handle->eventMask & xfer->event) && (handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - /* Slave transmit, master reading from slave. */ if (status & kI2C_TransferDirectionFlag) { @@ -1502,6 +1613,16 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) /* Read dummy to release the bus. */ dummy = base->D; + + if (dummy == 0) + { + xfer->event = kI2C_SlaveGenaralcallEvent; + } + } + + if ((handle->eventMask & xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); } } /* Check transfer complete flag. */ @@ -1607,27 +1728,30 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } +#if defined(I2C0) void I2C0_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C0, s_i2cHandle[0]); } +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 1) +#if defined(I2C1) void I2C1_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C1, s_i2cHandle[1]); } -#endif /* I2C COUNT > 1 */ +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 2) +#if defined(I2C2) void I2C2_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C2, s_i2cHandle[2]); } -#endif /* I2C COUNT > 2 */ -#if (FSL_FEATURE_SOC_I2C_COUNT > 3) +#endif + +#if defined(I2C3) void I2C3_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C3, s_i2cHandle[3]); } -#endif /* I2C COUNT > 3 */ +#endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.h index 7117fd5753..d55fd1d8ea 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -37,15 +37,14 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ /*! @name Driver version */ /*@{*/ -/*! @brief I2C driver version 2.0.1. */ -#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) +/*! @brief I2C driver version 2.0.3. */ +#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 3)) /*@}*/ #if (defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT || \ @@ -61,6 +60,7 @@ enum _i2c_status kStatus_I2C_Nak = MAKE_STATUS(kStatusGroup_I2C, 2), /*!< NAK received during transfer. */ kStatus_I2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_I2C, 3), /*!< Arbitration lost during transfer. */ kStatus_I2C_Timeout = MAKE_STATUS(kStatusGroup_I2C, 4), /*!< Wait event timeout. */ + kStatus_I2C_Addr_Nak = MAKE_STATUS(kStatusGroup_I2C, 5), /*!< NAK received during the address probe. */ }; /*! @@ -108,11 +108,11 @@ enum _i2c_interrupt_enable #endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ }; -/*! @brief Direction of master and slave transfers. */ +/*! @brief The direction of master and slave transfers. */ typedef enum _i2c_direction { - kI2C_Write = 0x0U, /*!< Master transmit to slave. */ - kI2C_Read = 0x1U, /*!< Master receive from slave. */ + kI2C_Write = 0x0U, /*!< Master transmits to the slave. */ + kI2C_Read = 0x1U, /*!< Master receives from the slave. */ } i2c_direction_t; /*! @brief Addressing mode. */ @@ -125,17 +125,17 @@ typedef enum _i2c_slave_address_mode /*! @brief I2C transfer control flag. */ enum _i2c_master_transfer_flags { - kI2C_TransferDefaultFlag = 0x0U, /*!< Transfer starts with a start signal, stops with a stop signal. */ - kI2C_TransferNoStartFlag = 0x1U, /*!< Transfer starts without a start signal. */ - kI2C_TransferRepeatedStartFlag = 0x2U, /*!< Transfer starts with a repeated start signal. */ - kI2C_TransferNoStopFlag = 0x4U, /*!< Transfer ends without a stop signal. */ + kI2C_TransferDefaultFlag = 0x0U, /*!< A transfer starts with a start signal, stops with a stop signal. */ + kI2C_TransferNoStartFlag = 0x1U, /*!< A transfer starts without a start signal. */ + kI2C_TransferRepeatedStartFlag = 0x2U, /*!< A transfer starts with a repeated start signal. */ + kI2C_TransferNoStopFlag = 0x4U, /*!< A transfer ends without a stop signal. */ }; /*! * @brief Set of events sent to the callback for nonblocking slave transfers. * * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together - * events is passed to I2C_SlaveTransferNonBlocking() in order to specify which events to enable. + * events is passed to I2C_SlaveTransferNonBlocking() to specify which events to enable. * Then, when the slave callback is invoked, it is passed the current event through its @a transfer * parameter. * @@ -144,36 +144,34 @@ enum _i2c_master_transfer_flags typedef enum _i2c_slave_transfer_event { kI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */ - kI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit + kI2C_SlaveTransmitEvent = 0x02U, /*!< A callback is requested to provide data to transmit (slave-transmitter role). */ - kI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received + kI2C_SlaveReceiveEvent = 0x04U, /*!< A callback is requested to provide a buffer in which to place received data (slave-receiver role). */ - kI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */ + kI2C_SlaveTransmitAckEvent = 0x08U, /*!< A callback needs to either transmit an ACK or NACK. */ #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT kI2C_SlaveStartEvent = 0x10U, /*!< A start/repeated start was detected. */ #endif - kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveGenaralcallEvent = 0x40U, /*!< Received the general call address after a start or repeated start. */ - /*! Bit mask of all available events. */ + /*! A bit mask of all available events. */ kI2C_SlaveAllEvents = kI2C_SlaveAddressMatchEvent | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT kI2C_SlaveStartEvent | #endif - kI2C_SlaveCompletionEvent, + kI2C_SlaveCompletionEvent | kI2C_SlaveGenaralcallEvent, } i2c_slave_transfer_event_t; /*! @brief I2C master user configuration. */ typedef struct _i2c_master_config { bool enableMaster; /*!< Enables the I2C peripheral at initialization time. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF bool enableStopHold; /*!< Controls the stop hold enable. */ #endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE - bool enableDoubleBuffering; /*!< Controls double buffer enable, notice that + bool enableDoubleBuffering; /*!< Controls double buffer enable; notice that enabling the double buffer disables the clock stretch. */ #endif uint32_t baudRate_Bps; /*!< Baud rate configuration of I2C peripheral. */ @@ -184,19 +182,20 @@ typedef struct _i2c_master_config typedef struct _i2c_slave_config { bool enableSlave; /*!< Enables the I2C peripheral at initialization time. */ - bool enableGeneralCall; /*!< Enable general call addressing mode. */ + bool enableGeneralCall; /*!< Enables the general call addressing mode. */ bool enableWakeUp; /*!< Enables/disables waking up MCU from low-power mode. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE - bool enableDoubleBuffering; /*!< Controls double buffer enable, notice that + bool enableDoubleBuffering; /*!< Controls a double buffer enable; notice that enabling the double buffer disables the clock stretch. */ #endif bool enableBaudRateCtl; /*!< Enables/disables independent slave baud rate on SCL in very fast I2C modes. */ - uint16_t slaveAddress; /*!< Slave address configuration. */ - uint16_t upperAddress; /*!< Maximum boundary slave address used in range matching mode. */ - i2c_slave_address_mode_t addressingMode; /*!< Addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint16_t slaveAddress; /*!< A slave address configuration. */ + uint16_t upperAddress; /*!< A maximum boundary slave address used in a range matching mode. */ + i2c_slave_address_mode_t + addressingMode; /*!< An addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint32_t sclStopHoldTime_ns; /*!< the delay from the rising edge of SCL (I2C clock) to the rising edge of SDA (I2C + data) while SCL is high (stop condition), SDA hold time and SCL start hold time + are also configured according to the SCL stop hold time. */ } i2c_slave_config_t; /*! @brief I2C master handle typedef. */ @@ -214,13 +213,13 @@ typedef struct _i2c_slave_handle i2c_slave_handle_t; /*! @brief I2C master transfer structure. */ typedef struct _i2c_master_transfer { - uint32_t flags; /*!< Transfer flag which controls the transfer. */ + uint32_t flags; /*!< A transfer flag which controls the transfer. */ uint8_t slaveAddress; /*!< 7-bit slave address. */ - i2c_direction_t direction; /*!< Transfer direction, read or write. */ - uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ - uint8_t subaddressSize; /*!< Size of command buffer. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_direction_t direction; /*!< A transfer direction, read or write. */ + uint32_t subaddress; /*!< A sub address. Transferred MSB first. */ + uint8_t subaddressSize; /*!< A size of the command buffer. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ } i2c_master_transfer_t; /*! @brief I2C master handle structure. */ @@ -228,20 +227,21 @@ struct _i2c_master_handle { i2c_master_transfer_t transfer; /*!< I2C master transfer copy. */ size_t transferSize; /*!< Total bytes to be transferred. */ - uint8_t state; /*!< Transfer state maintained during transfer. */ - i2c_master_transfer_callback_t completionCallback; /*!< Callback function called when transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + uint8_t state; /*!< A transfer state maintained during transfer. */ + i2c_master_transfer_callback_t completionCallback; /*!< A callback function called when the transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /*! @brief I2C slave transfer structure. */ typedef struct _i2c_slave_transfer { - i2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_slave_transfer_event_t event; /*!< A reason that the callback is invoked. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for #kI2C_SlaveCompletionEvent. */ - size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */ + size_t transferredCount; /*!< A number of bytes actually transferred since the start or since the last repeated + start. */ } i2c_slave_transfer_t; /*! @brief I2C slave transfer callback typedef. */ @@ -250,11 +250,11 @@ typedef void (*i2c_slave_transfer_callback_t)(I2C_Type *base, i2c_slave_transfer /*! @brief I2C slave handle structure. */ struct _i2c_slave_handle { - bool isBusy; /*!< Whether transfer is busy. */ + volatile bool isBusy; /*!< Indicates whether a transfer is busy. */ i2c_slave_transfer_t transfer; /*!< I2C slave transfer copy. */ - uint32_t eventMask; /*!< Mask of enabled events. */ - i2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */ - void *userData; /*!< Callback parameter passed to callback. */ + uint32_t eventMask; /*!< A mask of enabled events. */ + i2c_slave_transfer_callback_t callback; /*!< A callback function called at the transfer event. */ + void *userData; /*!< A callback parameter passed to the callback. */ }; /******************************************************************************* @@ -274,12 +274,12 @@ extern "C" { * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock * and configure the I2C with master configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module may cause a hard fault - * because clock is not enabled. The configuration structure can be filled by user - * from scratch, or be set with default values by I2C_MasterGetDefaultConfig(). + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can be custom filled + * or it can be set with default values by using the I2C_MasterGetDefaultConfig(). * After calling this API, the master is ready to transfer. - * Example: + * This is an example. * @code * i2c_master_config_t config = { * .enableMaster = true, @@ -292,20 +292,20 @@ extern "C" { * @endcode * * @param base I2C base pointer - * @param masterConfig pointer to master configuration structure + * @param masterConfig A pointer to the master configuration structure * @param srcClock_Hz I2C peripheral clock frequency in Hz */ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz); /*! * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock - * and initializes the I2C with slave configuration. + * and initialize the I2C with the slave configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module can cause a hard fault + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault * because the clock is not enabled. The configuration structure can partly be set - * with default values by I2C_SlaveGetDefaultConfig(), or can be filled by the user. - * Example + * with default values by I2C_SlaveGetDefaultConfig() or it can be custom filled by the user. + * This is an example. * @code * i2c_slave_config_t config = { * .enableSlave = true, @@ -314,15 +314,17 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin * .slaveAddress = 0x1DU, * .enableWakeUp = false, * .enablehighDrive = false, - * .enableBaudRateCtl = false + * .enableBaudRateCtl = false, + * .sclStopHoldTime_ns = 4000 * }; - * I2C_SlaveInit(I2C0, &config); + * I2C_SlaveInit(I2C0, &config, 12000000U); * @endcode * * @param base I2C base pointer - * @param slaveConfig pointer to slave configuration structure + * @param slaveConfig A pointer to the slave configuration structure + * @param srcClock_Hz I2C peripheral clock frequency in Hz */ -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig); +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz); /*! * @brief De-initializes the I2C master peripheral. Call this API to gate the I2C clock. @@ -342,28 +344,28 @@ void I2C_SlaveDeinit(I2C_Type *base); * @brief Sets the I2C master configuration structure to default values. * * The purpose of this API is to get the configuration structure initialized for use in the I2C_MasterConfigure(). - * Use the initialized structure unchanged in I2C_MasterConfigure(), or modify some fields of - * the structure before calling I2C_MasterConfigure(). - * Example: + * Use the initialized structure unchanged in the I2C_MasterConfigure() or modify + * the structure before calling the I2C_MasterConfigure(). + * This is an example. * @code * i2c_master_config_t config; * I2C_MasterGetDefaultConfig(&config); * @endcode - * @param masterConfig Pointer to the master configuration structure. + * @param masterConfig A pointer to the master configuration structure. */ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig); /*! * @brief Sets the I2C slave configuration structure to default values. * - * The purpose of this API is to get the configuration structure initialized for use in I2C_SlaveConfigure(). + * The purpose of this API is to get the configuration structure initialized for use in the I2C_SlaveConfigure(). * Modify fields of the structure before calling the I2C_SlaveConfigure(). - * Example: + * This is an example. * @code * i2c_slave_config_t config; * I2C_SlaveGetDefaultConfig(&config); * @endcode - * @param slaveConfig Pointer to the slave configuration structure. + * @param slaveConfig A pointer to the slave configuration structure. */ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); @@ -371,7 +373,7 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); * @brief Enables or disabless the I2C peripheral operation. * * @param base I2C base pointer - * @param enable pass true to enable module, false to disable module + * @param enable Pass true to enable and false to disable the module. */ static inline void I2C_Enable(I2C_Type *base, bool enable) { @@ -414,7 +416,7 @@ static inline uint32_t I2C_SlaveGetStatusFlags(I2C_Type *base) /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag. * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. @@ -449,7 +451,7 @@ static inline void I2C_MasterClearStatusFlags(I2C_Type *base, uint32_t statusMas /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. @@ -581,19 +583,21 @@ status_t I2C_MasterStop(I2C_Type *base); status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction); /*! - * @brief Performs a polling send transaction on the I2C bus without a STOP signal. + * @brief Performs a polling send transaction on the I2C bus. * * @param base The I2C peripheral base pointer. * @param txBuff The pointer to the data to be transferred. * @param txSize The length in bytes of the data to be transferred. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize); +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags); /*! - * @brief Performs a polling receive transaction on the I2C bus with a STOP signal. + * @brief Performs a polling receive transaction on the I2C bus. * * @note The I2C_MasterReadBlocking function stops the bus before reading the final byte. * Without stopping the bus prior for the final read, the bus issues another read, resulting @@ -602,10 +606,12 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t * @param base I2C peripheral base pointer. * @param rxBuff The pointer to the data to store the received data. * @param rxSize The length in bytes of the data to be received. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_Timeout Send stop signal failed, timeout. */ -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize); +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags); /*! * @brief Performs a polling send transaction on the I2C bus. diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.c index c8f7c20629..28a415e075 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -162,6 +162,26 @@ static void I2C_MasterTransferCallbackEDMA(edma_handle_t *handle, void *userData result = I2C_MasterStop(i2cPrivateHandle->base); } } + else + { + if (i2cPrivateHandle->handle->transfer.direction == kI2C_Read) + { + /* Change to send NAK at the last byte. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TXAK_MASK; + + /* Wait the last data to be received. */ + while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag)) + { + } + + /* Change direction to send. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TX_MASK; + + /* Read the last data byte. */ + *(i2cPrivateHandle->handle->transfer.data + i2cPrivateHandle->handle->transfer.dataSize - 1) = + i2cPrivateHandle->base->D; + } + } i2cPrivateHandle->handle->state = kIdleState; @@ -203,7 +223,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, assert(xfer); status_t result = kStatus_Success; - uint16_t timeout = UINT16_MAX; if (handle->state != kIdleState) { @@ -221,16 +240,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, handle->state = kTransferDataState; - /* Wait until ready to complete. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -250,22 +259,55 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction); } + if (result) + { + return result; + } + + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + /* Return if error. */ + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + if (I2C_MasterStop(base) != kStatus_Success) + { + result = kStatus_I2C_Timeout; + } + + if (handle->completionCallback) + { + (handle->completionCallback)(base, handle, result, handle->userData); + } + } + + return result; + } + /* Send subaddress. */ if (handle->transfer.subaddressSize) { do { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear interrupt pending flag. */ base->S = kI2C_IntPendingFlag; handle->transfer.subaddressSize--; base->D = ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize)); + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + /* Check if there's transfer error. */ result = I2C_CheckAndClearError(base, base->S); @@ -278,34 +320,34 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, if (handle->transfer.direction == kI2C_Read) { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; /* Send repeated start and slave address. */ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read); + + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + return result; + } } } - if (result) - { - return result; - } - - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); } return result; @@ -319,17 +361,7 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ { transfer_config.srcAddr = (uint32_t)I2C_GetDataRegAddr(base); transfer_config.destAddr = (uint32_t)(handle->transfer.data); - - /* Send stop if kI2C_TransferNoStop flag is not asserted. */ - if (!(handle->transfer.flags & kI2C_TransferNoStopFlag)) - { - transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); - } - else - { - transfer_config.majorLoopCounts = handle->transfer.dataSize; - } - + transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); transfer_config.srcTransferSize = kEDMA_TransferSize1Bytes; transfer_config.srcOffset = 0; transfer_config.destTransferSize = kEDMA_TransferSize1Bytes; @@ -348,6 +380,9 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ transfer_config.minorLoopBytes = 1; } + /* Store the initially configured eDMA minor byte transfer count into the I2C handle */ + handle->nbytes = transfer_config.minorLoopBytes; + EDMA_SubmitTransfer(handle->dmaHandle, &transfer_config); EDMA_StartTransfer(handle->dmaHandle); } @@ -427,7 +462,7 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle if (handle->transfer.direction == kI2C_Read) { /* Change direction for receive. */ - base->C1 &= ~I2C_C1_TX_MASK; + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); /* Read dummy to release the bus. */ dummy = base->D; @@ -479,6 +514,11 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle { result = I2C_MasterStop(base); } + else + { + /* Change direction to send. */ + base->C1 |= I2C_C1_TX_MASK; + } /* Read the last byte of data. */ if (handle->transfer.direction == kI2C_Read) @@ -504,7 +544,9 @@ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t if (kIdleState != handle->state) { - *count = (handle->transferSize - EDMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel)); + *count = (handle->transferSize - + (uint32_t)handle->nbytes * + EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel)); } else { diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.h index c95d6adeee..40cb648ea9 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW24D/drivers/fsl_i2c_edma.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -39,7 +39,6 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ @@ -56,13 +55,14 @@ typedef void (*i2c_master_edma_transfer_callback_t)(I2C_Type *base, /*! @brief I2C master eDMA transfer structure. */ struct _i2c_master_edma_handle { - i2c_master_transfer_t transfer; /*!< I2C master transfer struct. */ + i2c_master_transfer_t transfer; /*!< I2C master transfer structure. */ size_t transferSize; /*!< Total bytes to be transferred. */ + uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */ uint8_t state; /*!< I2C master transfer status. */ edma_handle_t *dmaHandle; /*!< The eDMA handler used. */ i2c_master_edma_transfer_callback_t - completionCallback; /*!< Callback function called after eDMA transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + completionCallback; /*!< A callback function called after the eDMA transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /******************************************************************************* @@ -79,12 +79,12 @@ extern "C" { */ /*! - * @brief Init the I2C handle which is used in transcational functions. + * @brief Initializes the I2C handle which is used in transcational functions. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param callback pointer to user callback function. - * @param userData user param passed to the callback function. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param callback A pointer to the user callback function. + * @param userData A user parameter passed to the callback function. * @param edmaHandle eDMA handle pointer. */ void I2C_MasterCreateEDMAHandle(I2C_Type *base, @@ -97,30 +97,30 @@ void I2C_MasterCreateEDMAHandle(I2C_Type *base, * @brief Performs a master eDMA non-blocking transfer on the I2C bus. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param xfer pointer to transfer structure of i2c_master_transfer_t. - * @retval kStatus_Success Sucessully complete the data transmission. - * @retval kStatus_I2C_Busy Previous transmission still not finished. - * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param xfer A pointer to the transfer structure of i2c_master_transfer_t. + * @retval kStatus_Success Sucessfully completed the data transmission. + * @retval kStatus_I2C_Busy A previous transmission is still not finished. + * @retval kStatus_I2C_Timeout Transfer error, waits for a signal timeout. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. - * @retval kStataus_I2C_Nak Transfer error, receive Nak during transfer. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, i2c_master_transfer_t *xfer); /*! - * @brief Get master transfer status during a eDMA non-blocking transfer. + * @brief Gets a master transfer status during the eDMA non-blocking transfer. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param count Number of bytes transferred so far by the non-blocking transaction. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param count A number of bytes transferred by the non-blocking transaction. */ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, size_t *count); /*! - * @brief Abort a master eDMA non-blocking transfer in a early time. + * @brief Aborts a master eDMA non-blocking transfer early. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. + * @param handle A pointer to the i2c_master_edma_handle_t structure. */ void I2C_MasterTransferAbortEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle); diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.c index b51fc07a15..6c9770af25 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -75,6 +75,19 @@ typedef void (*i2c_isr_t)(I2C_Type *base, void *i2cHandle); */ uint32_t I2C_GetInstance(I2C_Type *base); +/*! +* @brief Set SCL/SDA hold time, this API receives SCL stop hold time, calculate the +* closest SCL divider and MULT value for the SDA hold time, SCL start and SCL stop +* hold time. To reduce the ROM size, SDA/SCL hold value mapping table is not provided, +* assume SCL divider = SCL stop hold value *2 to get the closest SCL divider value and MULT +* value, then the related SDA hold time, SCL start and SCL stop hold time is used. +* +* @param base I2C peripheral base address. +* @param sourceClock_Hz I2C functional clock frequency in Hertz. +* @param sclStopHoldTime_ns SCL stop hold time in ns. +*/ +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz); + /*! * @brief Set up master transfer, send slave address and decide the initial * transfer state. @@ -137,8 +150,10 @@ static I2C_Type *const s_i2cBases[] = I2C_BASE_PTRS; /*! @brief Pointers to i2c IRQ number for each instance. */ static const IRQn_Type s_i2cIrqs[] = I2C_IRQS; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to i2c clocks for each instance. */ static const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief Pointer to master IRQ handler for each instance. */ static i2c_isr_t s_i2cMasterIsr; @@ -155,7 +170,7 @@ uint32_t I2C_GetInstance(I2C_Type *base) uint32_t instance; /* Find the instance index from base address mappings. */ - for (instance = 0; instance < FSL_FEATURE_SOC_I2C_COUNT; instance++) + for (instance = 0; instance < ARRAY_SIZE(s_i2cBases); instance++) { if (s_i2cBases[instance] == base) { @@ -163,16 +178,63 @@ uint32_t I2C_GetInstance(I2C_Type *base) } } - assert(instance < FSL_FEATURE_SOC_I2C_COUNT); + assert(instance < ARRAY_SIZE(s_i2cBases)); return instance; } +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz) +{ + uint32_t multiplier; + uint32_t computedSclHoldTime; + uint32_t absError; + uint32_t bestError = UINT32_MAX; + uint32_t bestMult = 0u; + uint32_t bestIcr = 0u; + uint8_t mult; + uint8_t i; + + /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register, + * and ranges from 0-2. It selects the multiplier factor for the divider. */ + /* SDA hold time = bus period (s) * mul * SDA hold value. */ + /* SCL start hold time = bus period (s) * mul * SCL start hold value. */ + /* SCL stop hold time = bus period (s) * mul * SCL stop hold value. */ + + for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult) + { + multiplier = 1u << mult; + + /* Scan table to find best match. */ + for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(s_i2cDividerTable[0]); ++i) + { + /* Assume SCL hold(stop) value = s_i2cDividerTable[i]/2. */ + computedSclHoldTime = ((multiplier * s_i2cDividerTable[i]) * 500000000U) / sourceClock_Hz; + absError = sclStopHoldTime_ns > computedSclHoldTime ? (sclStopHoldTime_ns - computedSclHoldTime) : + (computedSclHoldTime - sclStopHoldTime_ns); + + if (absError < bestError) + { + bestMult = mult; + bestIcr = i; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0) + { + break; + } + } + } + } + + /* Set frequency register based on best settings. */ + base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr); +} + static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer) { status_t result = kStatus_Success; i2c_direction_t direction = xfer->direction; - uint16_t timeout = UINT16_MAX; /* Initialize the handle transfer information. */ handle->transfer = *xfer; @@ -183,27 +245,13 @@ static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t /* Initial transfer state. */ if (handle->transfer.subaddressSize > 0) { - handle->state = kSendCommandState; if (xfer->direction == kI2C_Read) { direction = kI2C_Write; } } - else - { - handle->state = kCheckAddressState; - } - /* Wait until the data register is ready for transmit. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } + handle->state = kCheckAddressState; /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -265,34 +313,41 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han result = kStatus_Success; } - if (result) - { - return result; - } - /* Handle Check address state to check the slave address is Acked in slave probe application. */ if (handle->state == kCheckAddressState) { if (statusFlags & kI2C_ReceiveNakFlag) { - return kStatus_I2C_Nak; + result = kStatus_I2C_Addr_Nak; } else { - if (handle->transfer.direction == kI2C_Write) + if (handle->transfer.subaddressSize > 0) { - /* Next state, send data. */ - handle->state = kSendDataState; + handle->state = kSendCommandState; } else { - /* Next state, receive data begin. */ - handle->state = kReceiveDataBeginState; + if (handle->transfer.direction == kI2C_Write) + { + /* Next state, send data. */ + handle->state = kSendDataState; + } + else + { + /* Next state, receive data begin. */ + handle->state = kReceiveDataBeginState; + } } } } + if (result) + { + return result; + } + /* Run state machine. */ switch (handle->state) { @@ -375,6 +430,10 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han { result = I2C_MasterStop(base); } + else + { + base->C1 |= I2C_C1_TX_MASK; + } } /* Send NAK at the last receive byte. */ @@ -407,6 +466,7 @@ static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle) { s_i2cSlaveIsr(base, handle); } + __DSB(); } void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz) @@ -415,14 +475,26 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Temporary register for filter read. */ uint8_t fltReg; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - uint8_t c2Reg; -#endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE uint8_t s2Reg; #endif +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Enable I2C clock. */ CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Disable I2C prior to configuring it. */ base->C1 &= ~(I2C_C1_IICEN_MASK); @@ -433,14 +505,6 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Configure baud rate. */ I2C_MasterSetBaudRate(base, masterConfig->baudRate_Bps, srcClock_Hz); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Configure high drive feature. */ - c2Reg = base->C2; - c2Reg &= ~(I2C_C2_HDRS_MASK); - c2Reg |= I2C_C2_HDRS(masterConfig->enableHighDrive); - base->C2 = c2Reg; -#endif - /* Read out the FLT register. */ fltReg = base->FLT; @@ -472,8 +536,10 @@ void I2C_MasterDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) @@ -483,11 +549,6 @@ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) /* Default baud rate at 100kbps. */ masterConfig->baudRate_Bps = 100000U; -/* Default pin high drive is disabled. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - masterConfig->enableHighDrive = false; -#endif - /* Default stop hold enable is disabled. */ #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF masterConfig->enableStopHold = false; @@ -654,7 +715,7 @@ status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_ base->F = savedMult & (~I2C_F_MULT_MASK); /* We are already in a transfer, so send a repeated start. */ - base->C1 |= I2C_C1_RSTA_MASK; + base->C1 |= I2C_C1_RSTA_MASK | I2C_C1_TX_MASK; /* Restore the multiplier factor. */ base->F = savedMult; @@ -721,7 +782,7 @@ uint32_t I2C_MasterGetStatusFlags(I2C_Type *base) return statusFlags; } -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize) +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags) { status_t result = kStatus_Success; uint8_t statusFlags = 0; @@ -772,10 +833,19 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t } } + if (((result == kStatus_Success) && (!(flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) + { + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send stop. */ + result = I2C_MasterStop(base); + } + return result; } -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags) { status_t result = kStatus_Success; volatile uint8_t dummy = 0; @@ -817,8 +887,16 @@ status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) /* Single byte use case. */ if (rxSize == 0) { - /* Read the final byte. */ - result = I2C_MasterStop(base); + if (!(flags & kI2C_TransferNoStopFlag)) + { + /* Issue STOP command before reading last byte. */ + result = I2C_MasterStop(base); + } + else + { + /* Change direction to Tx to avoid extra clocks. */ + base->C1 |= I2C_C1_TX_MASK; + } } if (rxSize == 1) @@ -871,72 +949,6 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) return result; } - /* Send subaddress. */ - if (xfer->subaddressSize) - { - do - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear interrupt pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - xfer->subaddressSize--; - base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); - - } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); - - if (xfer->direction == kI2C_Read) - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - /* Send repeated start and slave address. */ - result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); - - /* Return if error. */ - if (result) - { - return result; - } - } - } - - /* Wait until address + command transfer complete. */ while (!(base->S & kI2C_IntPendingFlag)) { } @@ -949,32 +961,92 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) { if (result == kStatus_I2C_Nak) { + result = kStatus_I2C_Addr_Nak; + I2C_MasterStop(base); } return result; } + /* Send subaddress. */ + if (xfer->subaddressSize) + { + do + { + /* Clear interrupt pending flag. */ + base->S = kI2C_IntPendingFlag; + + xfer->subaddressSize--; + base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + I2C_MasterStop(base); + } + + return result; + } + + } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); + + if (xfer->direction == kI2C_Read) + { + /* Clear pending flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send repeated start and slave address. */ + result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); + + /* Return if error. */ + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + I2C_MasterStop(base); + } + + return result; + } + } + } + /* Transmit data. */ if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)) { /* Send Data. */ - result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize); - - if (((result == kStatus_Success) && (!(xfer->flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) - { - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; - - /* Send stop. */ - result = I2C_MasterStop(base); - } + result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } /* Receive Data. */ if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)) { - result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize); + result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } return result; @@ -1037,11 +1109,37 @@ void I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle) { assert(handle); + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + /* Disable interrupt. */ I2C_DisableInterrupts(base, kI2C_GlobalInterruptEnable); /* Reset the state to idle. */ handle->state = kIdleState; + + /* Send STOP signal. */ + if (handle->transfer.direction == kI2C_Read) + { + base->C1 |= I2C_C1_TXAK_MASK; + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + dummy = base->D; + } + else + { + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + } } status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count) @@ -1075,7 +1173,8 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) if (isDone || result) { /* Send stop command if transfer done or received Nak. */ - if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak)) + if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak) || + (result == kStatus_I2C_Addr_Nak)) { /* Ensure stop command is a need. */ if ((base->C1 & I2C_C1_MST_MASK)) @@ -1101,13 +1200,28 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz) { assert(slaveConfig); uint8_t tmpReg; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Configure addressing mode. */ switch (slaveConfig->addressingMode) @@ -1132,14 +1246,10 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg &= ~I2C_C1_WUEN_MASK; base->C1 = tmpReg | I2C_C1_WUEN(slaveConfig->enableWakeUp) | I2C_C1_IICEN(slaveConfig->enableSlave); - /* Configure general call & baud rate control & high drive feature. */ + /* Configure general call & baud rate control. */ tmpReg = base->C2; tmpReg &= ~(I2C_C2_SBRC_MASK | I2C_C2_GCAEN_MASK); tmpReg |= I2C_C2_SBRC(slaveConfig->enableBaudRateCtl) | I2C_C2_GCAEN(slaveConfig->enableGeneralCall); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - tmpReg &= ~I2C_C2_HDRS_MASK; - tmpReg |= I2C_C2_HDRS(slaveConfig->enableHighDrive); -#endif base->C2 = tmpReg; /* Enable/Disable double buffering. */ @@ -1147,6 +1257,9 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg = base->S2 & (~I2C_S2_DFEN_MASK); base->S2 = tmpReg | I2C_S2_DFEN(slaveConfig->enableDoubleBuffering); #endif + + /* Set hold time. */ + I2C_SetHoldTime(base, slaveConfig->sclStopHoldTime_ns, srcClock_Hz); } void I2C_SlaveDeinit(I2C_Type *base) @@ -1154,8 +1267,10 @@ void I2C_SlaveDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) @@ -1171,11 +1286,6 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) /* Slave address match waking up MCU from low power mode is disabled. */ slaveConfig->enableWakeUp = false; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Default pin high drive is disabled. */ - slaveConfig->enableHighDrive = false; -#endif - /* Independent slave mode baud rate at maximum frequency is disabled. */ slaveConfig->enableBaudRateCtl = false; @@ -1184,6 +1294,9 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) slaveConfig->enableDoubleBuffering = true; #endif + /* Set default SCL stop hold time to 4us which is minimum requirement in I2C spec. */ + slaveConfig->sclStopHoldTime_ns = 4000; + /* Enable the I2C peripheral. */ slaveConfig->enableSlave = true; } @@ -1215,7 +1328,7 @@ status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t tx /* Read dummy to release bus. */ dummy = base->D; - result = I2C_MasterWriteBlocking(base, txBuff, txSize); + result = I2C_MasterWriteBlocking(base, txBuff, txSize, kI2C_TransferDefaultFlag); /* Switch to receive mode. */ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); @@ -1323,7 +1436,7 @@ status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle handle->isBusy = true; /* Set up event mask. tx and rx are always enabled. */ - handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent; + handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | kI2C_SlaveGenaralcallEvent; /* Clear all flags. */ I2C_SlaveClearStatusFlags(base, kClearFlags); @@ -1412,7 +1525,10 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } - return; + if (!(status & kI2C_AddressMatchFlag)) + { + return; + } } #endif /* I2C_HAS_STOP_DETECT */ @@ -1482,11 +1598,6 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) handle->isBusy = true; xfer->event = kI2C_SlaveAddressMatchEvent; - if ((handle->eventMask & xfer->event) && (handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - /* Slave transmit, master reading from slave. */ if (status & kI2C_TransferDirectionFlag) { @@ -1502,6 +1613,16 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) /* Read dummy to release the bus. */ dummy = base->D; + + if (dummy == 0) + { + xfer->event = kI2C_SlaveGenaralcallEvent; + } + } + + if ((handle->eventMask & xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); } } /* Check transfer complete flag. */ @@ -1607,27 +1728,30 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } +#if defined(I2C0) void I2C0_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C0, s_i2cHandle[0]); } +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 1) +#if defined(I2C1) void I2C1_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C1, s_i2cHandle[1]); } -#endif /* I2C COUNT > 1 */ +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 2) +#if defined(I2C2) void I2C2_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C2, s_i2cHandle[2]); } -#endif /* I2C COUNT > 2 */ -#if (FSL_FEATURE_SOC_I2C_COUNT > 3) +#endif + +#if defined(I2C3) void I2C3_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C3, s_i2cHandle[3]); } -#endif /* I2C COUNT > 3 */ +#endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.h index 7117fd5753..d55fd1d8ea 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -37,15 +37,14 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ /*! @name Driver version */ /*@{*/ -/*! @brief I2C driver version 2.0.1. */ -#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) +/*! @brief I2C driver version 2.0.3. */ +#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 3)) /*@}*/ #if (defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT || \ @@ -61,6 +60,7 @@ enum _i2c_status kStatus_I2C_Nak = MAKE_STATUS(kStatusGroup_I2C, 2), /*!< NAK received during transfer. */ kStatus_I2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_I2C, 3), /*!< Arbitration lost during transfer. */ kStatus_I2C_Timeout = MAKE_STATUS(kStatusGroup_I2C, 4), /*!< Wait event timeout. */ + kStatus_I2C_Addr_Nak = MAKE_STATUS(kStatusGroup_I2C, 5), /*!< NAK received during the address probe. */ }; /*! @@ -108,11 +108,11 @@ enum _i2c_interrupt_enable #endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ }; -/*! @brief Direction of master and slave transfers. */ +/*! @brief The direction of master and slave transfers. */ typedef enum _i2c_direction { - kI2C_Write = 0x0U, /*!< Master transmit to slave. */ - kI2C_Read = 0x1U, /*!< Master receive from slave. */ + kI2C_Write = 0x0U, /*!< Master transmits to the slave. */ + kI2C_Read = 0x1U, /*!< Master receives from the slave. */ } i2c_direction_t; /*! @brief Addressing mode. */ @@ -125,17 +125,17 @@ typedef enum _i2c_slave_address_mode /*! @brief I2C transfer control flag. */ enum _i2c_master_transfer_flags { - kI2C_TransferDefaultFlag = 0x0U, /*!< Transfer starts with a start signal, stops with a stop signal. */ - kI2C_TransferNoStartFlag = 0x1U, /*!< Transfer starts without a start signal. */ - kI2C_TransferRepeatedStartFlag = 0x2U, /*!< Transfer starts with a repeated start signal. */ - kI2C_TransferNoStopFlag = 0x4U, /*!< Transfer ends without a stop signal. */ + kI2C_TransferDefaultFlag = 0x0U, /*!< A transfer starts with a start signal, stops with a stop signal. */ + kI2C_TransferNoStartFlag = 0x1U, /*!< A transfer starts without a start signal. */ + kI2C_TransferRepeatedStartFlag = 0x2U, /*!< A transfer starts with a repeated start signal. */ + kI2C_TransferNoStopFlag = 0x4U, /*!< A transfer ends without a stop signal. */ }; /*! * @brief Set of events sent to the callback for nonblocking slave transfers. * * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together - * events is passed to I2C_SlaveTransferNonBlocking() in order to specify which events to enable. + * events is passed to I2C_SlaveTransferNonBlocking() to specify which events to enable. * Then, when the slave callback is invoked, it is passed the current event through its @a transfer * parameter. * @@ -144,36 +144,34 @@ enum _i2c_master_transfer_flags typedef enum _i2c_slave_transfer_event { kI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */ - kI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit + kI2C_SlaveTransmitEvent = 0x02U, /*!< A callback is requested to provide data to transmit (slave-transmitter role). */ - kI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received + kI2C_SlaveReceiveEvent = 0x04U, /*!< A callback is requested to provide a buffer in which to place received data (slave-receiver role). */ - kI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */ + kI2C_SlaveTransmitAckEvent = 0x08U, /*!< A callback needs to either transmit an ACK or NACK. */ #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT kI2C_SlaveStartEvent = 0x10U, /*!< A start/repeated start was detected. */ #endif - kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveGenaralcallEvent = 0x40U, /*!< Received the general call address after a start or repeated start. */ - /*! Bit mask of all available events. */ + /*! A bit mask of all available events. */ kI2C_SlaveAllEvents = kI2C_SlaveAddressMatchEvent | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT kI2C_SlaveStartEvent | #endif - kI2C_SlaveCompletionEvent, + kI2C_SlaveCompletionEvent | kI2C_SlaveGenaralcallEvent, } i2c_slave_transfer_event_t; /*! @brief I2C master user configuration. */ typedef struct _i2c_master_config { bool enableMaster; /*!< Enables the I2C peripheral at initialization time. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF bool enableStopHold; /*!< Controls the stop hold enable. */ #endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE - bool enableDoubleBuffering; /*!< Controls double buffer enable, notice that + bool enableDoubleBuffering; /*!< Controls double buffer enable; notice that enabling the double buffer disables the clock stretch. */ #endif uint32_t baudRate_Bps; /*!< Baud rate configuration of I2C peripheral. */ @@ -184,19 +182,20 @@ typedef struct _i2c_master_config typedef struct _i2c_slave_config { bool enableSlave; /*!< Enables the I2C peripheral at initialization time. */ - bool enableGeneralCall; /*!< Enable general call addressing mode. */ + bool enableGeneralCall; /*!< Enables the general call addressing mode. */ bool enableWakeUp; /*!< Enables/disables waking up MCU from low-power mode. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE - bool enableDoubleBuffering; /*!< Controls double buffer enable, notice that + bool enableDoubleBuffering; /*!< Controls a double buffer enable; notice that enabling the double buffer disables the clock stretch. */ #endif bool enableBaudRateCtl; /*!< Enables/disables independent slave baud rate on SCL in very fast I2C modes. */ - uint16_t slaveAddress; /*!< Slave address configuration. */ - uint16_t upperAddress; /*!< Maximum boundary slave address used in range matching mode. */ - i2c_slave_address_mode_t addressingMode; /*!< Addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint16_t slaveAddress; /*!< A slave address configuration. */ + uint16_t upperAddress; /*!< A maximum boundary slave address used in a range matching mode. */ + i2c_slave_address_mode_t + addressingMode; /*!< An addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint32_t sclStopHoldTime_ns; /*!< the delay from the rising edge of SCL (I2C clock) to the rising edge of SDA (I2C + data) while SCL is high (stop condition), SDA hold time and SCL start hold time + are also configured according to the SCL stop hold time. */ } i2c_slave_config_t; /*! @brief I2C master handle typedef. */ @@ -214,13 +213,13 @@ typedef struct _i2c_slave_handle i2c_slave_handle_t; /*! @brief I2C master transfer structure. */ typedef struct _i2c_master_transfer { - uint32_t flags; /*!< Transfer flag which controls the transfer. */ + uint32_t flags; /*!< A transfer flag which controls the transfer. */ uint8_t slaveAddress; /*!< 7-bit slave address. */ - i2c_direction_t direction; /*!< Transfer direction, read or write. */ - uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ - uint8_t subaddressSize; /*!< Size of command buffer. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_direction_t direction; /*!< A transfer direction, read or write. */ + uint32_t subaddress; /*!< A sub address. Transferred MSB first. */ + uint8_t subaddressSize; /*!< A size of the command buffer. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ } i2c_master_transfer_t; /*! @brief I2C master handle structure. */ @@ -228,20 +227,21 @@ struct _i2c_master_handle { i2c_master_transfer_t transfer; /*!< I2C master transfer copy. */ size_t transferSize; /*!< Total bytes to be transferred. */ - uint8_t state; /*!< Transfer state maintained during transfer. */ - i2c_master_transfer_callback_t completionCallback; /*!< Callback function called when transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + uint8_t state; /*!< A transfer state maintained during transfer. */ + i2c_master_transfer_callback_t completionCallback; /*!< A callback function called when the transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /*! @brief I2C slave transfer structure. */ typedef struct _i2c_slave_transfer { - i2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_slave_transfer_event_t event; /*!< A reason that the callback is invoked. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for #kI2C_SlaveCompletionEvent. */ - size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */ + size_t transferredCount; /*!< A number of bytes actually transferred since the start or since the last repeated + start. */ } i2c_slave_transfer_t; /*! @brief I2C slave transfer callback typedef. */ @@ -250,11 +250,11 @@ typedef void (*i2c_slave_transfer_callback_t)(I2C_Type *base, i2c_slave_transfer /*! @brief I2C slave handle structure. */ struct _i2c_slave_handle { - bool isBusy; /*!< Whether transfer is busy. */ + volatile bool isBusy; /*!< Indicates whether a transfer is busy. */ i2c_slave_transfer_t transfer; /*!< I2C slave transfer copy. */ - uint32_t eventMask; /*!< Mask of enabled events. */ - i2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */ - void *userData; /*!< Callback parameter passed to callback. */ + uint32_t eventMask; /*!< A mask of enabled events. */ + i2c_slave_transfer_callback_t callback; /*!< A callback function called at the transfer event. */ + void *userData; /*!< A callback parameter passed to the callback. */ }; /******************************************************************************* @@ -274,12 +274,12 @@ extern "C" { * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock * and configure the I2C with master configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module may cause a hard fault - * because clock is not enabled. The configuration structure can be filled by user - * from scratch, or be set with default values by I2C_MasterGetDefaultConfig(). + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can be custom filled + * or it can be set with default values by using the I2C_MasterGetDefaultConfig(). * After calling this API, the master is ready to transfer. - * Example: + * This is an example. * @code * i2c_master_config_t config = { * .enableMaster = true, @@ -292,20 +292,20 @@ extern "C" { * @endcode * * @param base I2C base pointer - * @param masterConfig pointer to master configuration structure + * @param masterConfig A pointer to the master configuration structure * @param srcClock_Hz I2C peripheral clock frequency in Hz */ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz); /*! * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock - * and initializes the I2C with slave configuration. + * and initialize the I2C with the slave configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module can cause a hard fault + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault * because the clock is not enabled. The configuration structure can partly be set - * with default values by I2C_SlaveGetDefaultConfig(), or can be filled by the user. - * Example + * with default values by I2C_SlaveGetDefaultConfig() or it can be custom filled by the user. + * This is an example. * @code * i2c_slave_config_t config = { * .enableSlave = true, @@ -314,15 +314,17 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin * .slaveAddress = 0x1DU, * .enableWakeUp = false, * .enablehighDrive = false, - * .enableBaudRateCtl = false + * .enableBaudRateCtl = false, + * .sclStopHoldTime_ns = 4000 * }; - * I2C_SlaveInit(I2C0, &config); + * I2C_SlaveInit(I2C0, &config, 12000000U); * @endcode * * @param base I2C base pointer - * @param slaveConfig pointer to slave configuration structure + * @param slaveConfig A pointer to the slave configuration structure + * @param srcClock_Hz I2C peripheral clock frequency in Hz */ -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig); +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz); /*! * @brief De-initializes the I2C master peripheral. Call this API to gate the I2C clock. @@ -342,28 +344,28 @@ void I2C_SlaveDeinit(I2C_Type *base); * @brief Sets the I2C master configuration structure to default values. * * The purpose of this API is to get the configuration structure initialized for use in the I2C_MasterConfigure(). - * Use the initialized structure unchanged in I2C_MasterConfigure(), or modify some fields of - * the structure before calling I2C_MasterConfigure(). - * Example: + * Use the initialized structure unchanged in the I2C_MasterConfigure() or modify + * the structure before calling the I2C_MasterConfigure(). + * This is an example. * @code * i2c_master_config_t config; * I2C_MasterGetDefaultConfig(&config); * @endcode - * @param masterConfig Pointer to the master configuration structure. + * @param masterConfig A pointer to the master configuration structure. */ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig); /*! * @brief Sets the I2C slave configuration structure to default values. * - * The purpose of this API is to get the configuration structure initialized for use in I2C_SlaveConfigure(). + * The purpose of this API is to get the configuration structure initialized for use in the I2C_SlaveConfigure(). * Modify fields of the structure before calling the I2C_SlaveConfigure(). - * Example: + * This is an example. * @code * i2c_slave_config_t config; * I2C_SlaveGetDefaultConfig(&config); * @endcode - * @param slaveConfig Pointer to the slave configuration structure. + * @param slaveConfig A pointer to the slave configuration structure. */ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); @@ -371,7 +373,7 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); * @brief Enables or disabless the I2C peripheral operation. * * @param base I2C base pointer - * @param enable pass true to enable module, false to disable module + * @param enable Pass true to enable and false to disable the module. */ static inline void I2C_Enable(I2C_Type *base, bool enable) { @@ -414,7 +416,7 @@ static inline uint32_t I2C_SlaveGetStatusFlags(I2C_Type *base) /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag. * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. @@ -449,7 +451,7 @@ static inline void I2C_MasterClearStatusFlags(I2C_Type *base, uint32_t statusMas /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. @@ -581,19 +583,21 @@ status_t I2C_MasterStop(I2C_Type *base); status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction); /*! - * @brief Performs a polling send transaction on the I2C bus without a STOP signal. + * @brief Performs a polling send transaction on the I2C bus. * * @param base The I2C peripheral base pointer. * @param txBuff The pointer to the data to be transferred. * @param txSize The length in bytes of the data to be transferred. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize); +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags); /*! - * @brief Performs a polling receive transaction on the I2C bus with a STOP signal. + * @brief Performs a polling receive transaction on the I2C bus. * * @note The I2C_MasterReadBlocking function stops the bus before reading the final byte. * Without stopping the bus prior for the final read, the bus issues another read, resulting @@ -602,10 +606,12 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t * @param base I2C peripheral base pointer. * @param rxBuff The pointer to the data to store the received data. * @param rxSize The length in bytes of the data to be received. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_Timeout Send stop signal failed, timeout. */ -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize); +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags); /*! * @brief Performs a polling send transaction on the I2C bus. diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.c index c8f7c20629..28a415e075 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -162,6 +162,26 @@ static void I2C_MasterTransferCallbackEDMA(edma_handle_t *handle, void *userData result = I2C_MasterStop(i2cPrivateHandle->base); } } + else + { + if (i2cPrivateHandle->handle->transfer.direction == kI2C_Read) + { + /* Change to send NAK at the last byte. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TXAK_MASK; + + /* Wait the last data to be received. */ + while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag)) + { + } + + /* Change direction to send. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TX_MASK; + + /* Read the last data byte. */ + *(i2cPrivateHandle->handle->transfer.data + i2cPrivateHandle->handle->transfer.dataSize - 1) = + i2cPrivateHandle->base->D; + } + } i2cPrivateHandle->handle->state = kIdleState; @@ -203,7 +223,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, assert(xfer); status_t result = kStatus_Success; - uint16_t timeout = UINT16_MAX; if (handle->state != kIdleState) { @@ -221,16 +240,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, handle->state = kTransferDataState; - /* Wait until ready to complete. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -250,22 +259,55 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction); } + if (result) + { + return result; + } + + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + /* Return if error. */ + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + if (I2C_MasterStop(base) != kStatus_Success) + { + result = kStatus_I2C_Timeout; + } + + if (handle->completionCallback) + { + (handle->completionCallback)(base, handle, result, handle->userData); + } + } + + return result; + } + /* Send subaddress. */ if (handle->transfer.subaddressSize) { do { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear interrupt pending flag. */ base->S = kI2C_IntPendingFlag; handle->transfer.subaddressSize--; base->D = ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize)); + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + /* Check if there's transfer error. */ result = I2C_CheckAndClearError(base, base->S); @@ -278,34 +320,34 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, if (handle->transfer.direction == kI2C_Read) { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; /* Send repeated start and slave address. */ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read); + + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + return result; + } } } - if (result) - { - return result; - } - - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); } return result; @@ -319,17 +361,7 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ { transfer_config.srcAddr = (uint32_t)I2C_GetDataRegAddr(base); transfer_config.destAddr = (uint32_t)(handle->transfer.data); - - /* Send stop if kI2C_TransferNoStop flag is not asserted. */ - if (!(handle->transfer.flags & kI2C_TransferNoStopFlag)) - { - transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); - } - else - { - transfer_config.majorLoopCounts = handle->transfer.dataSize; - } - + transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); transfer_config.srcTransferSize = kEDMA_TransferSize1Bytes; transfer_config.srcOffset = 0; transfer_config.destTransferSize = kEDMA_TransferSize1Bytes; @@ -348,6 +380,9 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ transfer_config.minorLoopBytes = 1; } + /* Store the initially configured eDMA minor byte transfer count into the I2C handle */ + handle->nbytes = transfer_config.minorLoopBytes; + EDMA_SubmitTransfer(handle->dmaHandle, &transfer_config); EDMA_StartTransfer(handle->dmaHandle); } @@ -427,7 +462,7 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle if (handle->transfer.direction == kI2C_Read) { /* Change direction for receive. */ - base->C1 &= ~I2C_C1_TX_MASK; + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); /* Read dummy to release the bus. */ dummy = base->D; @@ -479,6 +514,11 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle { result = I2C_MasterStop(base); } + else + { + /* Change direction to send. */ + base->C1 |= I2C_C1_TX_MASK; + } /* Read the last byte of data. */ if (handle->transfer.direction == kI2C_Read) @@ -504,7 +544,9 @@ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t if (kIdleState != handle->state) { - *count = (handle->transferSize - EDMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel)); + *count = (handle->transferSize - + (uint32_t)handle->nbytes * + EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel)); } else { diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.h index c95d6adeee..40cb648ea9 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/drivers/fsl_i2c_edma.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -39,7 +39,6 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ @@ -56,13 +55,14 @@ typedef void (*i2c_master_edma_transfer_callback_t)(I2C_Type *base, /*! @brief I2C master eDMA transfer structure. */ struct _i2c_master_edma_handle { - i2c_master_transfer_t transfer; /*!< I2C master transfer struct. */ + i2c_master_transfer_t transfer; /*!< I2C master transfer structure. */ size_t transferSize; /*!< Total bytes to be transferred. */ + uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */ uint8_t state; /*!< I2C master transfer status. */ edma_handle_t *dmaHandle; /*!< The eDMA handler used. */ i2c_master_edma_transfer_callback_t - completionCallback; /*!< Callback function called after eDMA transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + completionCallback; /*!< A callback function called after the eDMA transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /******************************************************************************* @@ -79,12 +79,12 @@ extern "C" { */ /*! - * @brief Init the I2C handle which is used in transcational functions. + * @brief Initializes the I2C handle which is used in transcational functions. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param callback pointer to user callback function. - * @param userData user param passed to the callback function. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param callback A pointer to the user callback function. + * @param userData A user parameter passed to the callback function. * @param edmaHandle eDMA handle pointer. */ void I2C_MasterCreateEDMAHandle(I2C_Type *base, @@ -97,30 +97,30 @@ void I2C_MasterCreateEDMAHandle(I2C_Type *base, * @brief Performs a master eDMA non-blocking transfer on the I2C bus. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param xfer pointer to transfer structure of i2c_master_transfer_t. - * @retval kStatus_Success Sucessully complete the data transmission. - * @retval kStatus_I2C_Busy Previous transmission still not finished. - * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param xfer A pointer to the transfer structure of i2c_master_transfer_t. + * @retval kStatus_Success Sucessfully completed the data transmission. + * @retval kStatus_I2C_Busy A previous transmission is still not finished. + * @retval kStatus_I2C_Timeout Transfer error, waits for a signal timeout. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. - * @retval kStataus_I2C_Nak Transfer error, receive Nak during transfer. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, i2c_master_transfer_t *xfer); /*! - * @brief Get master transfer status during a eDMA non-blocking transfer. + * @brief Gets a master transfer status during the eDMA non-blocking transfer. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param count Number of bytes transferred so far by the non-blocking transaction. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param count A number of bytes transferred by the non-blocking transaction. */ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, size_t *count); /*! - * @brief Abort a master eDMA non-blocking transfer in a early time. + * @brief Aborts a master eDMA non-blocking transfer early. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. + * @param handle A pointer to the i2c_master_edma_handle_t structure. */ void I2C_MasterTransferAbortEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle); diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.c index e77a383239..6c9770af25 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -75,6 +75,19 @@ typedef void (*i2c_isr_t)(I2C_Type *base, void *i2cHandle); */ uint32_t I2C_GetInstance(I2C_Type *base); +/*! +* @brief Set SCL/SDA hold time, this API receives SCL stop hold time, calculate the +* closest SCL divider and MULT value for the SDA hold time, SCL start and SCL stop +* hold time. To reduce the ROM size, SDA/SCL hold value mapping table is not provided, +* assume SCL divider = SCL stop hold value *2 to get the closest SCL divider value and MULT +* value, then the related SDA hold time, SCL start and SCL stop hold time is used. +* +* @param base I2C peripheral base address. +* @param sourceClock_Hz I2C functional clock frequency in Hertz. +* @param sclStopHoldTime_ns SCL stop hold time in ns. +*/ +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz); + /*! * @brief Set up master transfer, send slave address and decide the initial * transfer state. @@ -125,20 +138,22 @@ static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle); static void *s_i2cHandle[FSL_FEATURE_SOC_I2C_COUNT] = {NULL}; /*! @brief SCL clock divider used to calculate baudrate. */ -const uint16_t s_i2cDividerTable[] = {20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, - 48, 56, 68, 48, 56, 64, 72, 80, 88, 104, 128, 80, 96, - 112, 128, 144, 160, 192, 240, 160, 192, 224, 256, 288, 320, 384, - 480, 320, 384, 448, 512, 576, 640, 768, 960, 640, 768, 896, 1024, - 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840}; +static const uint16_t s_i2cDividerTable[] = { + 20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, 68, + 48, 56, 64, 72, 80, 88, 104, 128, 80, 96, 112, 128, 144, 160, 192, 240, + 160, 192, 224, 256, 288, 320, 384, 480, 320, 384, 448, 512, 576, 640, 768, 960, + 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840}; /*! @brief Pointers to i2c bases for each instance. */ static I2C_Type *const s_i2cBases[] = I2C_BASE_PTRS; /*! @brief Pointers to i2c IRQ number for each instance. */ -const IRQn_Type s_i2cIrqs[] = I2C_IRQS; +static const IRQn_Type s_i2cIrqs[] = I2C_IRQS; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to i2c clocks for each instance. */ -const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS; +static const clock_ip_name_t s_i2cClocks[] = I2C_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief Pointer to master IRQ handler for each instance. */ static i2c_isr_t s_i2cMasterIsr; @@ -155,7 +170,7 @@ uint32_t I2C_GetInstance(I2C_Type *base) uint32_t instance; /* Find the instance index from base address mappings. */ - for (instance = 0; instance < FSL_FEATURE_SOC_I2C_COUNT; instance++) + for (instance = 0; instance < ARRAY_SIZE(s_i2cBases); instance++) { if (s_i2cBases[instance] == base) { @@ -163,16 +178,63 @@ uint32_t I2C_GetInstance(I2C_Type *base) } } - assert(instance < FSL_FEATURE_SOC_I2C_COUNT); + assert(instance < ARRAY_SIZE(s_i2cBases)); return instance; } +static void I2C_SetHoldTime(I2C_Type *base, uint32_t sclStopHoldTime_ns, uint32_t sourceClock_Hz) +{ + uint32_t multiplier; + uint32_t computedSclHoldTime; + uint32_t absError; + uint32_t bestError = UINT32_MAX; + uint32_t bestMult = 0u; + uint32_t bestIcr = 0u; + uint8_t mult; + uint8_t i; + + /* Search for the settings with the lowest error. Mult is the MULT field of the I2C_F register, + * and ranges from 0-2. It selects the multiplier factor for the divider. */ + /* SDA hold time = bus period (s) * mul * SDA hold value. */ + /* SCL start hold time = bus period (s) * mul * SCL start hold value. */ + /* SCL stop hold time = bus period (s) * mul * SCL stop hold value. */ + + for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult) + { + multiplier = 1u << mult; + + /* Scan table to find best match. */ + for (i = 0u; i < sizeof(s_i2cDividerTable) / sizeof(s_i2cDividerTable[0]); ++i) + { + /* Assume SCL hold(stop) value = s_i2cDividerTable[i]/2. */ + computedSclHoldTime = ((multiplier * s_i2cDividerTable[i]) * 500000000U) / sourceClock_Hz; + absError = sclStopHoldTime_ns > computedSclHoldTime ? (sclStopHoldTime_ns - computedSclHoldTime) : + (computedSclHoldTime - sclStopHoldTime_ns); + + if (absError < bestError) + { + bestMult = mult; + bestIcr = i; + bestError = absError; + + /* If the error is 0, then we can stop searching because we won't find a better match. */ + if (absError == 0) + { + break; + } + } + } + } + + /* Set frequency register based on best settings. */ + base->F = I2C_F_MULT(bestMult) | I2C_F_ICR(bestIcr); +} + static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t *handle, i2c_master_transfer_t *xfer) { status_t result = kStatus_Success; i2c_direction_t direction = xfer->direction; - uint16_t timeout = UINT16_MAX; /* Initialize the handle transfer information. */ handle->transfer = *xfer; @@ -183,27 +245,13 @@ static status_t I2C_InitTransferStateMachine(I2C_Type *base, i2c_master_handle_t /* Initial transfer state. */ if (handle->transfer.subaddressSize > 0) { - handle->state = kSendCommandState; if (xfer->direction == kI2C_Read) { direction = kI2C_Write; } } - else - { - handle->state = kCheckAddressState; - } - /* Wait until the data register is ready for transmit. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } + handle->state = kCheckAddressState; /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -265,34 +313,41 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han result = kStatus_Success; } - if (result) - { - return result; - } - /* Handle Check address state to check the slave address is Acked in slave probe application. */ if (handle->state == kCheckAddressState) { if (statusFlags & kI2C_ReceiveNakFlag) { - return kStatus_I2C_Nak; + result = kStatus_I2C_Addr_Nak; } else { - if (handle->transfer.direction == kI2C_Write) + if (handle->transfer.subaddressSize > 0) { - /* Next state, send data. */ - handle->state = kSendDataState; + handle->state = kSendCommandState; } else { - /* Next state, receive data begin. */ - handle->state = kReceiveDataBeginState; + if (handle->transfer.direction == kI2C_Write) + { + /* Next state, send data. */ + handle->state = kSendDataState; + } + else + { + /* Next state, receive data begin. */ + handle->state = kReceiveDataBeginState; + } } } } + if (result) + { + return result; + } + /* Run state machine. */ switch (handle->state) { @@ -375,6 +430,10 @@ static status_t I2C_MasterTransferRunStateMachine(I2C_Type *base, i2c_master_han { result = I2C_MasterStop(base); } + else + { + base->C1 |= I2C_C1_TX_MASK; + } } /* Send NAK at the last receive byte. */ @@ -407,6 +466,7 @@ static void I2C_TransferCommonIRQHandler(I2C_Type *base, void *handle) { s_i2cSlaveIsr(base, handle); } + __DSB(); } void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz) @@ -415,12 +475,26 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Temporary register for filter read. */ uint8_t fltReg; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - uint8_t c2Reg; +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + uint8_t s2Reg; #endif - +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Enable I2C clock. */ CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Disable I2C prior to configuring it. */ base->C1 &= ~(I2C_C1_IICEN_MASK); @@ -431,14 +505,6 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Configure baud rate. */ I2C_MasterSetBaudRate(base, masterConfig->baudRate_Bps, srcClock_Hz); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Configure high drive feature. */ - c2Reg = base->C2; - c2Reg &= ~(I2C_C2_HDRS_MASK); - c2Reg |= I2C_C2_HDRS(masterConfig->enableHighDrive); - base->C2 = c2Reg; -#endif - /* Read out the FLT register. */ fltReg = base->FLT; @@ -455,6 +521,12 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin /* Write the register value back to the filter register. */ base->FLT = fltReg; +/* Enable/Disable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + s2Reg = base->S2 & (~I2C_S2_DFEN_MASK); + base->S2 = s2Reg | I2C_S2_DFEN(masterConfig->enableDoubleBuffering); +#endif + /* Enable the I2C peripheral based on the configuration. */ base->C1 = I2C_C1_IICEN(masterConfig->enableMaster); } @@ -464,8 +536,10 @@ void I2C_MasterDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) @@ -475,11 +549,6 @@ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) /* Default baud rate at 100kbps. */ masterConfig->baudRate_Bps = 100000U; -/* Default pin high drive is disabled. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - masterConfig->enableHighDrive = false; -#endif - /* Default stop hold enable is disabled. */ #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF masterConfig->enableStopHold = false; @@ -488,12 +557,21 @@ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig) /* Default glitch filter value is no filter. */ masterConfig->glitchFilterWidth = 0U; +/* Default enable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + masterConfig->enableDoubleBuffering = true; +#endif + /* Enable the I2C peripheral. */ masterConfig->enableMaster = true; } void I2C_EnableInterrupts(I2C_Type *base, uint32_t mask) { +#ifdef I2C_HAS_STOP_DETECT + uint8_t fltReg; +#endif + if (mask & kI2C_GlobalInterruptEnable) { base->C1 |= I2C_C1_IICIE_MASK; @@ -502,14 +580,28 @@ void I2C_EnableInterrupts(I2C_Type *base, uint32_t mask) #if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT if (mask & kI2C_StopDetectInterruptEnable) { - base->FLT |= I2C_FLT_STOPIE_MASK; + fltReg = base->FLT; + + /* Keep STOPF flag. */ + fltReg &= ~I2C_FLT_STOPF_MASK; + + /* Stop detect enable. */ + fltReg |= I2C_FLT_STOPIE_MASK; + base->FLT = fltReg; } #endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */ #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT if (mask & kI2C_StartStopDetectInterruptEnable) { - base->FLT |= I2C_FLT_SSIE_MASK; + fltReg = base->FLT; + + /* Keep STARTF and STOPF flags. */ + fltReg &= ~(I2C_FLT_STOPF_MASK | I2C_FLT_STARTF_MASK); + + /* Start and stop detect enable. */ + fltReg |= I2C_FLT_SSIE_MASK; + base->FLT = fltReg; } #endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ } @@ -524,14 +616,14 @@ void I2C_DisableInterrupts(I2C_Type *base, uint32_t mask) #if defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT if (mask & kI2C_StopDetectInterruptEnable) { - base->FLT &= ~I2C_FLT_STOPIE_MASK; + base->FLT &= ~(I2C_FLT_STOPIE_MASK | I2C_FLT_STOPF_MASK); } #endif /* FSL_FEATURE_I2C_HAS_STOP_DETECT */ #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT if (mask & kI2C_StartStopDetectInterruptEnable) { - base->FLT &= ~I2C_FLT_SSIE_MASK; + base->FLT &= ~(I2C_FLT_SSIE_MASK | I2C_FLT_STOPF_MASK | I2C_FLT_STARTF_MASK); } #endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ } @@ -623,7 +715,7 @@ status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_ base->F = savedMult & (~I2C_F_MULT_MASK); /* We are already in a transfer, so send a repeated start. */ - base->C1 |= I2C_C1_RSTA_MASK; + base->C1 |= I2C_C1_RSTA_MASK | I2C_C1_TX_MASK; /* Restore the multiplier factor. */ base->F = savedMult; @@ -690,7 +782,7 @@ uint32_t I2C_MasterGetStatusFlags(I2C_Type *base) return statusFlags; } -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize) +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags) { status_t result = kStatus_Success; uint8_t statusFlags = 0; @@ -728,7 +820,7 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t result = kStatus_I2C_ArbitrationLost; } - if (statusFlags & kI2C_ReceiveNakFlag) + if ((statusFlags & kI2C_ReceiveNakFlag) && txSize) { base->S = kI2C_ReceiveNakFlag; result = kStatus_I2C_Nak; @@ -741,10 +833,19 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t } } + if (((result == kStatus_Success) && (!(flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) + { + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send stop. */ + result = I2C_MasterStop(base); + } + return result; } -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags) { status_t result = kStatus_Success; volatile uint8_t dummy = 0; @@ -786,8 +887,16 @@ status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) /* Single byte use case. */ if (rxSize == 0) { - /* Read the final byte. */ - result = I2C_MasterStop(base); + if (!(flags & kI2C_TransferNoStopFlag)) + { + /* Issue STOP command before reading last byte. */ + result = I2C_MasterStop(base); + } + else + { + /* Change direction to Tx to avoid extra clocks. */ + base->C1 |= I2C_C1_TX_MASK; + } } if (rxSize == 1) @@ -840,72 +949,6 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) return result; } - /* Send subaddress. */ - if (xfer->subaddressSize) - { - do - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear interrupt pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - xfer->subaddressSize--; - base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); - - } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); - - if (xfer->direction == kI2C_Read) - { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - - /* Clear pending flag. */ - base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); - - if (result) - { - if (result == kStatus_I2C_Nak) - { - I2C_MasterStop(base); - } - - return result; - } - - /* Send repeated start and slave address. */ - result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); - - /* Return if error. */ - if (result) - { - return result; - } - } - } - - /* Wait until address + command transfer complete. */ while (!(base->S & kI2C_IntPendingFlag)) { } @@ -918,32 +961,92 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) { if (result == kStatus_I2C_Nak) { + result = kStatus_I2C_Addr_Nak; + I2C_MasterStop(base); } return result; } + /* Send subaddress. */ + if (xfer->subaddressSize) + { + do + { + /* Clear interrupt pending flag. */ + base->S = kI2C_IntPendingFlag; + + xfer->subaddressSize--; + base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize)); + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + I2C_MasterStop(base); + } + + return result; + } + + } while ((xfer->subaddressSize > 0) && (result == kStatus_Success)); + + if (xfer->direction == kI2C_Read) + { + /* Clear pending flag. */ + base->S = kI2C_IntPendingFlag; + + /* Send repeated start and slave address. */ + result = I2C_MasterRepeatedStart(base, xfer->slaveAddress, kI2C_Read); + + /* Return if error. */ + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + I2C_MasterStop(base); + } + + return result; + } + } + } + /* Transmit data. */ if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)) { /* Send Data. */ - result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize); - - if (((result == kStatus_Success) && (!(xfer->flags & kI2C_TransferNoStopFlag))) || (result == kStatus_I2C_Nak)) - { - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; - - /* Send stop. */ - result = I2C_MasterStop(base); - } + result = I2C_MasterWriteBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } /* Receive Data. */ if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)) { - result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize); + result = I2C_MasterReadBlocking(base, xfer->data, xfer->dataSize, xfer->flags); } return result; @@ -1006,11 +1109,37 @@ void I2C_MasterTransferAbort(I2C_Type *base, i2c_master_handle_t *handle) { assert(handle); + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + /* Disable interrupt. */ I2C_DisableInterrupts(base, kI2C_GlobalInterruptEnable); /* Reset the state to idle. */ handle->state = kIdleState; + + /* Send STOP signal. */ + if (handle->transfer.direction == kI2C_Read) + { + base->C1 |= I2C_C1_TXAK_MASK; + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + dummy = base->D; + } + else + { + while (!(base->S & kI2C_IntPendingFlag)) + { + } + base->S = kI2C_IntPendingFlag; + base->C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + } } status_t I2C_MasterTransferGetCount(I2C_Type *base, i2c_master_handle_t *handle, size_t *count) @@ -1044,7 +1173,8 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) if (isDone || result) { /* Send stop command if transfer done or received Nak. */ - if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak)) + if ((!(handle->transfer.flags & kI2C_TransferNoStopFlag)) || (result == kStatus_I2C_Nak) || + (result == kStatus_I2C_Addr_Nak)) { /* Ensure stop command is a need. */ if ((base->C1 & I2C_C1_MST_MASK)) @@ -1070,13 +1200,28 @@ void I2C_MasterTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz) { assert(slaveConfig); uint8_t tmpReg; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) CLOCK_EnableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Reset the module. */ + base->A1 = 0; + base->F = 0; + base->C1 = 0; + base->S = 0xFFU; + base->C2 = 0; +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + base->FLT = 0x50U; +#elif defined(FSL_FEATURE_I2C_HAS_STOP_DETECT) && FSL_FEATURE_I2C_HAS_STOP_DETECT + base->FLT = 0x40U; +#endif + base->RA = 0; /* Configure addressing mode. */ switch (slaveConfig->addressingMode) @@ -1101,15 +1246,20 @@ void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig) tmpReg &= ~I2C_C1_WUEN_MASK; base->C1 = tmpReg | I2C_C1_WUEN(slaveConfig->enableWakeUp) | I2C_C1_IICEN(slaveConfig->enableSlave); - /* Configure general call & baud rate control & high drive feature. */ + /* Configure general call & baud rate control. */ tmpReg = base->C2; tmpReg &= ~(I2C_C2_SBRC_MASK | I2C_C2_GCAEN_MASK); tmpReg |= I2C_C2_SBRC(slaveConfig->enableBaudRateCtl) | I2C_C2_GCAEN(slaveConfig->enableGeneralCall); -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - tmpReg &= ~I2C_C2_HDRS_MASK; - tmpReg |= I2C_C2_HDRS(slaveConfig->enableHighDrive); -#endif base->C2 = tmpReg; + +/* Enable/Disable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + tmpReg = base->S2 & (~I2C_S2_DFEN_MASK); + base->S2 = tmpReg | I2C_S2_DFEN(slaveConfig->enableDoubleBuffering); +#endif + + /* Set hold time. */ + I2C_SetHoldTime(base, slaveConfig->sclStopHoldTime_ns, srcClock_Hz); } void I2C_SlaveDeinit(I2C_Type *base) @@ -1117,8 +1267,10 @@ void I2C_SlaveDeinit(I2C_Type *base) /* Disable I2C module. */ I2C_Enable(base, false); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Disable I2C clock. */ CLOCK_DisableClock(s_i2cClocks[I2C_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) @@ -1134,48 +1286,106 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig) /* Slave address match waking up MCU from low power mode is disabled. */ slaveConfig->enableWakeUp = false; -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - /* Default pin high drive is disabled. */ - slaveConfig->enableHighDrive = false; -#endif - /* Independent slave mode baud rate at maximum frequency is disabled. */ slaveConfig->enableBaudRateCtl = false; +/* Default enable double buffering. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + slaveConfig->enableDoubleBuffering = true; +#endif + + /* Set default SCL stop hold time to 4us which is minimum requirement in I2C spec. */ + slaveConfig->sclStopHoldTime_ns = 4000; + /* Enable the I2C peripheral. */ slaveConfig->enableSlave = true; } status_t I2C_SlaveWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize) { - return I2C_MasterWriteBlocking(base, txBuff, txSize); + status_t result = kStatus_Success; + volatile uint8_t dummy = 0; + + /* Add this to avoid build warning. */ + dummy++; + +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + /* Check start flag. */ + while (!(base->FLT & I2C_FLT_STARTF_MASK)) + { + } + /* Clear STARTF flag. */ + base->FLT |= I2C_FLT_STARTF_MASK; + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ + + /* Wait for address match flag. */ + while (!(base->S & kI2C_AddressMatchFlag)) + { + } + + /* Read dummy to release bus. */ + dummy = base->D; + + result = I2C_MasterWriteBlocking(base, txBuff, txSize, kI2C_TransferDefaultFlag); + + /* Switch to receive mode. */ + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + + /* Read dummy to release bus. */ + dummy = base->D; + + return result; } void I2C_SlaveReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize) { - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; + volatile uint8_t dummy = 0; - /* Wait until the data register is ready for receive. */ - while (!(base->S & kI2C_TransferCompleteFlag)) + /* Add this to avoid build warning. */ + dummy++; + +/* Wait until address match. */ +#if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT + /* Check start flag. */ + while (!(base->FLT & I2C_FLT_STARTF_MASK)) { } + /* Clear STARTF flag. */ + base->FLT |= I2C_FLT_STARTF_MASK; + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; +#endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ + + /* Wait for address match and int pending flag. */ + while (!(base->S & kI2C_AddressMatchFlag)) + { + } + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Read dummy to release bus. */ + dummy = base->D; + + /* Clear the IICIF flag. */ + base->S = kI2C_IntPendingFlag; /* Setup the I2C peripheral to receive data. */ base->C1 &= ~(I2C_C1_TX_MASK); while (rxSize--) { + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } /* Clear the IICIF flag. */ base->S = kI2C_IntPendingFlag; /* Read from the data register. */ *rxBuff++ = base->D; - - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } } } @@ -1226,7 +1436,7 @@ status_t I2C_SlaveTransferNonBlocking(I2C_Type *base, i2c_slave_handle_t *handle handle->isBusy = true; /* Set up event mask. tx and rx are always enabled. */ - handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent; + handle->eventMask = eventMask | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | kI2C_SlaveGenaralcallEvent; /* Clear all flags. */ I2C_SlaveClearStatusFlags(base, kClearFlags); @@ -1315,7 +1525,10 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } - return; + if (!(status & kI2C_AddressMatchFlag)) + { + return; + } } #endif /* I2C_HAS_STOP_DETECT */ @@ -1328,7 +1541,7 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) /* Clear the interrupt flag. */ base->S = kI2C_IntPendingFlag; - xfer->event = kI2C_SlaveRepeatedStartEvent; + xfer->event = kI2C_SlaveStartEvent; if ((handle->eventMask & xfer->event) && (handle->callback)) { @@ -1385,31 +1598,12 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) handle->isBusy = true; xfer->event = kI2C_SlaveAddressMatchEvent; - if ((handle->eventMask & xfer->event) && (handle->callback)) - { - handle->callback(base, xfer, handle->userData); - } - /* Slave transmit, master reading from slave. */ if (status & kI2C_TransferDirectionFlag) { /* Change direction to send data. */ base->C1 |= I2C_C1_TX_MASK; - /* If we're out of data, invoke callback to get more. */ - if ((!xfer->data) || (!xfer->dataSize)) - { - xfer->event = kI2C_SlaveTransmitEvent; - - if (handle->callback) - { - handle->callback(base, xfer, handle->userData); - } - - /* Clear the transferred count now that we have a new buffer. */ - xfer->transferredCount = 0; - } - doTransmit = true; } else @@ -1417,6 +1611,30 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) /* Slave receive, master writing to slave. */ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + /* Read dummy to release the bus. */ + dummy = base->D; + + if (dummy == 0) + { + xfer->event = kI2C_SlaveGenaralcallEvent; + } + } + + if ((handle->eventMask & xfer->event) && (handle->callback)) + { + handle->callback(base, xfer, handle->userData); + } + } + /* Check transfer complete flag. */ + else if (status & kI2C_TransferCompleteFlag) + { + /* Slave transmit, master reading from slave. */ + if (status & kI2C_TransferDirectionFlag) + { + doTransmit = true; + } + else + { /* If we're out of data, invoke callback to get more. */ if ((!xfer->data) || (!xfer->dataSize)) { @@ -1431,20 +1649,6 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) xfer->transferredCount = 0; } - /* Read dummy to release the bus. */ - dummy = base->D; - } - } - /* Check transfer complete flag. */ - else if (status & kI2C_TransferCompleteFlag) - { - /* Slave transmit, master reading from slave. */ - if (status & kI2C_TransferDirectionFlag) - { - doTransmit = true; - } - else - { /* Slave receive, master writing to slave. */ uint8_t data = base->D; @@ -1480,6 +1684,20 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) /* Send data if there is the need. */ if (doTransmit) { + /* If we're out of data, invoke callback to get more. */ + if ((!xfer->data) || (!xfer->dataSize)) + { + xfer->event = kI2C_SlaveTransmitEvent; + + if (handle->callback) + { + handle->callback(base, xfer, handle->userData); + } + + /* Clear the transferred count now that we have a new buffer. */ + xfer->transferredCount = 0; + } + if (handle->transfer.dataSize) { /* Send data. */ @@ -1510,27 +1728,30 @@ void I2C_SlaveTransferHandleIRQ(I2C_Type *base, void *i2cHandle) } } +#if defined(I2C0) void I2C0_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C0, s_i2cHandle[0]); } +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 1) +#if defined(I2C1) void I2C1_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C1, s_i2cHandle[1]); } -#endif /* I2C COUNT > 1 */ +#endif -#if (FSL_FEATURE_SOC_I2C_COUNT > 2) +#if defined(I2C2) void I2C2_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C2, s_i2cHandle[2]); } -#endif /* I2C COUNT > 2 */ -#if (FSL_FEATURE_SOC_I2C_COUNT > 3) +#endif + +#if defined(I2C3) void I2C3_DriverIRQHandler(void) { I2C_TransferCommonIRQHandler(I2C3, s_i2cHandle[3]); } -#endif /* I2C COUNT > 3 */ +#endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.h index 41a9afbdd5..d55fd1d8ea 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -37,16 +37,14 @@ * @{ */ -/*! @file */ - /******************************************************************************* * Definitions ******************************************************************************/ /*! @name Driver version */ /*@{*/ -/*! @brief I2C driver version 2.0.0. */ -#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*! @brief I2C driver version 2.0.3. */ +#define FSL_I2C_DRIVER_VERSION (MAKE_VERSION(2, 0, 3)) /*@}*/ #if (defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT || \ @@ -62,6 +60,7 @@ enum _i2c_status kStatus_I2C_Nak = MAKE_STATUS(kStatusGroup_I2C, 2), /*!< NAK received during transfer. */ kStatus_I2C_ArbitrationLost = MAKE_STATUS(kStatusGroup_I2C, 3), /*!< Arbitration lost during transfer. */ kStatus_I2C_Timeout = MAKE_STATUS(kStatusGroup_I2C, 4), /*!< Wait event timeout. */ + kStatus_I2C_Addr_Nak = MAKE_STATUS(kStatusGroup_I2C, 5), /*!< NAK received during the address probe. */ }; /*! @@ -109,11 +108,11 @@ enum _i2c_interrupt_enable #endif /* FSL_FEATURE_I2C_HAS_START_STOP_DETECT */ }; -/*! @brief Direction of master and slave transfers. */ +/*! @brief The direction of master and slave transfers. */ typedef enum _i2c_direction { - kI2C_Write = 0x0U, /*!< Master transmit to slave. */ - kI2C_Read = 0x1U, /*!< Master receive from slave. */ + kI2C_Write = 0x0U, /*!< Master transmits to the slave. */ + kI2C_Read = 0x1U, /*!< Master receives from the slave. */ } i2c_direction_t; /*! @brief Addressing mode. */ @@ -126,17 +125,17 @@ typedef enum _i2c_slave_address_mode /*! @brief I2C transfer control flag. */ enum _i2c_master_transfer_flags { - kI2C_TransferDefaultFlag = 0x0U, /*!< Transfer starts with a start signal, stops with a stop signal. */ - kI2C_TransferNoStartFlag = 0x1U, /*!< Transfer starts without a start signal. */ - kI2C_TransferRepeatedStartFlag = 0x2U, /*!< Transfer starts with a repeated start signal. */ - kI2C_TransferNoStopFlag = 0x4U, /*!< Transfer ends without a stop signal. */ + kI2C_TransferDefaultFlag = 0x0U, /*!< A transfer starts with a start signal, stops with a stop signal. */ + kI2C_TransferNoStartFlag = 0x1U, /*!< A transfer starts without a start signal. */ + kI2C_TransferRepeatedStartFlag = 0x2U, /*!< A transfer starts with a repeated start signal. */ + kI2C_TransferNoStopFlag = 0x4U, /*!< A transfer ends without a stop signal. */ }; /*! * @brief Set of events sent to the callback for nonblocking slave transfers. * * These event enumerations are used for two related purposes. First, a bit mask created by OR'ing together - * events is passed to I2C_SlaveTransferNonBlocking() in order to specify which events to enable. + * events is passed to I2C_SlaveTransferNonBlocking() to specify which events to enable. * Then, when the slave callback is invoked, it is passed the current event through its @a transfer * parameter. * @@ -145,33 +144,35 @@ enum _i2c_master_transfer_flags typedef enum _i2c_slave_transfer_event { kI2C_SlaveAddressMatchEvent = 0x01U, /*!< Received the slave address after a start or repeated start. */ - kI2C_SlaveTransmitEvent = 0x02U, /*!< Callback is requested to provide data to transmit + kI2C_SlaveTransmitEvent = 0x02U, /*!< A callback is requested to provide data to transmit (slave-transmitter role). */ - kI2C_SlaveReceiveEvent = 0x04U, /*!< Callback is requested to provide a buffer in which to place received + kI2C_SlaveReceiveEvent = 0x04U, /*!< A callback is requested to provide a buffer in which to place received data (slave-receiver role). */ - kI2C_SlaveTransmitAckEvent = 0x08U, /*!< Callback needs to either transmit an ACK or NACK. */ + kI2C_SlaveTransmitAckEvent = 0x08U, /*!< A callback needs to either transmit an ACK or NACK. */ #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT - kI2C_SlaveRepeatedStartEvent = 0x10U, /*!< A repeated start was detected. */ + kI2C_SlaveStartEvent = 0x10U, /*!< A start/repeated start was detected. */ #endif - kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveCompletionEvent = 0x20U, /*!< A stop was detected or finished transfer, completing the transfer. */ + kI2C_SlaveGenaralcallEvent = 0x40U, /*!< Received the general call address after a start or repeated start. */ - /*! Bit mask of all available events. */ + /*! A bit mask of all available events. */ kI2C_SlaveAllEvents = kI2C_SlaveAddressMatchEvent | kI2C_SlaveTransmitEvent | kI2C_SlaveReceiveEvent | #if defined(FSL_FEATURE_I2C_HAS_START_STOP_DETECT) && FSL_FEATURE_I2C_HAS_START_STOP_DETECT - kI2C_SlaveRepeatedStartEvent | + kI2C_SlaveStartEvent | #endif - kI2C_SlaveCompletionEvent, + kI2C_SlaveCompletionEvent | kI2C_SlaveGenaralcallEvent, } i2c_slave_transfer_event_t; /*! @brief I2C master user configuration. */ typedef struct _i2c_master_config { bool enableMaster; /*!< Enables the I2C peripheral at initialization time. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ -#endif #if defined(FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF) && FSL_FEATURE_I2C_HAS_STOP_HOLD_OFF bool enableStopHold; /*!< Controls the stop hold enable. */ +#endif +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + bool enableDoubleBuffering; /*!< Controls double buffer enable; notice that + enabling the double buffer disables the clock stretch. */ #endif uint32_t baudRate_Bps; /*!< Baud rate configuration of I2C peripheral. */ uint8_t glitchFilterWidth; /*!< Controls the width of the glitch. */ @@ -181,15 +182,20 @@ typedef struct _i2c_master_config typedef struct _i2c_slave_config { bool enableSlave; /*!< Enables the I2C peripheral at initialization time. */ - bool enableGeneralCall; /*!< Enable general call addressing mode. */ - bool enableWakeUp; /*!< Enables/disables waking up MCU from low power mode. */ -#if defined(FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION) && FSL_FEATURE_I2C_HAS_HIGH_DRIVE_SELECTION - bool enableHighDrive; /*!< Controls the drive capability of the I2C pads. */ + bool enableGeneralCall; /*!< Enables the general call addressing mode. */ + bool enableWakeUp; /*!< Enables/disables waking up MCU from low-power mode. */ +#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFER_ENABLE + bool enableDoubleBuffering; /*!< Controls a double buffer enable; notice that + enabling the double buffer disables the clock stretch. */ #endif bool enableBaudRateCtl; /*!< Enables/disables independent slave baud rate on SCL in very fast I2C modes. */ - uint16_t slaveAddress; /*!< Slave address configuration. */ - uint16_t upperAddress; /*!< Maximum boundary slave address used in range matching mode. */ - i2c_slave_address_mode_t addressingMode; /*!< Addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint16_t slaveAddress; /*!< A slave address configuration. */ + uint16_t upperAddress; /*!< A maximum boundary slave address used in a range matching mode. */ + i2c_slave_address_mode_t + addressingMode; /*!< An addressing mode configuration of i2c_slave_address_mode_config_t. */ + uint32_t sclStopHoldTime_ns; /*!< the delay from the rising edge of SCL (I2C clock) to the rising edge of SDA (I2C + data) while SCL is high (stop condition), SDA hold time and SCL start hold time + are also configured according to the SCL stop hold time. */ } i2c_slave_config_t; /*! @brief I2C master handle typedef. */ @@ -207,13 +213,13 @@ typedef struct _i2c_slave_handle i2c_slave_handle_t; /*! @brief I2C master transfer structure. */ typedef struct _i2c_master_transfer { - uint32_t flags; /*!< Transfer flag which controls the transfer. */ + uint32_t flags; /*!< A transfer flag which controls the transfer. */ uint8_t slaveAddress; /*!< 7-bit slave address. */ - i2c_direction_t direction; /*!< Transfer direction, read or write. */ - uint32_t subaddress; /*!< Sub address. Transferred MSB first. */ - uint8_t subaddressSize; /*!< Size of command buffer. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_direction_t direction; /*!< A transfer direction, read or write. */ + uint32_t subaddress; /*!< A sub address. Transferred MSB first. */ + uint8_t subaddressSize; /*!< A size of the command buffer. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ } i2c_master_transfer_t; /*! @brief I2C master handle structure. */ @@ -221,20 +227,21 @@ struct _i2c_master_handle { i2c_master_transfer_t transfer; /*!< I2C master transfer copy. */ size_t transferSize; /*!< Total bytes to be transferred. */ - uint8_t state; /*!< Transfer state maintained during transfer. */ - i2c_master_transfer_callback_t completionCallback; /*!< Callback function called when transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + uint8_t state; /*!< A transfer state maintained during transfer. */ + i2c_master_transfer_callback_t completionCallback; /*!< A callback function called when the transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /*! @brief I2C slave transfer structure. */ typedef struct _i2c_slave_transfer { - i2c_slave_transfer_event_t event; /*!< Reason the callback is being invoked. */ - uint8_t *volatile data; /*!< Transfer buffer. */ - volatile size_t dataSize; /*!< Transfer size. */ + i2c_slave_transfer_event_t event; /*!< A reason that the callback is invoked. */ + uint8_t *volatile data; /*!< A transfer buffer. */ + volatile size_t dataSize; /*!< A transfer size. */ status_t completionStatus; /*!< Success or error code describing how the transfer completed. Only applies for #kI2C_SlaveCompletionEvent. */ - size_t transferredCount; /*!< Number of bytes actually transferred since start or last repeated start. */ + size_t transferredCount; /*!< A number of bytes actually transferred since the start or since the last repeated + start. */ } i2c_slave_transfer_t; /*! @brief I2C slave transfer callback typedef. */ @@ -243,11 +250,11 @@ typedef void (*i2c_slave_transfer_callback_t)(I2C_Type *base, i2c_slave_transfer /*! @brief I2C slave handle structure. */ struct _i2c_slave_handle { - bool isBusy; /*!< Whether transfer is busy. */ + volatile bool isBusy; /*!< Indicates whether a transfer is busy. */ i2c_slave_transfer_t transfer; /*!< I2C slave transfer copy. */ - uint32_t eventMask; /*!< Mask of enabled events. */ - i2c_slave_transfer_callback_t callback; /*!< Callback function called at transfer event. */ - void *userData; /*!< Callback parameter passed to callback. */ + uint32_t eventMask; /*!< A mask of enabled events. */ + i2c_slave_transfer_callback_t callback; /*!< A callback function called at the transfer event. */ + void *userData; /*!< A callback parameter passed to the callback. */ }; /******************************************************************************* @@ -267,12 +274,12 @@ extern "C" { * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock * and configure the I2C with master configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module could cause hard fault - * because clock is not enabled. The configuration structure can be filled by user - * from scratch, or be set with default values by I2C_MasterGetDefaultConfig(). + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault + * because the clock is not enabled. The configuration structure can be custom filled + * or it can be set with default values by using the I2C_MasterGetDefaultConfig(). * After calling this API, the master is ready to transfer. - * Example: + * This is an example. * @code * i2c_master_config_t config = { * .enableMaster = true, @@ -285,20 +292,20 @@ extern "C" { * @endcode * * @param base I2C base pointer - * @param masterConfig pointer to master configuration structure + * @param masterConfig A pointer to the master configuration structure * @param srcClock_Hz I2C peripheral clock frequency in Hz */ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uint32_t srcClock_Hz); /*! * @brief Initializes the I2C peripheral. Call this API to ungate the I2C clock - * and initializes the I2C with slave configuration. + * and initialize the I2C with the slave configuration. * - * @note This API should be called at the beginning of the application to use - * the I2C driver, or any operation to the I2C module can cause a hard fault + * @note This API should be called at the beginning of the application. + * Otherwise, any operation to the I2C module can cause a hard fault * because the clock is not enabled. The configuration structure can partly be set - * with default values by I2C_SlaveGetDefaultConfig(), or can be filled by the user. - * Example + * with default values by I2C_SlaveGetDefaultConfig() or it can be custom filled by the user. + * This is an example. * @code * i2c_slave_config_t config = { * .enableSlave = true, @@ -307,15 +314,17 @@ void I2C_MasterInit(I2C_Type *base, const i2c_master_config_t *masterConfig, uin * .slaveAddress = 0x1DU, * .enableWakeUp = false, * .enablehighDrive = false, - * .enableBaudRateCtl = false + * .enableBaudRateCtl = false, + * .sclStopHoldTime_ns = 4000 * }; - * I2C_SlaveInit(I2C0, &config); + * I2C_SlaveInit(I2C0, &config, 12000000U); * @endcode * * @param base I2C base pointer - * @param slaveConfig pointer to slave configuration structure + * @param slaveConfig A pointer to the slave configuration structure + * @param srcClock_Hz I2C peripheral clock frequency in Hz */ -void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig); +void I2C_SlaveInit(I2C_Type *base, const i2c_slave_config_t *slaveConfig, uint32_t srcClock_Hz); /*! * @brief De-initializes the I2C master peripheral. Call this API to gate the I2C clock. @@ -335,28 +344,28 @@ void I2C_SlaveDeinit(I2C_Type *base); * @brief Sets the I2C master configuration structure to default values. * * The purpose of this API is to get the configuration structure initialized for use in the I2C_MasterConfigure(). - * Use the initialized structure unchanged in I2C_MasterConfigure(), or modify some fields of - * the structure before calling I2C_MasterConfigure(). - * Example: + * Use the initialized structure unchanged in the I2C_MasterConfigure() or modify + * the structure before calling the I2C_MasterConfigure(). + * This is an example. * @code * i2c_master_config_t config; * I2C_MasterGetDefaultConfig(&config); * @endcode - * @param masterConfig Pointer to the master configuration structure. + * @param masterConfig A pointer to the master configuration structure. */ void I2C_MasterGetDefaultConfig(i2c_master_config_t *masterConfig); /*! * @brief Sets the I2C slave configuration structure to default values. * - * The purpose of this API is to get the configuration structure initialized for use in I2C_SlaveConfigure(). + * The purpose of this API is to get the configuration structure initialized for use in the I2C_SlaveConfigure(). * Modify fields of the structure before calling the I2C_SlaveConfigure(). - * Example: + * This is an example. * @code * i2c_slave_config_t config; * I2C_SlaveGetDefaultConfig(&config); * @endcode - * @param slaveConfig Pointer to the slave configuration structure. + * @param slaveConfig A pointer to the slave configuration structure. */ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); @@ -364,7 +373,7 @@ void I2C_SlaveGetDefaultConfig(i2c_slave_config_t *slaveConfig); * @brief Enables or disabless the I2C peripheral operation. * * @param base I2C base pointer - * @param enable pass true to enable module, false to disable module + * @param enable Pass true to enable and false to disable the module. */ static inline void I2C_Enable(I2C_Type *base, bool enable) { @@ -389,7 +398,7 @@ static inline void I2C_Enable(I2C_Type *base, bool enable) * @brief Gets the I2C status flags. * * @param base I2C base pointer - * @return status flag, use status flag to AND #_i2c_flags could get the related status. + * @return status flag, use status flag to AND #_i2c_flags to get the related status. */ uint32_t I2C_MasterGetStatusFlags(I2C_Type *base); @@ -397,7 +406,7 @@ uint32_t I2C_MasterGetStatusFlags(I2C_Type *base); * @brief Gets the I2C status flags. * * @param base I2C base pointer - * @return status flag, use status flag to AND #_i2c_flags could get the related status. + * @return status flag, use status flag to AND #_i2c_flags to get the related status. */ static inline uint32_t I2C_SlaveGetStatusFlags(I2C_Type *base) { @@ -407,11 +416,11 @@ static inline uint32_t I2C_SlaveGetStatusFlags(I2C_Type *base) /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag. * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. - * The parameter could be any combination of the following values: + * The parameter can be any combination of the following values: * @arg kI2C_StartDetectFlag (if available) * @arg kI2C_StopDetectFlag (if available) * @arg kI2C_ArbitrationLostFlag @@ -442,11 +451,11 @@ static inline void I2C_MasterClearStatusFlags(I2C_Type *base, uint32_t statusMas /*! * @brief Clears the I2C status flag state. * - * The following status register flags can be cleared: kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag + * The following status register flags can be cleared kI2C_ArbitrationLostFlag and kI2C_IntPendingFlag * * @param base I2C base pointer * @param statusMask The status flag mask, defined in type i2c_status_flag_t. - * The parameter could be any combination of the following values: + * The parameter can be any combination of the following values: * @arg kI2C_StartDetectFlag (if available) * @arg kI2C_StopDetectFlag (if available) * @arg kI2C_ArbitrationLostFlag @@ -574,19 +583,21 @@ status_t I2C_MasterStop(I2C_Type *base); status_t I2C_MasterRepeatedStart(I2C_Type *base, uint8_t address, i2c_direction_t direction); /*! - * @brief Performs a polling send transaction on the I2C bus without a STOP signal. + * @brief Performs a polling send transaction on the I2C bus. * * @param base The I2C peripheral base pointer. * @param txBuff The pointer to the data to be transferred. * @param txSize The length in bytes of the data to be transferred. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ -status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize); +status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t txSize, uint32_t flags); /*! - * @brief Performs a polling receive transaction on the I2C bus with a STOP signal. + * @brief Performs a polling receive transaction on the I2C bus. * * @note The I2C_MasterReadBlocking function stops the bus before reading the final byte. * Without stopping the bus prior for the final read, the bus issues another read, resulting @@ -595,10 +606,12 @@ status_t I2C_MasterWriteBlocking(I2C_Type *base, const uint8_t *txBuff, size_t t * @param base I2C peripheral base pointer. * @param rxBuff The pointer to the data to store the received data. * @param rxSize The length in bytes of the data to be received. + * @param flags Transfer control flag to decide whether need to send a stop, use kI2C_TransferDefaultFlag +* to issue a stop and kI2C_TransferNoStop to not send a stop. * @retval kStatus_Success Successfully complete the data transmission. * @retval kStatus_I2C_Timeout Send stop signal failed, timeout. */ -status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize); +status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize, uint32_t flags); /*! * @brief Performs a polling send transaction on the I2C bus. @@ -650,7 +663,7 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer) * @param base I2C base pointer. * @param handle pointer to i2c_master_handle_t structure to store the transfer state. * @param callback pointer to user callback function. - * @param userData user paramater passed to the callback function. + * @param userData user parameter passed to the callback function. */ void I2C_MasterTransferCreateHandle(I2C_Type *base, i2c_master_handle_t *handle, @@ -660,15 +673,15 @@ void I2C_MasterTransferCreateHandle(I2C_Type *base, /*! * @brief Performs a master interrupt non-blocking transfer on the I2C bus. * - * @note Calling the API will return immediately after transfer initiates, user needs + * @note Calling the API returns immediately after transfer initiates. The user needs * to call I2C_MasterGetTransferCount to poll the transfer status to check whether - * the transfer is finished, if the return status is not kStatus_I2C_Busy, the transfer + * the transfer is finished. If the return status is not kStatus_I2C_Busy, the transfer * is finished. * * @param base I2C base pointer. * @param handle pointer to i2c_master_handle_t structure which stores the transfer state. * @param xfer pointer to i2c_master_transfer_t structure. - * @retval kStatus_Success Sucessully start the data transmission. + * @retval kStatus_Success Successfully start the data transmission. * @retval kStatus_I2C_Busy Previous transmission still not finished. * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. */ diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.c index c8f7c20629..28a415e075 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -162,6 +162,26 @@ static void I2C_MasterTransferCallbackEDMA(edma_handle_t *handle, void *userData result = I2C_MasterStop(i2cPrivateHandle->base); } } + else + { + if (i2cPrivateHandle->handle->transfer.direction == kI2C_Read) + { + /* Change to send NAK at the last byte. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TXAK_MASK; + + /* Wait the last data to be received. */ + while (!(i2cPrivateHandle->base->S & kI2C_TransferCompleteFlag)) + { + } + + /* Change direction to send. */ + i2cPrivateHandle->base->C1 |= I2C_C1_TX_MASK; + + /* Read the last data byte. */ + *(i2cPrivateHandle->handle->transfer.data + i2cPrivateHandle->handle->transfer.dataSize - 1) = + i2cPrivateHandle->base->D; + } + } i2cPrivateHandle->handle->state = kIdleState; @@ -203,7 +223,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, assert(xfer); status_t result = kStatus_Success; - uint16_t timeout = UINT16_MAX; if (handle->state != kIdleState) { @@ -221,16 +240,6 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, handle->state = kTransferDataState; - /* Wait until ready to complete. */ - while ((!(base->S & kI2C_TransferCompleteFlag)) && (--timeout)) - { - } - - /* Failed to start the transfer. */ - if (timeout == 0) - { - return kStatus_I2C_Timeout; - } /* Clear all status before transfer. */ I2C_MasterClearStatusFlags(base, kClearFlags); @@ -250,22 +259,55 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, result = I2C_MasterStart(base, handle->transfer.slaveAddress, direction); } + if (result) + { + return result; + } + + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + /* Return if error. */ + if (result) + { + if (result == kStatus_I2C_Nak) + { + result = kStatus_I2C_Addr_Nak; + + if (I2C_MasterStop(base) != kStatus_Success) + { + result = kStatus_I2C_Timeout; + } + + if (handle->completionCallback) + { + (handle->completionCallback)(base, handle, result, handle->userData); + } + } + + return result; + } + /* Send subaddress. */ if (handle->transfer.subaddressSize) { do { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear interrupt pending flag. */ base->S = kI2C_IntPendingFlag; handle->transfer.subaddressSize--; base->D = ((handle->transfer.subaddress) >> (8 * handle->transfer.subaddressSize)); + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + /* Check if there's transfer error. */ result = I2C_CheckAndClearError(base, base->S); @@ -278,34 +320,34 @@ static status_t I2C_InitTransferStateMachineEDMA(I2C_Type *base, if (handle->transfer.direction == kI2C_Read) { - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; /* Send repeated start and slave address. */ result = I2C_MasterRepeatedStart(base, handle->transfer.slaveAddress, kI2C_Read); + + if (result) + { + return result; + } + + /* Wait until data transfer complete. */ + while (!(base->S & kI2C_IntPendingFlag)) + { + } + + /* Check if there's transfer error. */ + result = I2C_CheckAndClearError(base, base->S); + + if (result) + { + return result; + } } } - if (result) - { - return result; - } - - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } - /* Clear pending flag. */ base->S = kI2C_IntPendingFlag; - - /* Check if there's transfer error. */ - result = I2C_CheckAndClearError(base, base->S); } return result; @@ -319,17 +361,7 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ { transfer_config.srcAddr = (uint32_t)I2C_GetDataRegAddr(base); transfer_config.destAddr = (uint32_t)(handle->transfer.data); - - /* Send stop if kI2C_TransferNoStop flag is not asserted. */ - if (!(handle->transfer.flags & kI2C_TransferNoStopFlag)) - { - transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); - } - else - { - transfer_config.majorLoopCounts = handle->transfer.dataSize; - } - + transfer_config.majorLoopCounts = (handle->transfer.dataSize - 1); transfer_config.srcTransferSize = kEDMA_TransferSize1Bytes; transfer_config.srcOffset = 0; transfer_config.destTransferSize = kEDMA_TransferSize1Bytes; @@ -348,6 +380,9 @@ static void I2C_MasterTransferEDMAConfig(I2C_Type *base, i2c_master_edma_handle_ transfer_config.minorLoopBytes = 1; } + /* Store the initially configured eDMA minor byte transfer count into the I2C handle */ + handle->nbytes = transfer_config.minorLoopBytes; + EDMA_SubmitTransfer(handle->dmaHandle, &transfer_config); EDMA_StartTransfer(handle->dmaHandle); } @@ -427,7 +462,7 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle if (handle->transfer.direction == kI2C_Read) { /* Change direction for receive. */ - base->C1 &= ~I2C_C1_TX_MASK; + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); /* Read dummy to release the bus. */ dummy = base->D; @@ -479,6 +514,11 @@ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle { result = I2C_MasterStop(base); } + else + { + /* Change direction to send. */ + base->C1 |= I2C_C1_TX_MASK; + } /* Read the last byte of data. */ if (handle->transfer.direction == kI2C_Read) @@ -504,7 +544,9 @@ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t if (kIdleState != handle->state) { - *count = (handle->transferSize - EDMA_GetRemainingBytes(handle->dmaHandle->base, handle->dmaHandle->channel)); + *count = (handle->transferSize - + (uint32_t)handle->nbytes * + EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel)); } else { diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.h index 234876d451..40cb648ea9 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/drivers/fsl_i2c_edma.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. - * All rights reserved. + * Copyright 2016-2017 NXP * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * o Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * @@ -39,31 +39,30 @@ * @{ */ -/*! @file */ - /******************************************************************************* * Definitions ******************************************************************************/ -/*! @brief I2C master edma handle typedef. */ +/*! @brief I2C master eDMA handle typedef. */ typedef struct _i2c_master_edma_handle i2c_master_edma_handle_t; -/*! @brief I2C master edma transfer callback typedef. */ +/*! @brief I2C master eDMA transfer callback typedef. */ typedef void (*i2c_master_edma_transfer_callback_t)(I2C_Type *base, i2c_master_edma_handle_t *handle, status_t status, void *userData); -/*! @brief I2C master edma transfer structure. */ +/*! @brief I2C master eDMA transfer structure. */ struct _i2c_master_edma_handle { - i2c_master_transfer_t transfer; /*!< I2C master transfer struct. */ + i2c_master_transfer_t transfer; /*!< I2C master transfer structure. */ size_t transferSize; /*!< Total bytes to be transferred. */ + uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */ uint8_t state; /*!< I2C master transfer status. */ edma_handle_t *dmaHandle; /*!< The eDMA handler used. */ i2c_master_edma_transfer_callback_t - completionCallback; /*!< Callback function called after edma transfer finished. */ - void *userData; /*!< Callback parameter passed to callback function. */ + completionCallback; /*!< A callback function called after the eDMA transfer is finished. */ + void *userData; /*!< A callback parameter passed to the callback function. */ }; /******************************************************************************* @@ -75,18 +74,18 @@ extern "C" { #endif /*_cplusplus. */ /*! - * @name I2C Block EDMA Transfer Operation + * @name I2C Block eDMA Transfer Operation * @{ */ /*! - * @brief Init the I2C handle which is used in transcational functions. + * @brief Initializes the I2C handle which is used in transcational functions. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param callback pointer to user callback function. - * @param userData user param passed to the callback function. - * @param edmaHandle EDMA handle pointer. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param callback A pointer to the user callback function. + * @param userData A user parameter passed to the callback function. + * @param edmaHandle eDMA handle pointer. */ void I2C_MasterCreateEDMAHandle(I2C_Type *base, i2c_master_edma_handle_t *handle, @@ -95,33 +94,33 @@ void I2C_MasterCreateEDMAHandle(I2C_Type *base, edma_handle_t *edmaHandle); /*! - * @brief Performs a master edma non-blocking transfer on the I2C bus. + * @brief Performs a master eDMA non-blocking transfer on the I2C bus. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param xfer pointer to transfer structure of i2c_master_transfer_t. - * @retval kStatus_Success Sucessully complete the data transmission. - * @retval kStatus_I2C_Busy Previous transmission still not finished. - * @retval kStatus_I2C_Timeout Transfer error, wait signal timeout. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param xfer A pointer to the transfer structure of i2c_master_transfer_t. + * @retval kStatus_Success Sucessfully completed the data transmission. + * @retval kStatus_I2C_Busy A previous transmission is still not finished. + * @retval kStatus_I2C_Timeout Transfer error, waits for a signal timeout. * @retval kStatus_I2C_ArbitrationLost Transfer error, arbitration lost. - * @retval kStataus_I2C_Nak Transfer error, receive Nak during transfer. + * @retval kStataus_I2C_Nak Transfer error, receive NAK during transfer. */ status_t I2C_MasterTransferEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, i2c_master_transfer_t *xfer); /*! - * @brief Get master transfer status during a edma non-blocking transfer. + * @brief Gets a master transfer status during the eDMA non-blocking transfer. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. - * @param count Number of bytes transferred so far by the non-blocking transaction. + * @param handle A pointer to the i2c_master_edma_handle_t structure. + * @param count A number of bytes transferred by the non-blocking transaction. */ status_t I2C_MasterTransferGetCountEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle, size_t *count); /*! - * @brief Abort a master edma non-blocking transfer in a early time. + * @brief Aborts a master eDMA non-blocking transfer early. * * @param base I2C peripheral base address. - * @param handle pointer to i2c_master_edma_handle_t structure. + * @param handle A pointer to the i2c_master_edma_handle_t structure. */ void I2C_MasterTransferAbortEDMA(I2C_Type *base, i2c_master_edma_handle_t *handle);