Skip to main content
Visitor II
April 30, 2019
Question

How to access multiple I2C devices on the same I2C line?

  • April 30, 2019
  • 9 replies
  • 13956 views

Hi,

I am using STM32F091VC based custom board. and our application is Multi thread with the FreeRTOS. On I2C1 line three device are connected. all the device are accessed from the different thread. to prevent the simultaneous access we have used Mutex. so, at a time only one device can be accessed. also we have configured I2C communication with the DMA(interrupt based). but some time application execution stuck in HAL layer's I2C ISR relted Api. this might be because of simultaneous access.

For your refer i am attaching my I2C code, Please suggest that Is our implementation is correct or not. also give some light to implement code to access multiple device on same I2C line.

    This topic has been closed for replies.

    9 replies

    Visitor II
    April 30, 2019

    I don't know much about HAL and how it handles I2C bus errors, but you do understand the I2C protocol and slave device addressing, right? I any of your three devices have the same ui16DeviceAddress (in your code), or if any of them do I2C "clock stretching" or don't ACK their address to the STM32F091VC the bus will hang. That might be why your application gets stuck in HAL.

    I don't know the STM32F091VC but in general the ST reference manuals have good descriptions of the I2C protocol in their I2C peripheral sections. If not, there's good generic I2C information available online, for example at https://www.i2c-bus.org/specification/

    Hope this helps.

    ssath.7Author
    Visitor II
    May 1, 2019

    Hello,

    Thanks for the response,

    Three device FRAM, EEPROM and LED controller are connected with the I2C1 and RFID card reader is connected with the I2C2. and all the devices have different I2C device address. and SDA and SCL lines are pull up with 3.3v 10K Ohm resistor.

    I am all ready using the mutex to protect I2C lines. I am using osMutexWait() freeRTOS mutex API, which you can see in i2c.c file. All the device works fine, but some it creates the problem.

    When we are using two I2C lines simultaneously at that time problem generate more frequently.

    If you time then please refer our I2c read write implementation in i2c.c file, which have attached with question. and suggest that that is our implementation correct or not.

    read API : I2C1_readData()

    write API : I2C1_writeData()

    I am also attaching the block diagram for your reference.

    Visitor II
    April 30, 2019

    What devices are you using, and do they have hard address lines (typically A0,A1,A2) that you can pull high/ground to set one of eight addresses. You will need to use a mutex to access them in a threaded/RTOS environment.

    ssath.7Author
    Visitor II
    May 1, 2019

    Hello Gray,

    Thanks for the response,

    Three device FRAM, EEPROM and LED controller are connected with the I2C1 and RFID card reader is connected with the I2C2. and all the devices have different I2C device address. and SDA and SCL lines are pull up with 3.3v 10K Ohm resistor.

    I am all ready using the mutex to protect I2C lines. I am using osMutexWait() freeRTOS mutex API, which you can see in i2c.c file. All the device works fine, but some it creates the problem.

    When we are using two I2C lines simultaneously at that time problem generate more frequently.

    If you time then please refer our I2c read write implementation in i2c.c file, which have attached with question. and suggest that that is our implementation correct or not.

    read API : I2C1_readData()

    write API : I2C1_writeData()

    I am also attaching the block diagram for your reference.

    Visitor II
    May 1, 2019

    Is (HAL_I2C_Mem_Read_DMA() blocking ?

    ssath.7Author
    Visitor II
    May 1, 2019

    Yes, Some time device stuck in HAL_I2C_Mem_Read_DMA() and some times it stucks in HAL_I2C_Mem_Write_DMA().

    and now i am performing read/write operation with only one I2C peripheral(Led controller) in long run of around 20 minutes, still device stuck in any of the above mentioned API.

    Visitor II
    May 1, 2019

    Is anything being executed in an ISR, such as the DMA IRQ callback? Could be a deadlock issue. You may need a context switch to a higher priority task so it may be getting delayed . You might look at using portYIELD_FROM_ISR.

    ssath.7Author
    Visitor II
    May 2, 2019

    We have not implemented I2C call backs.

    we have found one work around. Actually LED controller need 1ms of delay before two consecutive read/write call. but it is not mentioned led controller data sheet.

    Now I don't know that it is issue from the STM hal or led controller side.

    Visitor II
    May 2, 2019

    I think you understand that any one device can access the bus at a time, and with the delay you mention it seems like that might be the issue. Have you looked at using RTOS event flags for synchronization?

    Visitor II
    January 30, 2024

    Several slaves on I2C but with 3V3 and 10K pull-ups?
    Sound too "weak" to me:
    I use 2K2 on 3V3 with just a single device.

    The more slave devices you connect ("capacitors") - the lower you have to go with pull-ups.
    10K and three slaves - even 100Kbps does not seem reliable to me.

    Graduate II
    May 15, 2019
    	/* Create Mutex, if not created */
    	if(osMutexId_I2C1 == NULL)
    	{
    		 osMutexId_I2C1 = osMutexCreate(&osMutex_I2C1);
    	}

    You can't do that form a threads, which lock on that mutex! It creates race condition at start. One solution is to create those mutexes before starting kernel.

    And why do You implement the same functions for each peripheral instance? Implement one set of functions with a corresponding handle parameter.

    Graduate II
    January 26, 2024

    One issue that comes to mind is that you're releasing the mutex right after initiating a DMA transaction. You never wait for the DMA/I2C transaction to complete before allowing the caller to initiate the next DMA transaction. This would be my first suspect in your situation.

    I would solve this problem with a semaphore that gets taken right before the I2C/DMA transaction is initiated and released in the DMA transaction finished callback function.  The reason you need semaphores and not mutexes is that the DMA finished callback is called from the interrupt context, in which case a semaphore must be used to signal the thread that it's free to continue on with allowing the next transaction to proceed.

    Technical Moderator
    April 9, 2024

    Hello @ssath.7

    For a better analysis, could you please provide the following information:

    • The version of the STM32Cube firmware you are using.
    • The values of XferCount and XferSize when the application execution gets stuck.
    • The contents of the ISR, CR1, and CR2 registers when the application execution gets stuck.