I'm using the I2C interface on a LPC54608 as master device to read an I2C slave device (LM75B temperature sensor). I find that occasionally the I2C peripheral is detecting an arbitration error. The error itself is a worry, but a bigger concern is the fact that the SDK code cannot recover from this error.
My application code is running on FreeRTOS and I'm using the example RTOS code provided in the SDK. The low-level I2C driver code is version 2.0.6 (fsl_i2C). I can debug the code and I see that the arbitration bit is set, detected by the code, and cleared, but the peripheral seems to immediately go back to a pending state, and any subsequent attempts to acces the I2C interface will fail because the SDK code is written to wait until the peripheral is available, and it seems that it will never become available after this sequence.
A reset of the processor clears the error state and I2C communications to the device will then work again for a period of time. So I'm wondering if anyone can suggest the best was to recover this I2C peripheral device after an I2C arbitration error?
Regards,
Padraig
We are using the i.MX RT1176 and have the same problem with the latest SDK. Is NXP going to fix this issue? How can we recover from an i2c communication error? We use FreeRTOS too, just like Pardraig.
Kind regards,
John
In addition to the I2C abritation problem, the NXP SDK function I2C_RTOS_Transfer() has a few bugs, for which I have added details and suggested solutions as below.
status_t I2C_RTOS_Transfer(i2c_rtos_handle_t *handle, i2c_master_transfer_t *transfer)
{
status_t status;
/* Lock resource mutex */
if (xSemaphoreTake(handle->mutex, portMAX_DELAY) != pdTRUE)
{
return kStatus_I2C_Busy;
}
status = I2C_MasterTransferNonBlocking(handle->base, &handle->drv_handle, transfer);
if (status != kStatus_Success)
{
xSemaphoreGive(handle->mutex);
return status;
}
/* Wait for transfer to finish */
(void)xSemaphoreTake(handle->semaphore, portMAX_DELAY);
BUG 1
Using the standard SDK code, the xSemaphoreTake delay will never expire after an I2C error occurs, so any task calling this will obviously hang forever!
/* Unlock resource mutex */
xSemaphoreGive(handle->mutex);
/* Return status captured by callback function */
return handle->async_status;
BUG 2
The async_status is read after the mutex has been released, if another I2C transfer is pending for the same interface the returned status will be invalid. May seem unlikely but it does happen!!
}
-----------------------------------------------------------
BUG 1 Suggested solution (limited testing but so far this has recovered from the arbitration error)
Use a fixed time delay when waiting for the semaphore, and if a timeout occurs (due to arbitration or other error) then:
1) Clear I2C status flags using I2C_MasterClearStatusFlags()
2) Reset the problem I2C interface using RESET_PeripheralReset()
3) Init the interface using I2C_MasterInit()
4) Reset the RTOS transfer state-machine
handle->drv_handle.state = (uint8_t)kIdleState;
-----------------------------------------------------------
BUG 2 Suggested solution (as per fsl_spi_freertos.c, SPI_RTOS_Transfer())
/* Retrieve status before releasing mutex */
status = handle->async_status;
Thanks for providing this feedback. I will send this information to the SDK team internally.
Best regards,
Felipe
Hi Padraig,
Most of the times arbitration lost is caused by a timing issue. The recommended workaround for this is to reset the I2C bus to avoid you reset the MCU.
You can try executing I2C_MasterDeinit and initialize the module again once you detect arbitration error.
Best regards,
Felipe
-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!
- We are following threads for 7 weeks after the last post, later replies are ignored.
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
------------------------------------------------------------------------------
Felipe,
Thank you for the suggestion, I can certainly try this.
I have tried similar approaches, but since I am running FreeRTOS there is other code e.g. the transfer state machine which must also be reset and re-initialised; and the I2C_RTOS_Deinit() function is no use since it destroys the RTOS mutex and semaphore.
Anyway, I take it from the your response that the SDK code does not have any implemented and tested mechanism to recover from this error.
regards,
Padraig