cancel
Showing results for 
Search instead for 
Did you mean: 

About I2C communication of STM32C031

shank
Associate III

Hello.
I am trying to implement RFID using NXP's NT3H2211W0FT1. The microcontroller I am using is the STM32C031F6.
After powering on the board, the first thing I do is read the data from the NT3H2211W0FT1 via I2C, but sometimes I can read it and sometimes I can't.
I tried leaving a wait of more than one second after powering it on, but that didn't change the situation.
The program for the I2C part is below.

while(icdata_flg==0){
      HAL_GPIO_WritePin(GPIOA, ANNTENA_SW_Pin,GPIO_PIN_SET);
      HAL_Delay(10);
      tdata[0]=0x01;//Read
      HAL_I2C_Master_Transmit(&hi2c1,0xaa,tdata,1,100);
      HAL_Delay(10);
      HAL_I2C_Master_Receive(&hi2c1,0xab,rdata,8,100);
      HAL_Delay(10);
      HAL_GPIO_WritePin(GPIOA, ANNTENA_SW_Pin,GPIO_PIN_RESET);
}

 I would appreciate any advice you could give me regarding I2C communication.

8 REPLIES 8
TDK
Guru

Ensure HAL_I2C_IsDeviceReady returns HAL_OK before using any other HAL_I2C function.

If a transfer is interrupted, perhaps due to debugging, the slave could be retaining control of the SDA line. In that case you need to cycle SCL 9 times to clear it.

Using a logic analyzer to see behavior of SDA/SCL will provide better insight.

If you feel a post has answered your question, please click "Accept as Solution".
KnarfB
Principal III

According to the data sheet Figure 18 and the text below: 

" WARNING: READ sequence shall be atomic. Complete sequence of above figure needs to be executed,
otherwise that tag may go to undefined state and stretches the clock infinitely."

I would guess you have to read 16 bytes.

It is funny that the data sheets mentions "atomic", but the official NXP  "UM10204 I2C-bus specification and user manual" does not define that term. Here my guess is, that you could better use the HAL_I2C_Mem_Read which uses internally a restart condition and is atomic in a common sense.

As @TDK said, a logic analyzer is incredibly helpful and a $10 entry level USB LA will do fine for I2C. Also check the return value of each HAL function call and/or use the debugger.

Final remarks:

- "sometimes ... I can't" is vague. What happens? Reading garbage, getting stuck, timeout, where?

- using flywire/ prototype setups may degrade I2C waveforms because of higher parasitic line capacities. Try low pull-up R's, slow communication @ 100 kHz, and ideally use a scope to validate the edges. 

hth

KnarfB

Don't ignore error returns.

Examine bus signals with a scope or logic analyzer. 

If slave device is not responding perhaps look into that, and possible reset or recovery methods where there's no async reset pin.

Check if slave starts in wrong mode, or needs pull-ups on specific pins at power-up

Do other slaves on the bus work? Can you clock the slave out of odd modes?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Karl Yamashita
Principal

You need to check for the HAL status for what the possible error could be.

If it returns HAL_ERROR, you'll need to debug and find out which of the 3 functions within HAL_I2C_Master_Transmit that can return an error.

  • I2C_WaitOnFlagUntilTimeout
  • I2C_WaitOnTXISFlagUntilTimeout
  • I2C_WaitOnSTOPFlagUntilTimeout
HAL_StatusTypeDef hal_status;
	
	while(icdata_flg==0){
	      HAL_GPIO_WritePin(GPIOA, ANNTENA_SW_Pin,GPIO_PIN_SET);
	      HAL_Delay(10);
	      tdata[0]=0x01;//Read
	      hal_status = HAL_I2C_Master_Transmit(&hi2c1,0xaa,tdata,1,100);
	      if(hal_status != HAL_OK)
	      {
	    	  if(hal_status == HAL_BUSY)
	    	  {
	    		  printf("I2C HAL BUSY");
	    	  }
	    	  else if(hal_status == HAL_ERROR)
	    	  {
	    		  printf("I2C HAL ERROR");
	    	  }
	    	  break;
	      }
	      hal_status = HAL_I2C_Master_Receive(&hi2c1,0xab,rdata,8,100);
	      if(hal_status != HAL_OK)
		  {
			  if(hal_status == HAL_BUSY)
			  {
				  printf("I2C HAL BUSY");
			  }
			  else if(hal_status == HAL_ERROR)
			  {
				  printf("I2C HAL ERROR");
			  }
			  break;;
		  }
	      HAL_GPIO_WritePin(GPIOA, ANNTENA_SW_Pin,GPIO_PIN_RESET);
	}

