MCUXpresso: Update I2C SDK driver

Use the K66F driver that has the latest

Signed-off-by: Mahesh Mahadevan <mahesh.mahadevan@nxp.com>
pull/11308/head
Mahesh Mahadevan 2019-08-21 17:18:34 -05:00 committed by adbridge
parent 8022ca918f
commit eda75fd02a
16 changed files with 2065 additions and 1274 deletions

View File

@ -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

View File

@ -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.

View File

@ -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
{

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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
{

View File

@ -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);

View File

@ -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

View File

@ -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.

View File

@ -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
{

View File

@ -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);

View File

@ -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.
*/

View File

@ -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
{

View File

@ -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);