Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 73

Optimizing Power with RCC Peripheral Clock Control

Recommended resources

Introduction

Welcome back. In our previous lesson, we explored how to achieve significant power savings by placing the MCU into Sleep and Stop modes when it's idle. You learned to wake the system using an external interrupt and, critically, how to restore the system clock after waking from Stop mode.

Those techniques are excellent for reducing standby power consumption. Today, we shift our focus to reducing active power consumption. The learning outcome for this lesson is to disable unused peripheral clocks in the RCC to minimize power consumption. This technique, known as clock gating, is fundamental to writing power-efficient firmware. You will learn why every enabled peripheral draws power—even if it's not being used—and how to selectively turn them off to create a more efficient system.


1. The Principle of Clock Gating

In an STM32 microcontroller, the Reset and Clock Control (RCC) peripheral acts as the heart of the system's power distribution. It takes the main clock sources (like HSI or HSE) and routes the clock signals to the CPU, memory, and all the peripherals like UART, SPI, I2C, and timers.

A core principle of low-power design is: If a component is being clocked, it is consuming power. This holds true even if your code isn't actively calling functions related to that peripheral. Simply having its clock enabled means its internal logic is active and drawing current.

Clock gating is the practice of programmatically enabling (ungating) a peripheral's clock only when it's needed and disabling (gating) it when it's not.

STM32 RCC Clock Tree Diagram
This clock tree diagram illustrates how clock signals are distributed from sources like HSI/HSE through prescalers to the various peripheral buses (AHB, APB1, APB2). Every peripheral's clock originates from this network.

To understand the mechanism, let's look at a foundational article.

STM32 Clock Configuration Guide: Understanding the Clock System ...

The 'STM32 Clock Configuration Guide' provides a clear explanation of how the RCC manages system resources. We'll focus on the sections that describe how clocks are controlled.

Please read two key parts of this article: Start at the section 'Clock Sources'. Read the important note just below the list of clock sources, which explicitly states that each source can be switched on or off to optimize power. Then, jump to the section 'Peripheral Clock Gating and Autonomous Mode'. Read the paragraphs that explain how each peripheral's clock is managed by enable (EN) bits in the RCC_AHBxENR and RCC_APBxENR registers. Pay close attention to the 'Important' note about register accessibility.

As you've just read, the entire mechanism boils down to controlling individual bits in a set of special RCC registers.


2. The Mechanism: RCC Enable Registers

When you configure a peripheral like USART1 or SPI1 in STM32CubeIDE, the generated initialization code automatically adds a line to enable its clock. This is done by setting a specific bit in one of the RCC's peripheral enable registers: RCC_AHBENR, RCC_APB1ENR, or RCC_APB2ENR.

For example, the clock for every peripheral on the APB2 bus is controlled by a single bit in the RCC_APB2ENR register.

RCC_APB2ENR Register Bitfield Map
This image shows the `RCC_APB2ENR` register. As you can see, Bit 14 (`USART1EN`) enables the clock for USART1, Bit 12 (`SPI1EN`) for SPI1, and Bit 4 (`IOPCEN`) for GPIOC. To disable a peripheral's clock, you simply clear its corresponding bit.

In our first module, you learned to manipulate registers directly. Enabling the clock for GPIOC would look like this:
RCC->APB2ENR |= (1 << 4); // Set bit 4 to enable GPIOC clock

To save power, we simply do the opposite:
RCC->APB2ENR &= ~(1 << 4); // Clear bit 4 to disable GPIOC clock

The following video, though focused on clock setup, contains a short segment demonstrating this exact register-level manipulation to enable a peripheral. It's a good reminder of the low-level process.

#1.2 STM32F103 Clock Setup using REGISTERS || TIMER Config || GPIO Config

In this video from ControllersTech, the presenter enables peripheral clocks using direct register access. Watching this will reinforce the concept that clock control is simply a matter of setting bits.

Watch the two short clips from 06:06 to 07:16 and 11:35 to 12:34. Observe how the RCC->APB1ENR and RCC->APB2ENR registers are modified with bitwise operations to enable the clocks for Timer 2 and GPIO Port C.


3. Implementing Clock Gating with the HAL

While direct register access works perfectly, the STM32 HAL provides a more portable and readable way to manage peripheral clocks using a set of macros. These are the recommended methods when working within the HAL ecosystem.

The two main macros are:

  • __HAL_RCC_PERIPH_CLK_ENABLE()
  • __HAL_RCC_PERIPH_CLK_DISABLE()

