summaryrefslogtreecommitdiff
path: root/drivers/fsl_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/fsl_i2c.c')
-rw-r--r--drivers/fsl_i2c.c376
1 files changed, 250 insertions, 126 deletions
diff --git a/drivers/fsl_i2c.c b/drivers/fsl_i2c.c
index b51fc07..6c9770a 100644
--- a/drivers/fsl_i2c.c
+++ b/drivers/fsl_i2c.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
- * All rights reserved.
+ * Copyright 2016-2017 NXP
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
@@ -12,7 +12,7 @@
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
- * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
@@ -76,6 +76,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,19 +949,42 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer)
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;
+
+ 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))
{
}
- /* Clear interrupt pending flag. */
- base->S = kI2C_IntPendingFlag;
-
/* Check if there's transfer error. */
result = I2C_CheckAndClearError(base, base->S);
@@ -897,21 +998,27 @@ status_t I2C_MasterTransferBlocking(I2C_Type *base, i2c_master_transfer_t *xfer)
return result;
}
- xfer->subaddressSize--;
- base->D = ((xfer->subaddress) >> (8 * xfer->subaddressSize));
-
} 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))
{
}
- /* Clear pending flag. */
- base->S = kI2C_IntPendingFlag;
-
/* Check if there's transfer error. */
result = I2C_CheckAndClearError(base, base->S);
@@ -919,62 +1026,27 @@ 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 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))
- {
- }
-
- /* Check if there's transfer error. */
- result = I2C_CheckAndClearError(base, base->S);
-
- /* Return if error. */
- if (result)
- {
- if (result == kStatus_I2C_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