i2c freertos

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

i2c freertos

1,857 Views
Microfelix
Contributor IV

Hi, I need help.
And recently I have been working with freertos, I have been able to use different peripherals but I still have problems with I2C.

The examples are also very poor.
How can I read and write an I2C peripheral as I did with mqx 4.1.

Thanks to those who will help me.
a good example is welcome.

Maurizio

0 Kudos
4 Replies

1,834 Views
Microfelix
Contributor IV

hi @myke_predko 

Thanks for the reply.
I've already tried, but the answer is always the same.
From my device, I see with oscilloscope only the first byte then nothing.
And I2C_RTOS_Transfer returns 0x451.
Some idea?

Maurizio

0 Kudos

1,831 Views
myke_predko
Senior Contributor III

HI @Microfelix 

When you get error codes, you're going to have to do some digging in the source code and look at data in different formats - the documentation isn't great but looking at the source code it really isn't that hard and just takes a few seconds.  

I clicked on "I2C_RTOS_Transfer" and then presed "F3" to go to "fsl_i2c_freertos.c" and in there, I saw that there is a "return kStatus_I2C_Busy;" statement at the start.  The value of the error is 1100 decimal.  

I clicked on "kStatus_I2C_Busy" and then pressed "F3" and ended up in "fsl_i2c.h" with the code block:

enum _i2c_status
{
kStatus_I2C_Busy = MAKE_STATUS(kStatusGroup_I2C, 0), /*!< I2C is busy with current transfer. */
kStatus_I2C_Idle = MAKE_STATUS(kStatusGroup_I2C, 1), /*!< Bus is Idle. */
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), /*!< Timeout poling status flags. */
kStatus_I2C_Addr_Nak = MAKE_STATUS(kStatusGroup_I2C, 5), /*!< NAK received during the address probe. */
};

When I look at the "MAKE_STATUS" macro, it's multiplying the first parameter by 100 decimal and adding the second one to it.  If you hover over "kStatusGroup_I2C" you'll discover that it is equal to 11 decimal - for "kStatus_I2C_Busy" it's 11 * 100 plus 0 (as you can see above).  

Now, 0x451 is 1105 decimal, so looking at the enum above, I can see that the message being returned is "kStatus_I2C_Addr_Nak" - you'll have to look at the address of the peripheral you're trying to address.  

On the address Nak error, here's a hint, you may have to take the I2C address specified in the peripheral chip's dtasheet and shift it to the left once (or multiply be 2, it's the same thing).  This is something of a quirk with these parts - the address is effectively shifted up by 2 when it is transmitted but this isn't done in the drivers.  I think everybody using I2C has been caught by this error.  

Regardless, I've spent about 10x the time writing up what I did compared to how much time it took to actually find the error's definition.  

Good luck.  

 

1,849 Views
myke_predko
Senior Contributor III

Hi @Microfelix 

I'm guessing you're asking about master mode.  

I've attached my I2C write task written for FreeRTOS here.  In the task, a message with data to send is sent to the task which sends it out using I2C and returns when the transfer is complete (or has failed).  In the attached task I'm using the Kinetis FreeRTOS driver (I2C FreeRTOS Driver Reference) and you can see that it's really quite simple.  This code is for doing writes to an OLED display driver - another task loads "rxMsg" with the device address, provides a single dimensional array of UINT8_t bytes to transmit with the number of bytes specified.  

Based on my experience with the ADC, SPI and UART FreeRTOS Kinetis drivers, I am going to rewrite this task to use the standard SDK I2C drivers with interrupts (where appropriate).  There should be less overhead along with having more control over the I2C port's operation.  

Regardless of what I want to do, the Kinetis I2C FreeRTOS drivers are very easy to work with  and can be used for fast/quick and dirty interfaces.  

Good luck!

myke

0 Kudos

1,547 Views
danielholala
Senior Contributor II

Dear @myke_predko ,

I'm also trying to bring fsl_i2c_freertos.c  from SDK to good use. But I'm worried that it does not properly lock i2c transactions.

I don't know the SDK code for your MCU, mine is for the LPC55xx and the relevant part looks like:

 

 

 

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)
    {
        (void)xSemaphoreGive(handle->mutex);
        return status;
    }

    /* Wait for transfer to finish */
    (void)xSemaphoreTake(handle->semaphore, portMAX_DELAY);

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

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

 

The call to I2C_MasterTransferNonBlocking() is protected by a mutex, however, the SDK is poorly written (in comparison to LPCOpen) and thus a single I2C transaction likely will have to use multiple calls to I2C_RTOS_Transfer(). In between these calls the I2C bus is left in a  busy state.

Consider two tasks accessing I2C via I2C_RTOS_Transfer(). The first task calls to send a write-datagram and omits the Stop-Condition ( to continue with the I2C-transaction with a call to a read data). What happens if a second task now accesses I2C_RTOS_Transfer? The I2C bus is still busy because the bus devices have seen a Start Condition but not yet a Stop Condition. But as the I2C_RTOS_Transfer() is I2C-transaction-agnostic, it does not prevent this.

I assume one needs to add a I2C-transaction based lock. 

Does that make sense?

 

 

0 Kudos