Showing results for 
Search instead for 
Did you mean: 

STM32F413 I2C. ACK from slave is not recognized.

Associate II

Hello everybody,

I am having an issue when I try to establish a communication with the NFC chip M24SR64 via I2C. After I have sent the address (0xAC), the flag AF is set, indicating that the ACK of the slave was not read. However, I can see the ACK from the slave in the Oscilloscope, i.e., during the 9th SCL pulse the SDA line is in low (see attached picture). Then, in the error handler subroutine for the AF case, a STOP condition is generated. I repeat the process many times but always the AF flag is set.

I am pretty sure my I2C settings are right (PF0 and PF1 as open drain outputs, high speed, alternative function, etc). In fact, the I2C driver works flawlessly in the STM32F446. I compared the two reference manuals and there is no difference in the I2C modules of the controllers.

The pull-up resistors value remained the same (3K) . I also attached my initialization code.

Thanks for your help.0690X000006C2gFQAS.jpg

 // Set I2C eState Busy
  NFCL_tIICHandle.eState = I2C_STATE_BUSY;
  // Disable the selected I2C peripheral
  I2C_NFC->CR1 &= ~I2C_CR1_PE;       // 0:  PE: = 0:    Peripheral disable
  I2C_NFC->CR1 |= I2C_CR1_SWRST;
  I2C_NFC->CR1 &= ~I2C_CR1_SWRST;
  // Get PCLK1 frequency
  u32Pclk1 = (UINT32)(RCC_SYS_CLK >> i2c_au8APBAHBPrescTable[u32Presc]);       // PRQA S 3393 //RCC_SYS_CLK causes the warning!
  // Calculate frequency range
  u32FreqRange = I2C_FREQRANGE(u32Pclk1);
  // Configure I2C2: Frequency range
  I2C_NFC->CR2 = u32FreqRange;       // PCLK1 = 50 MHz
  // Configure I2C2: Rise Time
  I2C_NFC->TRISE = I2C_TIME_RISE;      // TRISE = 0x10
  // Configure I2C2: Speed I2C clock control
  I2C_NFC->CCR = 0x2A           // 0-11: CCR     = 0x2A (42):  Clock Control Register (2500ns / (3 * 20ns) = 42)
                       // 14:  DUTY    = 0:      Fast Mode Duty Cycle
        | I2C_CCR_FS;         // 15:  FS     = 1:      Master mode selection
  // Configure I2C2: Generalcall and NoStretch mode
  I2C_NFC->CR1 = I2C_GENERALCALL_DISABLE  // 0:  PE:     = 0: General call disabled. Address 00h is NACKed.
                       // 1:  SMBUS:   = 0: I2C mode
                       // 2:  Reserved, must be kept at reset value
                       // 3:  SMBTYPE:  = 0:
                       // 4:  ENARP:   = 0: ARP disable
                       // 5:  ENPEC:   = 0: PEC calculation disabled
                       // 6:  ENGC:    = 0: General call disabled. Address 00h is NACKed.
        | I2C_NOSTRETCH_DISABLE   // 7:  NOSTRETCH: = 0: Clock stretching enabled
                       // 8:  START:   = 0: In Master Mode: 0: No Start generation
                       // 9:  STOP:    = 0: In Master Mode: 0: No Stop generation.
  | 0;              // 10:  ACK:    = 0: No acknowledge returned
                       // 11:  POS:    = 0: ACK bit controls the (N)ACK of the current byte being received in the shift register.
                       // 12:  PEC:    = 0: No PEC transfer
                       // 13:  ALERT:   = 0: SMBus alert, Releases SMBA pin high
                       // 14:  Reserved, must be kept at reset value
                       // 15:  SWRST:   = 0: I2C Peripheral not under reset
  // Configure I2C2: Own Address1 and addressing mode
  I2C_NFC->OAR1 = 0;            // 0:  ADD0:    = 0: Interface address. 7-bit addressing mode: don’t care
                       // 1-7: ADD[7:1]:  = 0: Interface address.
                       // 8-9: ADD[9:8]:  = 0: Interface address. 7-bit addressing mode: don’t care
                       // 10:13:Reserved, must be kept at reset value
                       // 14:  Should always be kept at 1 by software.
                       // 15:  ADDMODE:  = 0: 7-bit slave address (10-bit address not acknowledged)
  // Configure I2C2x: Dual mode and Own Address2
  I2C_NFC->OAR2 = I2C_DUALADDRESS_DISABLE; // 0:  ENDUAL:   = 0: Dual addressing mode enable
                       // 1-7: ADD2[7:1]: = FE: Interface address in dual addressing mode
                       // 8:15: Reserved, must be kept at reset value
  //I2C_NFC->CR1 |= I2C_CR1_ACK;
  //TODO CN: add delay if needed
  // Enable the I2C2 peripheral
  I2C_NFC->CR1 |= I2C_CR1_PE;        // 0:  PE:     = 1: Peripheral enable
  // Set I2C u32Error None
  NFCL_tIICHandle.u32ErrorCode    = I2C_ERROR_NONE;
  // Set I2C eState Ready
  NFCL_tIICHandle.eState       = I2C_STATE_READY;
  // Set I2C u32PreviousState None
  NFCL_tIICHandle.u32PreviousState  = I2C_STATE_NONE;


I think it is not recognized as ACK, because it is no ACK.

The slave is supposed to pull SDA low while SCL is high.

What you see is IMHO the master switching back the direction of the SDA line.

SDA is output for the 8 data bits, and input for the ACK bits.

Associate II

I though it would be enough for representing an ACK that SDA remains in low while SCL is high, during the 9th SCL pulse. Actually, I changed once the address for checking the slave response and the SDA line was kept high at the 9th SCL pulse, which means that the chip rejected the wrong address.


For the ACK pulse, the master switches SDA from output to input before clocking the pulse out.

The pull-up resistors will keep SDA high, resulting in "NO ACK" if the slave does not actively pull it down.

When the ACK pulse is done, he switches back.

Associate II

I saw as well the signals using the STM32446 and the SDA line remained constant in the low level during the 9th pulse (before it too since the last bit of the address is 0). With this controller, the I2C communication works without any issue as I mentioned above. It seems to me really strange since there is absolutely no difference between the I2C modules of the two controllers. Perhaps it is worth to mention that I needed to reset the CR1 after disabling the module because the BUSY flag was stuck at 1. This workaround was not necessary using the 446 controller. Perhaps there is an additional workaround for this issue with the AF flag. Unfortunately this is not mentioned in any erratasheet. Or maybe is it necessary to adapt the value of the pull-up resistors.