cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L0 I2C Slave, hotplug Issue

Artur1
Associate II

Hello,

I'm working on a product where we will use the STM32L71 device containing an I2C Interface for servicing and control. I develop first parts of the firmware on a STM32L53 nucleo board. Since the device must be hot-pluggable, it is not allowed to influence the I2C bus, by pulling the SCL or SDA lines to ground while power-on. In general no problem for STM32L0, because of open drain I2C. But I've seen it happens while the initialization of IO used for I2C and it's unfortunately not acceptable for our product. 

I've found a way to fix it. Dropping the lines (for 2.75µs) to ground was caused while "LL_GPIO_SetPinMode" function which was called while LL_GPIO_Init for I2C. I could fix this by placing the LL_GPIO_SetPinMode after the "LL_GPIO_SetAFPin_8_15".

Now it seems to work.

There is the complete change of LL_GPIO_Init function (stm32l0xx_ll_gpio.h generated by Cube MX V4.25.1)

Before fix (line 25):

ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
  uint32_t pinpos     = 0x00000000U;
  uint32_t currentpin = 0x00000000U;
 
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
  assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin));
  assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode));
  assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull));
 
  /* ------------------------- Configure the port pins ---------------- */
  /* Initialize  pinpos on first pin set */
  /* pinpos = 0; useless as already done in default initialization */
 
  /* Configure the port pins */
  while (((GPIO_InitStruct->Pin) >> pinpos) != 0x00000000U)
  {
    /* Get current io position */
    currentpin = (GPIO_InitStruct->Pin) & (0x00000001U << pinpos);
 
    if (currentpin)
    {
      /* Pin Mode configuration */
      LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode);
 
      if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
      {
        /* Check Speed mode parameters */
        assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed));
 
        /* Speed mode configuration */
        LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed);
      }
 
      /* Pull-up Pull down resistor configuration*/
      LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull);
 
      if (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE)
      {
        /* Check Alternate parameter */
        assert_param(IS_LL_GPIO_ALTERNATE(GPIO_InitStruct->Alternate));
 
        /* Speed mode configuration */
        if (currentpin < LL_GPIO_PIN_8)
        {
          LL_GPIO_SetAFPin_0_7(GPIOx, currentpin, GPIO_InitStruct->Alternate);
        }
        else
        {
          LL_GPIO_SetAFPin_8_15(GPIOx, currentpin, GPIO_InitStruct->Alternate);
        }
      }
    }
    pinpos++;
  }

After fix (line 52):

ErrorStatus LL_GPIO_Init(GPIO_TypeDef *GPIOx, LL_GPIO_InitTypeDef *GPIO_InitStruct)
{
  uint32_t pinpos     = 0x00000000U;
  uint32_t currentpin = 0x00000000U;
 
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
  assert_param(IS_LL_GPIO_PIN(GPIO_InitStruct->Pin));
  assert_param(IS_LL_GPIO_MODE(GPIO_InitStruct->Mode));
  assert_param(IS_LL_GPIO_PULL(GPIO_InitStruct->Pull));
 
  /* ------------------------- Configure the port pins ---------------- */
  /* Initialize  pinpos on first pin set */
  /* pinpos = 0; useless as already done in default initialization */
 
  /* Configure the port pins */
  while (((GPIO_InitStruct->Pin) >> pinpos) != 0x00000000U)
  {
    /* Get current io position */
    currentpin = (GPIO_InitStruct->Pin) & (0x00000001U << pinpos);
 
    if (currentpin)
    {
      if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
      {
        /* Check Speed mode parameters */
        assert_param(IS_LL_GPIO_SPEED(GPIO_InitStruct->Speed));
 
        /* Speed mode configuration */
        LL_GPIO_SetPinSpeed(GPIOx, currentpin, GPIO_InitStruct->Speed);
      }
 
      /* Pull-up Pull down resistor configuration*/
      LL_GPIO_SetPinPull(GPIOx, currentpin, GPIO_InitStruct->Pull);
 
      if (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE)
      {
        /* Check Alternate parameter */
        assert_param(IS_LL_GPIO_ALTERNATE(GPIO_InitStruct->Alternate));
 
        /* Speed mode configuration */
        if (currentpin < LL_GPIO_PIN_8)
        {
          LL_GPIO_SetAFPin_0_7(GPIOx, currentpin, GPIO_InitStruct->Alternate);
        }
        else
        {
          LL_GPIO_SetAFPin_8_15(GPIOx, currentpin, GPIO_InitStruct->Alternate);
        }
      }
      /* Pin Mode configuration */
      LL_GPIO_SetPinMode(GPIOx, currentpin, GPIO_InitStruct->Mode);
    }
    pinpos++;
  }
 
  if ((GPIO_InitStruct->Mode == LL_GPIO_MODE_OUTPUT) || (GPIO_InitStruct->Mode == LL_GPIO_MODE_ALTERNATE))
  {
    /* Check Output mode parameters */
    assert_param(IS_LL_GPIO_OUTPUT_TYPE(GPIO_InitStruct->OutputType));
 
    /* Output mode configuration*/
    LL_GPIO_SetPinOutputType(GPIOx, GPIO_InitStruct->Pin, GPIO_InitStruct->OutputType);
 
  }
  return (SUCCESS);
}

Could you confirm please if it's OK? I mean could this fix have some negative influence to other IO initialization routines while I2C seems to work proper now?

Best Regards

3 REPLIES 3
AvaTar
Lead

The I2C bus was never designed for hot-plugging, and does not support it.

Pull-up resistors are necessary for proper function (bidirectional operation) and idle state.

> ... while I2C seems to work proper now?

It seems so, now. Expect trouble with unresponsive slaves.

Artur1
Associate II

Hi AvaTar,

>The I2C bus was never designed for hot-plugging, and does not support it.

>Pull-up resistors are necessary for proper function (bidirectional operation) and idle state.

Maybe it wasn't designed for. The product I'm working on is based on an multi agreement and has the requirement to be controlled via I2C Slave interface which must be hot pluggable. So it's nothing new in the real world. STML0 has such I2C IO characteristics to be used as a hot swap area. IOs are not pulled to GND while power on and are open drain. Pull-up resistors are installed on the master side.

>It seems so, now. Expect trouble with unresponsive slaves.

STM32 shall act as a slave.

I found a was to fix the issue, my question was about the sequence of IO initialization especially for the case as I've posted above.

Best regards

AvaTar
Lead

> Maybe it wasn't designed for. The product I'm working on is based on an multi agreement and has the requirement to be controlled via I2C Slave interface which must be hot pluggable.

If you come up with the requirement that a VW Beetle must now be fit for Formula One, this doesn't make it a racing car.

The future will tell how comprehensive you planning/testing was. But I predict trouble because of this sub-optimal choice.