Skip to content

Wire.begin() and USB peripheral clock conflict #2930

@zfields

Description

@zfields

This simple sketch reveals a bug in the Cygnet:

#include <Wire.h>

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);

  for (int i = 0; i < 5; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
  }

  Wire.begin();
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

Describe the bug
The sketch will indefinitely hang at Wire.begin(); until the USB is plugged in. If the USB is plugged in at the beginning of the sketch, the whole sketch will run without interruption.

To Reproduce

Flash the sketch above using SWD when the device is powered by battery, and the Cygnet will blink 5 times quickly, but never transition to the slower blinks.

Plug in the USB and it will continue to the slower blinks.

Expected behavior
Continuous Blinking

Desktop (please complete the following information):

  • OS: Linux
  • Arduino IDE version: 2.3.8
  • STM32 core version: 2.12.0
  • Tools menu settings if not the default: n/a
  • Upload method: SWD

Board (please complete the following information):

  • Name: Blues Cygnet
  • Hardware Revision: 1.2
  • Extra hardware used if any: n/a

Additional context

I've tested several modifications to the initialization routines, and I was able to narrow it down to the following change in the WEAK void SystemClock_Config(void) function:

From (reproducing):

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC | RCC_PERIPHCLK_USB;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_MSI;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
    Error_Handler();
  }

To (no repro):

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
    Error_Handler();
  }

When I stepped through the debugger, this is the exact place it hangs in the code:

twi.c:

#if defined(I2C3_BASE)
  if (i2c == I2C3) {
#if defined(RCC_PERIPHCLK_I2C3) || defined(RCC_PERIPHCLK_I2C35)
#ifdef RCC_PERIPHCLK_I2C3
    clkSrcFreq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C3);
#else
    clkSrcFreq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_I2C35);
#endif
    if (clkSrcFreq == 0)
#endif
    {
#if defined(__HAL_RCC_GET_I2C3_SOURCE)
      switch (__HAL_RCC_GET_I2C3_SOURCE()) {
#ifdef RCC_I2C3CLKSOURCE_HSI
        case RCC_I2C3CLKSOURCE_HSI:
          clkSrcFreq = HSI_VALUE;
          break;
#endif
#ifdef RCC_I2C3CLKSOURCE_SYSCLK
        case RCC_I2C3CLKSOURCE_SYSCLK:
          clkSrcFreq = SystemCoreClock;
          break;
#endif
#if defined(RCC_I2C3CLKSOURCE_PCLK1) || defined(RCC_I2C3CLKSOURCE_D2PCLK1)
#ifdef RCC_I2C3CLKSOURCE_PCLK1
        case RCC_I2C3CLKSOURCE_PCLK1:
#endif
#ifdef RCC_I2C3CLKSOURCE_D2PCLK1
        case RCC_I2C3CLKSOURCE_D2PCLK1:
#endif
          clkSrcFreq = HAL_RCC_GetPCLK1Freq();
          break;
#endif
#ifdef RCC_I2C3CLKSOURCE_CSI
        case RCC_I2C3CLKSOURCE_CSI:
          clkSrcFreq = CSI_VALUE;
          break;
#endif
#ifdef RCC_I2C3CLKSOURCE_PLL3
        case RCC_I2C3CLKSOURCE_PLL3:
          HAL_RCCEx_GetPLL3ClockFreq(&PLL3_Clocks);
          clkSrcFreq = PLL3_Clocks.PLL3_R_Frequency;
          break;
#endif
        default:
          Error_Handler();
      }
#else
      /* STM32 G0 I2C3 has no independent clock */
      clkSrcFreq = HAL_RCC_GetPCLK1Freq();
#endif
    }
  }
#endif // I2C3_BASE

I don't understand the relationship between the USB and the I2C peripherals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions