Welcome back! In our previous lesson, we demystified the process of using the STM32 reference manual to find the specific hardware registers that control a peripheral. You learned to navigate from the high-level memory map right down to the individual bits that govern hardware behavior.
Today, we will apply this essential skill to one of the most critical parts of the microcontroller: the Reset and Clock Control (RCC) peripheral. A stable and predictable clock is the very heartbeat of your system, and everything from communication speeds to task scheduling depends on it.
This lesson directly addresses the learning outcome: Configure the system clock (RCC) from HSI/HSE sources and verify the frequency.
We will move away from the default, less accurate internal clock and learn how to configure your Blue Pill board to run at its maximum performance of 72 MHz, driven by its precise external crystal. Most importantly, you will learn how to prove that your configuration is correct using your logic analyzer, a technique that separates amateurs from professionals.
1. The Heartbeat of the MCU: Clock Sources
Every synchronous digital circuit, including our STM32 microcontroller, needs a clock signal—a pulsing square wave—to orchestrate its operations. The speed of this clock determines how fast the processor executes instructions.
For the STM32F103, there are several possible clock sources, but we will focus on the three most important for high-performance operation:
- HSI (High-Speed Internal): An internal 8 MHz RC oscillator. It's built into the chip, starts up quickly, and requires no external components. However, its frequency can drift with temperature and voltage changes, making it less suitable for precise timing. This is the default clock source after a reset.
- HSE (High-Speed External): An external crystal oscillator. Your Blue Pill board has an 8 MHz crystal connected to the MCU. This source is highly accurate and stable, making it the standard choice for professional applications.
- PLL (Phase-Locked Loop): This is not a source itself, but a powerful internal frequency multiplier. We can feed the stable 8 MHz signal from the HSE into the PLL and multiply it to generate a much faster system clock. To reach the maximum 72 MHz on your MCU, we will multiply the 8 MHz HSE by 9.
The following block diagram from the reference manual illustrates how these sources are routed through various multiplexers (muxes) and dividers (prescalers) to clock the entire system. Don't worry about understanding every detail now; focus on the path from HSE, through the PLL, to the SYSCLK (System Clock).

