Skip to main content
Graduate II
October 3, 2022
Question

F411 I2C LL Call Hangs

  • October 3, 2022
  • 1 reply
  • 1398 views

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?

    This topic has been closed for replies.

    1 reply

    Technical Moderator
    October 3, 2022

    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

    HDaji.1Author
    Graduate II
    October 4, 2022

    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.