### STM32Cube code initialization for “blue pill”

Lately I’ve playing around with the STM32F103 development board known as “blue pill”. Developing software for it is not as easy as for Arduino boards. The MCU contains a 32-bit ARM CPU. I have previously tried to write software for this board using HAL library, but I didn’t get the most out of it because I found the programming model rather complicated.

One of the methods to develop software for this MCU is to use ST HAL library (which uses a higher level API than other libraries for this MCU). I chose the Eclipse IDE with a set of plugins for STM32 family. There is an easier way to get the SDK and IDE with the toolchain called System Workbench for STM32 (recommended by ST too). This is the download directory where you can find all releases for the major operating systems. But before creating a blank project in SW4STM32, you should know that there is a tool which can create this project for you. Not quite blank, as you will configure the MCU with a graphical tool in a step-by-step process.

In my opinion, the most difficult initialization procedure for STM32 is the clock configuration. With multiple clock sources, clock prescalers and multipliers, you need to read carefully the documentation to get the right clock frequency. STM32Cube is the graphical initialization tool and it is not limited to clock configuration only. MCU ports and communication interfaces can be configured at this point too. This post will focus mostly on clock configuration though.

 Install HAL for STM32 in CubeMX

STM32Cube is ready for use. Create a new project (File menu, toolbar button or Ctrl+N shortcut). It may download something at this point. Just wait. In the New Project window you must choose the correct MCU. Blue pills use STM32F103C8 or STM32F103CB (the difference is flash size: 64kB for C8 version and 128kB for CB version). Connect the blue pill to ST-Link and use the programming utility (see the Windows and Linux sections here) to check flash size. If it’s 128kB, the MCU is CB version. Select MCU and click Start Project.

 Create new project based on STM32F103
You’ll be prompted with the Pinout tab. Here you can either click on a pin and set its function or you can use the left treeview and configure peripherals. Since blue pill uses and 8 MHz crystal, that’s the first thing to configure. Go to Peripherals—RCC and set High Speed Clock (HSE) to Crystal/Ceramic Resonator. It should be noted that the bluepill also contains a 32.768 kHz oscillator, therefore you can set the same for LSE, if you intend to use the RTC peripheral.

 Enable HSE clock in STM32Cube
You can move to Clock Configuration where you will see a flowchart. Look at the screenshot below. I’ll try to match each GUI setting to the line of code you will see (and later edit) in clock configuration function. At the beginning of the main() code entry, clock needs to be configured. This is usually done in a function that is called here.

 STM32F103 Clock configuration in CubeMX
Two HAL calls configure system clock: HAL_RCC_OscConfig (selects physical clock sources) and HAL_RCC_ClockConfig (selects system clock source and configures dividers). A specific, previously declared and configured structure type is passed to these functions.

Looking and the visual configuration, HSE clock (which is 8 MHz—from the crystal) can and will be used as source for both PLL and System Clock muxes. It must be enabled (you just did this in Pinout tab). The result is:
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
To be able to make changes to RTC Clock Mux, enable the RTC in Pinout tab. If you do this, the above OscillatorType will include LSE too.

In the PLL Source Mux, HSE will obviously be used instead of HSI. You can use the full frequency or divide it by a factor of two (HSE Prediv value) [1]. You configure this in the code like this:
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
The PLL has the ability to multiply its input frequency by maximum 9 for this microcontroller [2]. This will result in a system clock of 72 MHz, the maximum available. Choosing PLLCLK as source for System Clock Mux [3], will generate code for enabling PLL. It will be configured with HSE source and chosen multiplier.
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
STM32Cube also configures HSI (internal RC oscillator) as turned on because it is used as Flash memory programming clock. You can turn it off however. When programming flash, the ST-Link will reset MCU to default state where HSI is enabled.
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
At this point we have system clock frequency configuration (SYSCLK [4])! There’s one more clock that derives straight from PLL instead of SYSCLK. That’s the USB clock, but we’ll talk about it later. To apply current clock configuration, you must call HAL_RCC_OscConfig with the address of RCC_OscInitStruct variable.

The next clocks are configured in a different structure. The structure variable can configure one or more clocks. By default, STM32Cube configures all (high-speed clock, system clock, peripheral clock 1 and 2):
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
PLLCLK is the system clock source [3]. Here it is set:
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
Following the diagram, SYSCLK can be applied to AHB (advanced high-perfomance bus) prescaled [5]. AHB prescaler is configured in code:
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
The output from prescaler drives CPU clock (HCLK) and peripheral clocks (via prescalers).

 Peripheral clock configuration
Only APB1 and APB2 clocks (advanced peripheral buses) are configured in RCC_ClkInitStruct. They can be prescaled with factors of 1/1, 1/2, 1/4, 1/8 and 1/16. APB1 needs to be divided by at least 2 if HCLK is 72 MHz. That’s because PCLK1 can’t be higher than 36 MHz. The remaining code is:
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
Similar to the previous structure variable, the address of this one is passed to HAL_RCC_ClockConfig function.

Specific peripheral clocks are configured with an extension driver. For example USB clock that derives straight from PLL is configured like this:
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
Similar to previous ClockConfig function, this one can configure multiple clocks in a single call if you specify clocks in PeriphClockSelection and set their parameters.

STM32Cube can configure CSS (Clock Security System) too. This is a function that switches the main clock source from HSE to HSI if by any chance HSE stops working. This is done with a single call:
HAL_RCC_EnableCSS();
As you can see there are a lot of options to set the clock of STM32 MCU. Luckily, you don’t have to read the manual a lot of times to understand all of them since STM32Cube helps you configure STM32 clocks in a visual way. More than that, if you make a mistake it informs you and can fix the problem for you. Use Project – Generate Code to create the SW4STM32 project. It will ask for a project folder (or you can set these in Project - Settings). If you use a different IDE, set it in Toolchain / IDE combobox.

You can also head over to Configuration tab of STM32Cube and adjust options for enabled subsystems. Generate code and see the programming model in main.c file. The first routine called in main() is HAL initialization function followed by local clock configuration generated based on your settings. The SystemClock_Config function is reusable for any project with similar clock configuration (copy-paste it in your projects and you don’t have to use STM32Cube).

At the end I'm offering you a sample Cube project for bluepill. It configures HSE, LSE, LED at PC13 and USB interface. All clocks are at their maximum values. Download the project, modify it and generate your code.

## References

#### 1 comment :

1. Thank you Cornelius, for the interesting information on STM32Cube and using it to program the Blue Pill. It's a pleasant surprise to me that the graphical tool STM32Cube is free! I need to start playing with it soon!!

I have two Blue Pill boards with different types of reset switch but both have the same STM32F103C8T6 chip and the same pinout. On checking the boards using ST Link/V2, I find that the flash size is 64K in one while it is 128K in the other. Checked again; the chip is STM32F103C8T6 in both the boards. I understand that F103C8T6 chip comes with 64K or 128K flash.

Looking forward to more projects with the Blue Pill.