Problem in FreeRTOS I2C driver for KW4x microcontroller

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem in FreeRTOS I2C driver for KW4x microcontroller

Jump to solution
2,947 Views
saurabhbansal
Contributor II

Hello All,

 

I am working on KW41 microcontroller and using KDS for development. I have to do i2c communication, for that I am using FreeRTOS library. I am calling I2C_RTOS_Transfer to read a register in my I2C device. Please have a look on below defination of I2C_RTOS_Transfer :

 

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 */
    xSemaphoreTake(handle->sem, portMAX_DELAY);

 

    /* Unlock resource mutex */
    xSemaphoreGive(handle->mutex);

 

    /* Return status captured by callback function */
    return handle->async_status;
}

 

This program is hanging while executing the xSemaphoreTake command highlighted with red color.

while looking in code with debugger, the program is going to hang while executing portYIELD_WITHIN_API(); in queue.h library.

Can somebody help me to resolve this problem.

 

Thanks,

Saurabh

Labels (1)
0 Kudos
Reply
1 Solution
2,038 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Saurabh,

For the serial bus example based on FreeRTOS platform, for example uart, spi, iic even can, this is the architecture:

the serial bus uses interrupt mode to transfer data, and the example transfer one block of data(the size of block data can be programmed). In the ISR, we have code to check if the predefined number of block of data has been transferred completely, if the block of data has been transferred completely, a callback functiion is called. In the callback function, the so-called xSemaphoreGive() is posted so that the task which has the code I2C_RTOS_Transfer() can be unblocked.

Hope it can help you

BR

Xiangjun Rong

View solution in original post

4 Replies
2,038 Views
saurabhbansal
Contributor II

Thanks for your help. I was able to resolve this issue.

It was because of 2 problems:

1.   Debugger was showing different places for hanging each time(I am using J-Link for this).

2.   There was wrong clock initialisation, because I was porting the code from other microcontroller, but clock part was left same by mistake.

@Xiangjun Rong thanks for clarifying the point of clearing the semaphore in callback.

0 Kudos
Reply
2,039 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Saurabh,

For the serial bus example based on FreeRTOS platform, for example uart, spi, iic even can, this is the architecture:

the serial bus uses interrupt mode to transfer data, and the example transfer one block of data(the size of block data can be programmed). In the ISR, we have code to check if the predefined number of block of data has been transferred completely, if the block of data has been transferred completely, a callback functiion is called. In the callback function, the so-called xSemaphoreGive() is posted so that the task which has the code I2C_RTOS_Transfer() can be unblocked.

Hope it can help you

BR

Xiangjun Rong

2,038 Views
manfredschnell
Contributor IV

Hi Saurabh & Xiangjun Rong

I think every RTOS-Driver for hardware should have a separate timeout for getting the hardware (mutex) and for end of Transfer (sem). ...

I reworked the I2C driver as follows:

"fsl_i2c_freertos.h"

/*! @brief I2C FreeRTOS handle */
typedef struct _i2c_rtos_handle
{
    I2C_Type *base;                 /*!< I2C base address */
    i2c_master_handle_t drv_handle; /*!< Handle of the underlying driver, treated as opaque by the RTOS layer */
    status_t async_status;
    SemaphoreHandle_t mutex; /*!< Mutex to lock the handle during a trasfer */
    TickType_t xTicsToWaitForMutex; // by MS --> timeout for getting the hardware
    SemaphoreHandle_t sem;   /*!< Semaphore to notify and unblock task when transfer ends */
    TickType_t xTicsToWaitForSem; // by MS --> timeout for device response
} i2c_rtos_handle_t;

"fsl_i2c_freertos.c"

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, handle->xTicsToWaitForMutex) != 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 */
    if ( xSemaphoreTake(handle->sem, handle->xTicsToWaitForSem) != pdTRUE)
    {
        /* Unlock resource mutex */
        xSemaphoreGive(handle->mutex);
        return kStatus_I2C_Timeout;
    }

    /* Unlock resource mutex */
    xSemaphoreGive(handle->mutex);

    /* Return status captured by callback function */
    return handle->async_status;
}

Best regards

Manfred

0 Kudos
Reply
2,038 Views
FreeRTOS_org
Contributor IV

First, it is generally not good practice to wait indefinitely using portMAX_DELAY, but instead to use a timeout that is just a little longer than the maximum time you would expect to have to wait.  That way if the block time expires you know something has gone wrong and you have the opportunity to diagnose and correct the issue.  If something goes wrong while you are blocked indefinitely then the blocked task will just hang where it is forever.

Second in most cases it is desirable to use a direct to task notification in place of a semaphore.  See the code snippet on the following page for an example: vTaskNotifyGiveFromISR() RTOS task notification API documentation 

Then to your question - why is the task hanging in the xSemaphoreTake() call:  First you have to determine which end is the causing the problem, giving the semaphore or taking the semaphores.  If the call to xSemaphoreTake() never completes my first assumption would be that nothing is giving the semaphore.  Can you verify that the corresponding call to xSemaphoreGive() (or the ISR equivalent) is completing.