Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
5 years, 10 months ago.
STM32 Clock Sources
Hi
I'm a little confused about how the clock souce is determined in mbed for the Nucleo devices. I know by default, the ST-Link on the same board as the Nucleo's will provide a 8MHz MCO output which is used as the HSE clock.
Say you break off the ST-Link part of the Nucleo board. I'm suspecting the clock source will revert to the internal oscillator (HSI)? If you solder a 8Mhz crystal in X3 with the appropriate caps and solder bridges bridged, will the STM automatically switch to using the crystal as the source?
I tried reading through https://os.mbed.com/teams/ST/wiki/Automatic-clock-configuration
In the explanation it says the controller will look in this order:
Quote:
If several values are set in the mask, STM32 SDK tries to configure the clock in this order:
1. USE_PLL_HSE_EXTC:
2. USE_PLL_HSE_XTAL
3. USE_PLL_HSI
4. USE_PLL_MSI
But then it states:
Quote:
Note that : HSE_BYPASS and HSE_ON (USE_PLL_HSE_EXTC and USE_PLL_HSE_XTAL) are exclusive: you should not select both value in the mask.
The default clock source in the targets.json for all the STM32-family
targets.json
"clock_source": { "help": "Mask value : USE_PLL_HSE_EXTC (SYSCLK=72 MHz) | USE_PLL_HSE_XTAL (need HW patch) | USE_PLL_HSI (SYSCLK=64 MHz)", "value": "USE_PLL_HSE_EXTC|USE_PLL_HSI", "macro_name": "CLOCK_SOURCE" },
From the value for clock_source in targets.json it doesn't seem like it would fall back to the crystal? What am I missing?
2 Answers
5 years, 10 months ago.
Taking a look at: https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F411xE/TARGET_NUCLEO_F411RE/system_clock.c#L96
SetSysClock() first attempts to use HSE via external clock source (Provided USE_PLL_HSE_EXTC is set). If that fails, it then tries to use HSE via external oscillator (provided USE_PLL_HSE_XTAL is set). Finally, if both fail, it reverts to setting up the HSI.
The reason USE_PLL_HSE_EXTC and USE_PLL_HSE_XTAL are exclusive is that you _cannot_ have a hardware configuration that supports both. Since the OSC_IN clock pins are shared (PH0/PH1) - you either have an external clock source or an external crystal hooked up to those pins, not both.
Note: Technically the code does not ASSERT that you only have one set - you could set them both and use that code on 2 hardware builds - one with an xtal and one with clock source. The one with the xtal should fail to set up as external clock then fallback to using xtal
posted by 08 Jul 2018I'm struggling with this part here in the source file you linked:
void SetSysClock()
#if ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) /* 1- Try to start with HSE and external clock */ if (SetSysClock_PLL_HSE(1) == 0) #endif { #if ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) /* 2- If fail try to start with HSE and external xtal */ if (SetSysClock_PLL_HSE(0) == 0) #endif
The default targets.json sets CLOCK_SOURCE = "USE_PLL_HSE_EXTC|USE_PLL_HSI" Doesn't that mean that the second #ifdef in the above code snippet (/* 2- If fail try to start with HSE and external xtal */) won't be executed?
posted by 08 Jul 20185 years, 9 months ago.
Hello Riaan,
USE_PLL_HSE_EXTC
and USE_PLL_HSE_XTAL
are defined in the system_clock.c
as below:
system_clock.c
//... #define USE_PLL_HSE_EXTC 0x8 // Use external clock (ST Link MCO) #define USE_PLL_HSE_XTAL 0x4 // Use external xtal (X3 on board - not provided by default) #define USE_PLL_HSI 0x2 // Use HSI internal clock //...
If we examine them in binary format then we can see that they are designed to represent bit-positions.
USE_PLL_HSE_EXTC = 0b00001000 USE_PLL_HSE_XTAL = 0b00000100 USE_PLL_HSI = 0b00000010
Hence
CLOCK_SOURCE = USE_PLL_HSE_EXTC | USE_PLL_HSI = 0b00001100 // notice that "|" is a bitwise OR (not a logical OR)
Since &
in the snippet below is a bitwise AND
(not a logical AND
) implies that the second #ifdef
still can be executed.
void SetSysClock()
#if ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC) /* 1- Try to start with HSE and external clock */ if (SetSysClock_PLL_HSE(1) == 0) #endif { #if ((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) /* 2- If fail try to start with HSE and external xtal */ if (SetSysClock_PLL_HSE(0) == 0) #endif