If it's just one master and slave, then it's unlikely it'll return HAL_BUSY. But if it does, then you may need to check if the SDA line is held down by the slave. 

 

HAL_I2C_Master_Receive has 3 possible return errors as well.

  • I2C_WaitOnFlagUntilTimeout
  • I2C_WaitOnRXNEFlagUntilTimeout
  • I2C_WaitOnSTOPFlagUntilTimeout

 

Having the correct pull-ups resistors on the I2C bus is also crucial. Hopefully you are not using the internal pull-ups as that won't work reliably.

You should provide diagram of how you've connected the NT3H2211W0FT1 to the STM32 including the pull-up resistors and values.

 

As @TDK mentions, use an logic analyzer or oscilloscope to see what is happening on the I2C bus.

Either of those tools are your best friend.

 

 

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

Thank you everyone for your advice.

Unfortunately, I can't check the waveform using a logic analyzer or oscilloscope because the board is covered in resin.

I mainly used Karl's debugging method as a reference and found that it never entered HAL_BUSY, but entered HAL_ERROR.

・I2C_WaitOnFlagUntilTimeout
・I2C_WaitOnTXISFlagUntilTimeout
・I2C_WaitOnSTOPFlagUntilTimeout

Is there a way to determine which function error it's entered?
I've attached an image of the I2C peripheral wiring.
The cubeMX settings are as follows:
PB6:I2C1_SCL
           GPIO mode:Alternate Function Open Drain
           GPIO Pull-up/Pull-down:No pull-up and no pull-down
           Maximum output speed:Very High
           Fast Mode:Disable

PB7:I2C1_SDA
           GPIO mode:Alternate Function Open Drain
           GPIO Pull-up/Pull-down:No pull-up and no pull-down
           Maximum output speed:Very High
           Fast Mode:Disable

   

Is there a way to determine which function error it's entered?

When you start debugging, set breakpoints in HAL_I2C_Master_Transmit (stm32c0xx_hal_i2c.c) at all 3 "return HAL_ERROR;" locations and watch which one will be hit. But, anyway the timeout error indicates that either the I2C connection failed at the electric level or the slave is in some irresponsive state. 

The external 10k pull-ups in the schematic are relatively weak, smaller values are quite common. If you cannot access those R's, I would definitely slow I2C down to a low comm. speed and activate the internal pull-ups which work in parallel. It is also helpful to apply the "9 cycles reset" @TDK mentioned after reset. As a last resort you may use a I2C bit-banging implementation where you can control the pin timing in software.

All these measure may help bringing-up a few prototypes in the lab. For production quality, get a PCB without resin (or let it remove) and work at the electric level.

hth

KnarfB

Thank you for your reply, Knauf B.

I set breakpoints on all "return HAL_ERROR;" and tried to debug, but a pop-up appeared saying "Breakpoints will be disabled" and I was unable to debug properly.

After listening to everyone's advice, an idea came to my mind. Since I was able to read I2C properly and it worked normally about 90% of the time and couldn't read it properly about 10% of the time, I thought that performing a software reset when HAL_ERROR occurred would be a good solution. By performing "HAL_NVIC_SystemReset();" when HAL_ERROR is returned, the program no longer freezes with HAL_ERROR. Is this solution not very good for programming?

while(icdata_flg==0){
      HAL_GPIO_WritePin(GPIOA, ANNTENA_SW_Pin,GPIO_PIN_SET);
      HAL_Delay(10);
      tdata[0]=0x01;
      hal_status = HAL_I2C_Master_Transmit(&hi2c1,0xaa,tdata,1,100);
      if(hal_status == HAL_ERROR){
        HAL_NVIC_SystemReset();
      }
      HAL_I2C_Master_Receive(&hi2c1,0xab,rdata,8,100);
      HAL_GPIO_WritePin(GPIOA, ANNTENA_SW_Pin,GPIO_PIN_RESET);
}

Are you okay with flaky I2C communication and having your chip reset unpredictably? If so, that solution will work.

If you feel a post has answered your question, please click "Accept as Solution".