To get a narrated overview of these clock sources and the clock tree, watch the following short video.
Tutorial 8: MCU Clocks configuration in STM32 using STM32CUBEMX
This clip from a tutorial by Hexnbit explains the role of the RCC and breaks down the primary clock sources (HSI, HSE, PLL) and their purposes.
Watch the video in three parts: From 00:30 to 01:28 to understand why clocks are fundamental. From 01:44 to 03:37 for a description of HSI, HSE, and the PLL. From 06:48 to 08:56 for an excellent analogy that clarifies the clock tree structure and the concept of a central System Clock.
2. Clock Configuration with STM32CubeIDE
While we can (and will) look at the registers, modern development workflows often start with a graphical configuration tool like STM32CubeIDE. It presents the complex clock tree in an interactive way and automatically calculates the necessary PLL multipliers and bus dividers.
We will now configure your project to run at 72 MHz using the external crystal (HSE).
Getting Started with STM32 Blue Pill: Clock Setup & Code Upload with ST-Link Programmer | #stm32
This video by Kitflix provides a concise, hands-on guide to configuring the clock on a Blue Pill board—your exact hardware. Follow along with the steps in your own STM32CubeIDE project.
Watch from 09:16 to 13:42. The key steps to replicate are: In the Pinout & Configuration tab, go to System Core -> RCC. Under High Speed Clock (HSE), select Crystal/Ceramic Resonator. Switch to the Clock Configuration tab. For the PLL Source Mux, select HSE. For the System Clock Mux, select PLLCLK. In the HCLK (MHz) box, type 72 and press Enter. The tool will automatically solve the configuration, setting the PLL multiplier to x9 and adjusting the APB1 prescaler to /2 to keep that bus within its 36 MHz limit.
After performing these steps, save the .ioc file to generate the initialization code. You have now instructed the system to use the external crystal and run at full speed. But there is one more critical piece to this puzzle.
3. A Critical Detail: Flash Memory Latency
When the CPU core runs at 72 MHz, it requests instructions from the Flash memory at a very high rate. If the Flash memory is not fast enough to respond, the CPU will fetch invalid data, leading to a hard fault and system crash.
To prevent this, we must configure Flash wait states. This essentially tells the CPU to wait a specific number of clock cycles for the Flash memory to prepare the data. The faster the system clock, the more wait states are required.
This article from Rohit Nimkar on Medium clearly explains the concept of Flash latency and why it's essential for high-speed operation. This is a topic that often trips up beginners.
Read the section titled 'Set Flash Latency'. Pay close attention to the table that maps system clock frequency (SYSCLK) to the required number of wait states. Note that for our target of 72 MHz, we need 'Two wait states'.
Fortunately, STM32CubeIDE handles this for you automatically when you configure the clock. You can verify this by going back to Pinout & Configuration -> System Core -> RCC. You will see that Flash Latency (ws) has been set to 2. Knowing why this setting exists is crucial for professional development and debugging.
4. Verification: Measuring the Frequency
How can we be certain the MCU is actually running at 72 MHz? We must measure it.
The STM32 has a feature called MCO (Master Clock Output), which allows you to route internal clock signals, including the main system clock, directly to a GPIO pin. We can then connect a logic analyzer to this pin to measure the frequency precisely.
For the STM32F103, the MCO function is available on pin PA8.
Let's enable it and perform the measurement.
Tutorial 8: MCU Clocks configuration in STM32 using STM32CUBEMX
The Hexnbit video we watched earlier also explains how to configure the MCO pin for verification.
Watch from 10:37 to 12:30. This segment demonstrates how to enable the MCO1 output in the RCC settings and route a clock source to it. You will do the same in your project.
Hands-on Task:
- In your STM32CubeIDE project, navigate to the
Pinout & Configurationtab. - Find pin PA8 and click on it. Select the function
RCC_MCO. - Go to
System Core->RCCand find theMaster Clock Output 1setting. Set its source toSYSCLK. - Save the
.iocfile to generate code. Then, build and flash the project to your Blue Pill. - Connect your logic analyzer: one channel to pin PA8 and the ground probe to a GND pin on the board.
- Start a capture. You should see a square wave. Use your logic analyzer's measurement tools to find its frequency. It should be very close to 72 MHz.
This step provides definitive proof that your clock configuration is correct.
5. Under the Hood: Bare-Metal Register Configuration
The code generated by STM32CubeIDE simply writes to the RCC and Flash registers in the correct sequence. To solidify your understanding from the last lesson, let's review the step-by-step bare-metal process. The following article provides a clean C code implementation within the standard SystemInit function, which runs automatically at startup before main().
Getting Started with STM32F103: Pushing CPU to 72MHz
This blog post from EmbeddedExpert.io provides a perfect, concise code walkthrough of the bare-metal clock configuration sequence. It mirrors the steps the HAL code performs under the hood.
Read Section 2, 'Setting the core frequency using registers'. Do not copy the code, but instead, trace the logic and map it to the concepts we've discussed: FLASH->ACR = ...: Setting the Flash latency (2 wait states) and enabling the prefetch buffer. RCC->CR |= RCC_CR_HSEON;: Turning on the High-Speed External oscillator. while((RCC->CR & RCC_CR_HSERDY) == 0);: Polling the HSE Ready flag until the crystal is stable. RCC->CFGR |= ...: Configuring the PLL multiplier and bus prescalers. RCC->CR |= RCC_CR_PLLON;: Turning on the PLL. while((RCC->CR & RCC_CR_PLLRDY) == 0);: Polling the PLL Ready flag. RCC->CFGR |= RCC_CFGR_SW_1;: Switching the main system clock source to the PLL. This sequence of enabling, waiting for ready flags, and then switching is a very common pattern in embedded programming.
Understanding this sequence is invaluable for debugging and for working in environments where code-generation tools are not available.
Conclusion
In this lesson, you took a significant step toward professional firmware development. You have configured the system's core clock for maximum performance and, most importantly, verified its operation with an external tool.
Key Takeaways:
- The system clock is the heartbeat of the MCU. An HSE (external crystal) provides the accuracy and stability required for professional products.
- The PLL is a frequency multiplier used to boost the clock source's frequency to the desired system speed (e.g., 8 MHz HSE -> 72 MHz SYSCLK).
- Increasing the CPU clock speed requires increasing the Flash memory wait states to prevent system instability.
- STM32CubeIDE provides a powerful graphical tool for clock configuration, but understanding the underlying register operations is key.
- You can verify your clock frequency by outputting it on the MCO pin (PA8) and measuring it with a logic analyzer.
Preview of the Next Lesson:
With a precise 72 MHz clock source now established, we have a stable foundation for all timing-related activities. In the next lesson, we will configure the SysTick timer. This core timer will be used to generate a perfect 1-millisecond interrupt, creating a reliable time base that will serve as the foundation for our own delay functions and for scheduling tasks later in the course.