cancel
Showing results for 
Search instead for 
Did you mean: 

F411 I2C LL Call Hangs

HDaji.1
Senior

I am using F411 to communicate with ADXL355 through I2C1.

I have a very strange issue:

  LL_I2C_GenerateStartCondition(I2C1);
	
  /* (1.3) Loop until Start Bit transmitted (SB flag raised) ********************/
  /* Loop until SB flag is raised  */
  while(!LL_I2C_IsActiveFlag_SB(I2C1)) { }
 
  /* (2.1) Send a 7-Bit SLAVE ADDRESS for a write request because my next step
	       is also write (putting register address on SDA line). 	 */
  LL_I2C_TransmitData8(I2C1, (dev_Addr << 1) | I2C_REQUEST_WRITE);
	
  /* (2.2) Loop until ADDR flag is raised, i.e. address is fully sent  */
  while(!LL_I2C_IsActiveFlag_ADDR(I2C1)) { }

Sometimes the above code hangs at step 2.2 when I change other part of the firmware, which is totally unrelated to this one.

FYI I made my own PCB and run this code on it.

Can anybody give any advice or hint on why it happens?

3 REPLIES 3
Imen.D
ST Employee

Hello @HDaji.1​ ,

Adding LL_I2C_ClearFlag_ADDR(I2C1);​ after line 12.

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

Hello @Imen DAHMEN​ 

Thank you for your advice. I have that LL_I2C_ClearFlag_ADDR after line 12. The issue is that it hangs at line 12, before reaching Clear Flag ADDR.

Here is the whole function:

void I2C_Read_1Byte(uint8_t dev_Addr, uint8_t reg_Addr, uint8_t *buffer) {
  /* First Round, MCU transmits only so no need to Prepare ACK ******************/
  //LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);
  
  /* (1.1) Initiate a Start condition to the Slave device ***********************/
  /* Master Generate Start condition */
  LL_I2C_GenerateStartCondition(I2C1);
	
  /* (1.3) Loop until Start Bit transmitted (SB flag raised) ********************/
  /* Loop until SB flag is raised  */
  while(!LL_I2C_IsActiveFlag_SB(I2C1)) { }
 
  /* (2.1) Send a 7-Bit SLAVE ADDRESS for a write request because my next step
	       is also write (putting register address on SDA line). 	 */
  LL_I2C_TransmitData8(I2C1, (dev_Addr << 1) | I2C_REQUEST_WRITE);
	
  /* (2.2) Loop until ADDR flag is raised, i.e. address is fully sent  */
  while(!LL_I2C_IsActiveFlag_ADDR(I2C1)) { }
	
	/* (2.3) Clear ACK.*/
	/* There is no Clear ACK function?? */
  /* (2.4) Clear ADDR flag value in ISR register */
  LL_I2C_ClearFlag_ADDR(I2C1);
	
  /* (3.1) Send data (for ADXL355, it is register address) on SDA line. */
  LL_I2C_TransmitData8(I2C1, reg_Addr);
	
  /* (3.2) Loop until Transmit data register empty flag is raised, i.e. 
	         data fully sent LL_I2C_IsActiveFlag_TXE(I2C1) == 1  */
  while(!LL_I2C_IsActiveFlag_TXE(I2C1)) { }
	
	/* (3.3) Clear ACK*/
	/* There is no Clear ACK function?? */
		
	/* According to data sheet, we need to send ReStart */
  /* (4.1) Since to receive ONE byte, we need to prepare NACK */
  LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK);
  
  /* (4.2) Initiate a Start condition to the Slave device ***********************/
  /* Master Generate Start condition */
  LL_I2C_GenerateStartCondition(I2C1);
	
  /* (4.3) Loop until Start Bit transmitted (SB flag raised) ********************/
  /* Loop until SB flag is raised  */
  while(!LL_I2C_IsActiveFlag_SB(I2C1)) { }
 
  /* (5.1) Send a 7-Bit SLAVE ADDRESS for a write request because my next step
	       is also write (putting register address on SDA line). */
  LL_I2C_TransmitData8(I2C1, (dev_Addr << 1) | I2C_REQUEST_READ);
	
  /* (5.2) Loop until ADDR flag is raised, i.e. address is fully sent  */
  while(!LL_I2C_IsActiveFlag_ADDR(I2C1)) { }
	
	/* (5.3) Clear ACK.*/
	/* There is no Clear ACK function?? */
	
  /* (5.4) Clear ADDR flag value in ISR register */
  LL_I2C_ClearFlag_ADDR(I2C1);
	
  /* (6.1) Loop until RXNE flag is raised  */
  while(!LL_I2C_IsActiveFlag_RXNE(I2C1)) { }
	
  /* Read character in Receive Data register.
     RXNE flag is cleared by reading data in RXDR register */
	*buffer = LL_I2C_ReceiveData8(I2C1);
	
  /* (7) End of tranfer, Data consistency are checking into Slave process *****/
  /* Generate Stop condition */
  LL_I2C_GenerateStopCondition(I2C1);
}

The above function reads one byte from a certain register in ADXL355, which is based on one of the I2C LL sample (polling) code in STM32Cube_FW_F4_V1.26.0.

I read somewhere that interrupt or DMA is recommended/supported instead of polling for I2C communication. I am going to re-write the above code with interrupt method and will post any issues or questions in this thread. I have been working with LL APIs for UART, SPI, and I2C for months, and found the I2C is very complicated to understand and implement.

Hi @Imen DAHMEN​ 

I have coded I2C1_EV_IRQHandler, but cannot get correct result.

Do you have any advice on how to debug it?

Setting breakpoint in the middle of IRQ handler is not a good way, is it? It will break the I2C protocol.