cancel
Showing results for 
Search instead for 
Did you mean: 

I2C Slave - clock stretching disables communication and other problems (STM32L0)

TDJ
Senior III

I try to implement I2C slave so it behaves like a typical EPROM and master can read/write using HAL_I2C_Mem_Read/HAL_I2C_Mem_Write functions.

After 3 days of searching and trying I found only one, partially working example: STM32F072 I2C slave Receive callback

Problems:

  1. Communication seems to work only when clock stretching is disabled (Clock No Stretch Mode = Enable/I2C_NOSTRETCH_ENABLE). Enabling clock stretching causes slave to pull SCL line down indefinitely once it receives its address.
  2. Description of I2C_XFEROPTIONS (I2C_FIRST_FRAME, I2C_NEXT_FRAME, I2C_LAST_FRAME) found in UM1940 is completely cryptic and no description in HAL source code is found.
  3. I am able to receive data but not to send. I receive odd address, call HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &_dataBuffer[_offset], 1, I2C_NEXT_FRAME) and that results in HAL_I2C_ERROR_OVR error.

I read many posts discouraging use of HAL functions for slave implementation but I hoped the functionality has been improved recent years and maybe now it is usable.

I use the latest STM32Cube_FW_L0_V1.12.1, functions calls in interrupt mode (*_IT) and STM32L041.

I am familiar with the I2C_TwoBoards_RestartAdvComIT example. It does provide some insight but it does not address the above two problems. This example is provided for Nucleo-L073RZ only, which may or may not indicate that tests with other L0 Nucleos were not successful. Moreover, HAL_I2C_EnableListen_IT() is called in the loop which indicates author(s) of this example could not find a better yet reliable solution.

Please advise.

16 REPLIES 16
KnarfB
Principal III

Once I did some example code: https://gitlab.com/stm32mcu/i2c_master_and_servant. It does not handle clock-stretching but memory type read and write worked fine.

hth

KnarfB

TDJ
Senior III

I have tested your example using popular Bus Pirate interface and the following commands:

[0x60 0x00 0x00 0x01 0x02 0x03 0x04 0x05]

[0x60 0x00 [0x61 r:6]

The first command writes 6 bytes to slave at address 0x60, starting from register 0x00. The second one attempts to read the previously written 6 bytes.

It could be that either your code or HAL has some glitches since only one (1st) byte gets returned, HAL_I2C_SlaveTxCpltCallback does not get called and HAL_I2C_ErrorCallback executes three times with error HAL_I2C_ERROR_OVR but at least it transfers this one byte! I have tested it with STM32F303K8T and STM32H7A3VI.

However, it does NOT work with STM32L041G6UxS. I can write (receive) but not read (transfer) at all. I suspect HAL bugs.

Moreover, you example only works with clock stretching disabled, which is consistent with my tests and probably indicates more HAL problem.

Imen.D
ST Employee

Hello @TJast​ ,

You can review the STM32L0 errata sheet related to your devices to check the known I2C peripheral limitations and if you have the same condition (If clock stretching is enabled).

0693W00000D2itQQAR.jpg 

When your question is answered, please close this topic by choosing Select as Best. This will help other users find that answer faster.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
TDJ
Senior III

@Imen DAHMEN​ Thank you for the hint but in my case processor does not enter Stop mode. It must be something else.

I think first I need to make sure timings are correct - see my other post: Possible CubeMX I2C timing config bug (STM32L0x and other)

TDJ
Senior III

@Imen DAHMEN​ As far as I can tell, besides incorrect CubeMX-generated timing, the problem is that during HAL "slave operations" (HAL_I2C_Slave** functions) transfer options (XferOptions) are not used at all. They are passed but not used. All "master operations" (HAL_I2C_Master** functions) use I2C_TransferConfig() function for that purpose but no similar concept/approach is found in "slave" functions. It seems XferOptions are just ignored - that is, not being applied to the I2C_CR2 register.

If I am correct, HAL I2C Slave functions have serious bugs which render them unusable. Other posts on this topic I came across seem to confirm that.

@KnarfB​ I think you managed to get it working because Nucleo-STM32F401RE you used for for tests has much different and simpler I2C interface than the newer MCUs.

Hi @TJast​ ,

Thanks for this details, I will raise your issue to CubeMx team.

Hello @Houda GHABRI​ ,

It seems this post is related to the CubeMX issue - see this post: Possible CubeMX I2C timing config bug (STM32L0x and other).

Can you please review and confirm this issue with CubeMx?

Thanks

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

I have done detailed I2C timing analysis in Excel based on available specs. I can email it.

However, it seems that this is not only CubeMX incorrect timing config problem. I am showing that HAL_I2C_Mem_Read() function execution can prevent SysTick_Handler() from firing. Consequently, HAL_I2C_Mem_Read() timeout never occurs because program execution goes into infinite loop since SysTick value does not increment. Tested with NUCLE0-F303K8. Yes, HAL_I2C_Mem_Read() is called from interrupt handler but this interrupt has lower priority than SysTick with PreemptPriority=0 (highest).

I begin to understand why some folks recommend using LL-HAL only and/or using HAL just for initial config but not for production grade systems.

Just to inform you how "competent" the HAL/CubeMX developers are...

https://community.st.com/s/question/0D50X0000BOtfhnSQB/how-to-make-ethernet-and-lwip-working-on-stm32