AnsweredAssumed Answered

STM32F10xxx - I2C master receiving 2 bytes - NACK after first read byte

Question asked by Bascetta.Marco on Nov 9, 2015
Latest reply on Nov 11, 2015 by Bascetta.Marco
Hello,
I'm trying to write an I2C application that should read/write one or more bytes as master with polling mode.
I'm able to write one ore more bytes and read one byte, but when I try to read 2 bytes after a single byte read the first call goes wrong; next 2 bytes read works!

I'm try to explain better:
       
  • Perform a read of a byte.   
             
    •  Start bit -> Send address 7bit (W) -> (receive ACK) -> Write register (1byte) -> (receive ACK) -> Stop
    •        
    •  Start bit -> Send address 7bit (R) -> (receive ACK) -> (Read value (1byte)) -> send NACK -> Stop
    •    
       
  •    
  • Perform a read of two bytes. (This FAIL)   
             
    • Start bit -> Send address 7bit (W) -> (receive ACK) -> Write register (1byte) -> (receive ACK) -> Stop
    •        
    • Start bit -> Send address 7bit (R) -> (receive ACK) -> (Read value (1byte)) -> send NACK (WRONG) -> (Read value (1byte) => WRONG) -> send NACK -> Stop
    •    
       
  •    
  • Perform a read of two bytes. (Same request now works)   
             
    • Start bit -> Send address 7bit (W) -> (receive ACK) -> Write register (1byte) -> (receive ACK) -> Stop
    •        
    • Start bit -> Send address 7bit (R) -> (receive ACK) -> (Read value (1byte)) -> send ACK (OK) -> (Read value (1byte)) -> send NACK -> Stop
    •    
       
In order to write my code I use RM0008, AN2824, and I2CRoutines.c example retrieved from STM32F10x_AN2824_FW_V4.0.0 package.

In those documents and in FAQ #87 ( https://my.st.com/public/Faq/Lists/faqlst/DispForm.aspx?ID=87 ) the 2 bytes read sequence has little differences.

In RM0008 like in AN2824, Page 6:
       
  • Send START
  •    
  • Send ADDR
  •    
  • Set POS and ACK
  •    
  • Wait ADDR flag
  •    
  • Clear ADDR and ACK
  •    
  • Wait BTF flag
  •    
  • Program STOP
  •    
  • Read DR twice
In AN2824, Page 8, Figure 2:
       
  • Send START
  •    
  • Send ADDR
  •    
  • Wait ADDR flag
  •    
  • Set POS
  •    
  • Disable interrupts
  •    
  • Clear ADDR and ACK
  •    
  • Enable interrupts
  •    
  • Wait BTF flag
  •    
  • Disable interrupts
  •    
  • Program STOP
  •    
  • Read DR (byte 1)
  •    
  • Enable interrupts
  •    
  • Read DR (byte 2)
  •    
  • Wait STOP flag is cleared
  •    
  • Reset POS
  •    
  • Set ACK

My code for two bytes read could be synthesized as:
01.I2Cx->CR2 |= I2C_IT_ERR;
02. 
03.I2C_GenerateSTART(I2Cx, ENABLE);
04.WAIT_FOR_CONDITION_OR_RESET_ON_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_SB) == SET);
05. 
06.I2C_Send7bitAddress(I2Cx, (uint8_t)(i2c_addr << 1), dir);
07.WAIT_FOR_CONDITION_OR_RESET_ON_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR) == SET);
08. 
09./* Clear ACK bit */
10.I2C_AcknowledgeConfig(I2Cx, DISABLE);
11./* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3
12.software sequence must complete before the current byte end of transfer */
13.__disable_irq();
14./* Clear ADDR flag */
15.CLEAR_REGISTER(I2Cx->SR1);  //TODO:BASCETTA:TEST: Aggiunto da me
16.CLEAR_REGISTER(I2Cx->SR2);
17./* Program the STOP */
18.I2C_GenerateSTOP(I2Cx, ENABLE);
19./* Re-enable IRQs */
20.__enable_irq();
21. 
22. 
23.WAIT_FOR_CONDITION_OR_TIMEOUT(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF) == SET);
24. 
25./* Disable IRQs around STOP programming and data reading because of the limitation ?*/
26.__disable_irq();
27./* Program the STOP */
28.I2C_GenerateSTOP(I2Cx, ENABLE);
29./* Read first data */
30.bytes[i] = I2C_ReceiveData(I2Cx);
31.i++;
32./* Re-enable IRQs */
33.__enable_irq();
34. 
35./* Read second data */
36.bytes[i] = I2C_ReceiveData(I2Cx);
37.i++;
38. 
39./* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
40.//WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP);
41.WAIT_FOR_CONDITION_OR_TIMEOUT((I2Cx->CR1 & I2C_CR1_STOP) == 0);
42./* Enable Acknowledgement to be ready for another reception */
43.I2C_AcknowledgeConfig(I2Cx, ENABLE);
44./* Clear POS bit */
45.I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
    
Could you help me to find my mistake??

Thank you for your replies,

Regards

Outcomes