cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F091 I2C1 not working but I2C2 works perfectly.

I have a design where I am using both I2C1 (external ADC) and I2C2 (external EEPROM). I have no problem making I2C2 work perfectly. The MCU both transmits and receives messages with no problem and I can see in on the Oscilloscope. However, when I attempt to use I2C1 in the same way, using the same HAL commands:

HAL_I2C_Master_Transmit(&hi2c1, ADCAddrWrite, ADCConfigCond, 0x01, 1000);

and

HAL_I2C_Master_Receive(&hi2c1, ADCAddrRead, (uint8_t *)aRxBuffer, 0x02, 1000);

It does not work. On the oscilloscope I can see the clock signal go low briefly and then go high again every time the MCU attempts to either send or receive a message. I think the MCU is issuing the Start bit but then it times out. When I use the debugger and follow the code through step by step I see that the bus is timing out (or at least I think it is). If I elongate the timeout to 10 seconds I can even count it off and see that the MCU pauses at the command for 10 seconds and then moves on. If it was a bad ADC chip I would expect the Transmit to work perfectly but the receive command to timeout and not work, but that's not what's happening.

For the record I used STMCubeMX to generate my code (other than the application specific code I've added since) and I have my HAL libraries up to date. I know in the past the HAL libraries for I2C weren't great but it seems like things have changed/improved some since.

Is there something special about I2C1 vs. the other I2C buses that maybe I am not handling properly? I know it's clocked differently, but I have checked the clock initialization code and that seems to be correct. I've even switched it to run from the HSI and that didn't help. Here is the relevant code:

Initialization Code:

static void MX_I2C1_Init(void)

{

 /* USER CODE BEGIN I2C1_Init 0 */

 /* USER CODE END I2C1_Init 0 */

 /* USER CODE BEGIN I2C1_Init 1 */

 /* USER CODE END I2C1_Init 1 */

 hi2c1.Instance = I2C1;

 hi2c1.Init.Timing = 0x20303E5D;

//  hi2c1.Init.Timing = 0x2000090D;

 hi2c1.Init.OwnAddress1 = 0;

 hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

 hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

 hi2c1.Init.OwnAddress2 = 0;

 hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;

 hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;

 hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

 if (HAL_I2C_Init(&hi2c1) != HAL_OK)

 {

  Error_Handler();

 }

 /**Configure Analogue filter

 */

 if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)

 {

  Error_Handler();

 }

 /**Configure Digital filter

 */

 if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN I2C1_Init 2 */

 /* USER CODE END I2C1_Init 2 */

}

Pin Initialization code:

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if(hi2c->Instance==I2C1)

 {

 /* USER CODE BEGIN I2C1_MspInit 0 */

 /* USER CODE END I2C1_MspInit 0 */

  __HAL_RCC_GPIOB_CLK_ENABLE();

  /**I2C1 GPIO Configuration  

  PB6   ------> I2C1_SCL

  PB7   ------> I2C1_SDA

  */

  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* Peripheral clock enable */

  __HAL_RCC_I2C1_CLK_ENABLE();

 /* USER CODE BEGIN I2C1_MspInit 1 */

 /* USER CODE END I2C1_MspInit 1 */

 }

 else if(hi2c->Instance==I2C2)

 {

 /* USER CODE BEGIN I2C2_MspInit 0 */

 /* USER CODE END I2C2_MspInit 0 */

 __HAL_RCC_GPIOB_CLK_ENABLE();

  /**I2C2 GPIO Configuration  

  PB13   ------> I2C2_SCL

  PB14   ------> I2C2_SDA

  */

  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF5_I2C2;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* Peripheral clock enable */

  __HAL_RCC_I2C2_CLK_ENABLE();

 /* USER CODE BEGIN I2C2_MspInit 1 */

 /* USER CODE END I2C2_MspInit 1 */

 }

}

I2C Transmit and Receive Commands:

HAL_I2C_Master_Transmit(&hi2c1, ADCAddrWrite, ADCConfigCond, 0x01, 1000);

HAL_Delay(100);

 HAL_I2C_Master_Receive(&hi2c1, ADCAddrRead, (uint8_t *)aRxBuffer, 0x02, 1000);

 HAL_Delay(100);

1 ACCEPTED SOLUTION

Accepted Solutions

I think the problem was hardware related. Going off the idea that the SDA line was being pulled low by something I went ahead and took the Nuclear option and brought up a new piece of hardware (I had three manufactured originally) and without any changes to the code the ADC is now communicating with the MCU without a problem. Either the original hardware was damaged during previous tests or there was a manufacturing defect. This could also be why the problem seemed to be intermittant until it completely died yesterday.

View solution in original post

7 REPLIES 7

> On the oscilloscope I can see the clock signal go low briefly

And SDA? You should observe START on both lines.

JW

PS How is I2C1 clock set in RCC?

The SDA signal remains low throughout, no change.

System Clock Code:

void SystemClock_Config(void)

{

 RCC_OscInitTypeDef RCC_OscInitStruct = {0};

 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

 /**Initializes the CPU, AHB and APB busses clocks

 */

 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

 RCC_OscInitStruct.HSEState = RCC_HSE_ON;

 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;

 RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;

 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

 {

   Error_Handler();

 }

 /**Initializes the CPU, AHB and APB busses clocks

 */

 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                             |RCC_CLOCKTYPE_PCLK1;

 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)

 {

   Error_Handler();

 }

 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3|RCC_PERIPHCLK_USART1

                             |RCC_PERIPHCLK_I2C1;

 PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;

 PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1;

 PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;

//   PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;

 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)

 {

   Error_Handler();

 }

}

Also, I do have Pullup Resistors on both the SCL and SDA pins. Since SDA remains low either the ADC or the MCU must be driving it low.

> either the ADC or the MCU must be driving it low.

What board is this? Can't there be anything else connected?

Checking MCU is easy - just turn given pin to input, directly in respective GPIO_MODER register in the debugger.

JW

PS. I don't use Cube. When investigating functionality, it's better to read out content of relevant registers rather than rely on any code written or generated.

This is a custom PCB, not a Nucleo board.

I tried changing the GPIO_MODER register for GPIOB7 to input and that didn't change anything...SDA is still low.

One thing I forgot to mention is that the ADC runs on 5V due to the fact that the analog circuitry runs at 5V. Thus, the ADC is interfaced to the MCU through a TI LSF0102DQER level shifter. The datasheet says it is auto-bidirectional and that it is designed to work with I2C so I don't think this is should be causing a problem, but I wanted to throw it out there.

Okay so now it's not the STM32, and it's up to you to find the problem.

Using voltmeter (isolated) on milivolt range, measuring from the pullup's lower end to various nodes should show you where the current flows.

JW

I think the problem was hardware related. Going off the idea that the SDA line was being pulled low by something I went ahead and took the Nuclear option and brought up a new piece of hardware (I had three manufactured originally) and without any changes to the code the ADC is now communicating with the MCU without a problem. Either the original hardware was damaged during previous tests or there was a manufacturing defect. This could also be why the problem seemed to be intermittant until it completely died yesterday.