STM32F4 System Clock Testing – MCOx
In previous tutorials we discussed what are different clock source available on STM32 and how each of them can be selected programmatically. Although we set clock selection bits in respective registers as per STM32F4 Reference Manual  yet there was (may be) still a teeny tiny doubt:
- Is the clock really selected?
- Does the system really switched to selected clock source?
- What actual clock frequency does the system receiving as apposed to expected clock!
In short – how can the configured clock be verified? 😉
Well the good news is there is a way around to verify system clock. The Microntroller Clock Ouput (MCOx) feature of STM32 allows to reroute one of six system clocks i.e. HSI, HSE, LSE, SYSCLK, PLL, and PLLI2S to specific GPIOs Pins for verification purpose or providing clock to external devices in case if required.
The STM32 onchip clock and power control unit i.e. RCC provides the facility to route various system clock sources to specific GPIOs Output Pins (MCO1-PA8, MCO2-PC9) as a part of alternate function. This output clock routed from system clock sources can be measured externally via a logic analyzer etc.
In this tutorial we will discuss how clock from various clock sources can be routed to GPIO pins for test purpose. The board we are using is STM32F4-Discovery. If we look at STM32F407 Clock tree , we will see that there are two pins i.e. MCO1 and MCO2 to which various clock source are connected via a multiplexer and prescalers. Figure-1.
The MCO1 and MCO2 are the pins which can be used to verify various System clock sources. According to datasheet :
For demonstration purpose we will verify the default connected clock source i.e. the internal 16MHZ HSI Oscillator on MCO1 (PA8).
Following are the steps…
1. As we are using MCO1 pin which is multiplexed with GPIOA Pin#8 (PA.8) so the first step is to configure PA.8 to be used for Clock output and not as General Purpose GPIO. The configuration includes enabling clock to GPIOA and programming PA.8 for Alternate function AF0. We have a separate tutorial for GPIO configuration as an Alternate Function. The tutorial can be accessed via the following link.
PA.8 is configured as Alternate Function – 0 via the following code snippet.
/* MCO1 --> PA8 */ /* Enable clock to GPIOA */ RCC->AHB1ENR |= 1U; /********************* PA.8 Configuration *********************/ /* PA8 will be used for clock output (MCO1) and not as GPIO so configure it for alternate funciton */ GPIOA->MODER &= ~(1U << 16); GPIOA->MODER |= (1U << 17); /* Push Pull -> clock inlcludes both states */ GPIOA->OTYPER &= ~(1U << 8); /* high speed */ GPIOA->OSPEEDR |= (2U << 16); /* connect to alternate function AF0 (System Function)*/ GPIOA->AFR &= ~(0xFU);
2. As shown in Figure-2, four different clock sources can be output on MCO1. For demonstration purpose we will select the internal RC Oscillator HSI. The clock sources for both MCO1 and MCO2 can be selected via RCC Clock Configuration Register (RCC_CFGR) – Figure-3.
For MCO1, bit#21,22 are used to select clock source.
00: HSI clock selected
01: LSE oscillator selected
10: HSE oscillator clock selected
11: PLL clock selected
As we want HSI output on MCO1 so bit#21,22 are both set to 0
/******************** MCO1 Settings ********************/ /* 00: HSI clock selected [WE WILL SELECT THIS ON] 01: LSE oscillator selected 10: HSE oscillator clock selected 11: PLL clock selected */ RCC->CFGR &= ~(3U << 21);
3. This step is kind of optional. If both output clock frequency comes under the range of:
- Bus frequency on which GPIOx is interfaced (Max Bus Speed)
- Measuring Instrument
If both of these conditions are satisfied then you may skip this step. Otherwise in either case, you need to scale down the frequency internally by a factor so that it can be measured accurately. The actual frequency will be the measured frequency multiplied by the scaled factor. The scale factor can be set via bit#24-26 (for MCO1) and bit#27-29 (for MCO2) in RCC Clock Configuration Register (RCC_CFGR) – Figure-3.
0xx: no division
100: division by 2
101: division by 3
110: division by 4
111: division by 5
In our case, as we want the clock output to be HSI (16MHz), so lets scale it down by a factor of 4. Now the clock frequency on MCO1 pin should be ~4Mhz (16/4).
/* Prescale by factor of 4 --> 4Mhz output on MCO1 (in range of low quality analyzer) */ RCC->CFGR &= ~(1U << 24); RCC->CFGR |= (3U << 25); /* Now HSI clock is connected to MCO1 MCO1 pin will now provide clock of ~4Mhz. */
For complete code refer to the link given at the start of this tutorial.
 – Reference manual-RM0090