cancel
Showing results for 
Search instead for 
Did you mean: 

Why does i2c require a reset to work when power is turned on?

CDyer.1
Senior

Hi, I'm having lots of trouble with the i2c peripheral on STM32 using HAL and this is question 1 of a number of questions I have. Bit of background: I have a custom board with a F411RE and a F446RE. I want to communicate between them using i2c. The board layout is fine, pins are connected correctly and i2c line is held high with 4k7 resistors. The F411RE is the master and the F446RE is the slave. I have two dummy programs to just get the i2c prototcol working as expected. I am using HAL. Firstly, if I have both devices just polling the i2c peripheral using:

HAL_I2C_Slave_Receive()

and

HAL_I2C_Master_Transmit()

then everything seems to work flawlessly. However, I need to use an interrupt based system for my proper code (i.e. not the dummy code) and using interrupts is where I'm findings lots of problems. So the first issue I have is when slave is set to polling mode and master is set to transmit in interrupt mode. When debugging the slave, I noticed that the data wouldn't get sent unless the master was reset after a power cycle. Hooking a scope up to the i2c line, I see that on a power cycle, the line is just held high. If i reset the master (pulldown on the rst pin) everything works as expected and a transfer occurs.

Code on master f411:

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
  i2c_data_tx.b[0] = 201;
  i2c_data_tx.b[1] = 1;
  while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
 {
 
 }
if(HAL_I2C_IsDeviceReady(&hi2c1, 42, 100, HAL_MAX_DELAY) == HAL_OK)
{
  HAL_I2C_Master_Transmit_DMA(&hi2c1, 42, i2c_data_tx.b, sizeof(i2c_data_tx));
 }
  while (1)
  {
	  HAL_Delay(200);
	  if (HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_READY)
	  {
			  if(HAL_I2C_IsDeviceReady(&hi2c1, 42, 100, HAL_MAX_DELAY) == HAL_OK)
			  {
				  if(i2c_int_flag)
				  {
				  i2c_int_flag = 0;
				  HAL_I2C_Master_Transmit_DMA(&hi2c1, 42, i2c_data_tx.b, sizeof(i2c_data_tx));
				  }
			  }
	  }
 
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
 
	i2c_data_tx.b[1] += 1;
	i2c_int_flag = 1;
 // HAL_I2C_Master_Transmit_DMA(&hi2c1, 42, i2c_data_tx.b, sizeof(i2c_data_tx));
 
}

In cubeMX, interrupts for i2c and dma are enabled. They all have different sub priorities to avoid a clash. I don't want the code to attempt anything until the master i2c peripheral is ready. Once it becomes avaialble, it checks to see if the slave is ready and if so, starts the transfer routine through DMA. Once the transfer has completed, the master waits 200ms and then starts the process over again.

Obviously I can't debug this because the debugger will reset the device and then everything will work fine.

This is measured on the i2c line after a power cycle and stays this way permanently:

0693W00000Nr0jTQAR.png And here is after a reset, you can see that the master is attempting to communicate with the slave every 200ms (it is unsuccessful but that's for another question):

0693W00000Nr0k2QAB.png Any help or ideas would be appreciated - I've found the i2c to be by far the most diffcult peripheral to work with on the stm32f4 so far!

1 REPLY 1

Maybe you I2C peripheral(s) is/are not powering-up cleanly?

It is in the nature of I2C that there's potential for lock-up.

The I2C specification gives a process for clearing the bus:

0693W00000Nr21dQAB.png 

"I've found the i2c to be by far the most diffcult peripheral to work with on the stm32f4 so far!"

I think that's generally the case with most microcontrollers!

BTW: please use the screen capture feature of your scope - it'll give a much cleaner picture than a photograph.