Here are a few examples for peripherals on your Blue Pill board:

// To manage the SPI1 peripheral (on APB2 bus)
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_DISABLE();

// To manage the I2C1 peripheral (on APB1 bus)
__HAL_RCC_I2C1_CLK_ENABLE();
__HAL_RCC_I2C1_CLK_DISABLE();

// To manage the USART1 peripheral (on APB2 bus)
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_USART1_CLK_DISABLE();

Crucial Rule: As highlighted in the article from aticleworld.com, once a peripheral's clock is disabled, its registers become inaccessible. Any attempt to write to or read from the peripheral's configuration (e.g., hspi1.Instance->DR) will fail and may cause a HardFault. You must re-enable the clock before interacting with the peripheral again.

The following document provides a concise, practical example of clock gating.

Low Power modes on STM32

This PDF on 'Low Power modes on STM32' contains an excellent, focused section on the effect of clock gating.

Please read section 3.9 'Effect of USART2 Clock gating'. This section perfectly encapsulates today's topic. It explains that since the USART is only used during an ISR, its clock can be disabled at other times to save power. It also introduces the HAL functions for doing so.


4. Hands-on Exercise: On-Demand Peripheral Management

It's time to put this into practice. In this exercise, you will create an application that enables and disables peripheral clocks on demand based on user input.

Your Task:
Create a new STM32CubeIDE project for your Blue Pill board.

  1. CubeMX Configuration:

    • Enable USART1 in Asynchronous mode for printf communication (e.g., 115200 baud).
    • Enable SPI1 in a basic mode (e.g., Transmit Only Master). Don't worry about pin configuration for now.
    • Enable I2C1 in I2C mode.
    • Generate the code. CubeMX will automatically add the _CLK_ENABLE() calls for all three peripherals in main.c.
  2. Firmware Logic in main.c:

    • You will need to implement UART reception to get user commands. You can use the polling-based HAL_UART_Receive() for simplicity in this exercise.
    • Immediately after the MX_..._Init() functions are called in main(), explicitly disable the clocks for SPI1 and I2C1. USART1 must remain enabled for communication.
      /* Right after MX_GPIO_Init(), MX_USART1_UART_Init(), etc. */
      printf("System Initialized. SPI1 and I2C1 clocks are OFF.\r\n");
      __HAL_RCC_SPI1_CLK_DISABLE();
      __HAL_RCC_I2C1_CLK_DISABLE();
      
    • In your while(1) loop:
      • Print a menu to the user:
        Menu:
        1. Enable SPI1 Clock
        2. Disable SPI1 Clock
        3. Enable I2C1 Clock
        4. Disable I2C1 Clock
        Enter command: 
        
      • Wait for a character to be received via USART1.
      • Use a switch statement to handle the input:
        • If '1' is received, call __HAL_RCC_SPI1_CLK_ENABLE() and print a confirmation message.
        • If '2' is received, call __HAL_RCC_SPI1_CLK_DISABLE() and print a confirmation message.
        • Do the same for '3' and '4' with I2C1.

Expected Outcome:
When you run the program, you should be able to control the clock state of the SPI and I2C peripherals from your serial terminal. While you won't be measuring the power drop in this lesson, you are building the exact firmware structure required to do so. This exercise proves you understand the API and the logic of enabling/disabling clocks dynamically.


Conclusion

Excellent work. You have now learned one of the most common and effective techniques for reducing active power consumption: clock gating.

Key Takeaways:

  • Any peripheral with an active clock consumes power, regardless of whether it's actively used in your code.
  • Clock Gating is the practice of disabling peripheral clocks when they are not needed.
  • The RCC peripheral controls clock distribution via enable bits in the RCC_APBxENR and RCC_AHBENR registers.
  • The HAL provides convenient macros (__HAL_RCC_PERIPH_CLK_ENABLE() and __HAL_RCC_PERIPH_CLK_DISABLE()) for this purpose.
  • Crucially, a peripheral's registers are inaccessible when its clock is disabled. You must enable the clock before attempting to configure or use the peripheral.

Preview of the Next Lesson:

So far, we've used external events like button presses to wake our MCU. But what if a device needs to wake up periodically, for example, once every hour to take a sensor reading? In the next lesson, we will configure the Real-Time Clock (RTC) to wake the system from a low-power mode, a feature that is essential for long-term, battery-powered applications.