An easy way to generate initial configuration of a development project for the STM32 bluepill using STM32CubeMX software.
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.
The first step is to download and install STM32Cube. You can get it from ST by providing your email address or making an account. Download link is sent to your email address. The software is based on Java, so you have to install it to run STM32Cube. A graphical installer is provided for all operating systems, so there’s nothing to say about the installation procedure. When it’s done launch it.
Install HAL for STM32 in CubeMX |
Select and download HAL for STM32F1 |
Create new project based on STM32F103 |
Enable HSE clock in STM32Cube |
STM32F103 Clock configuration in CubeMX |
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 |
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
- STMicroelectronics. UM1850 User manual - Description of STM32F1 HAL and Low-layer drivers.
- STMicroelectronics. RM0008 Reference manual - STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs.
- Wikipedia contributors. Advanced Microcontroller Bus Architecture.
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!!
ReplyDeleteI 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.
Hi Bala,
DeleteI don't know the specific case for the STM32F103C8T6 , but the following is a very common situation in the Silicon industry.
The cost to design and manufacture chips is made up of two parts:
First is the design effort and the creating of the master masks/reticles used to manufacture the chips. This is very expensive. For small chips it might be a few million dollars, and for big chips it can be over 100 million dollars. The actual manufacturing is expensive too, ranging from a $500 to $500 per wafer
http://www.icinsights.com/news/bulletins/LeadingEdge-IC-Foundry-Market-Forecast-To-Increase-72-In-2014/
https://caly-technologies.com/die-yield-calculator/
But the wafer cost is divided by the chip size. If you can fit 15,000 chips (2 mm x 2mm) on a 300 mm wafer with 90 nm process, the cost per chip is about $2000/15000 = $0.13 each. So that is my ball park guess for STM32F103C8T6 . Then add packaging cost, test cost, support cost, and maybe some profit.
Why the long story above? Because you have to sell a hell of a lot of chips that sell for under a dollar to get enough profit to cover the design and mask costs. So what manufacturers do is they design a Master chip that they can sell at a premium, and sell the same chip but with a different label, less declared capabilities, and less testing, at a lower price. Thus the total number of wafers and total sold chips increases for the one initial upfront cost of a few million dollars.
Since many people (including me) have seen STM32F103C8T6 that seem to have 128 KB of Flash, then the likely scenario is that the master chip is STM32F103CBT6 , and when manufacturing parts that will be labeled STM32F103C8T6 , they don't bother testing the upper half of memory.
A manufacturer that cared about their reputation, would only use the Flash that ST says the device has and which is tested. If they needed 128K, they would buy the STM32F103CBT6 and pay the extra cost for it being tested to meet the appropriate spec.
In STM32CubeMX
ReplyDeletePinout&Configuration -> RTC -> RTC Mode and Configuration -> RTC OUT set to "No RTC Output"
Then PC13-TAMPER-RTC output to Pin.
All work!
Hehey, nice tip, couldn't figure out why my BluePill LED was constantly lit. Everything was set up perfectly, yet simple hal_toggle/hal_delay didn't work.
DeleteChecked CubeMX again and I had 'Activate clock source' under RTC checked and while RTC_OUT was set to Disable I noticed Output in bottom window still was still at "Alarm pulse signal on the TAMPER pin"
Changed RTC_OUT in top window to "No RTC output" and Output in bottom window switched to "No output on the TAMPER pin" - and blinky suddenly started blinking.
I have a bunch of BluePill-s from AliExpress, all with wrong R10 resistor. See
ReplyDeletehttp://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html
//
// AliExpress BluePills with wrong R10.
// See http://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html
// Call once from main just after SystemClock_Config(); call.
//
void USB_BluePill_Reenumerate()
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, 0);
HAL_Delay(1);
}
BTW, boards work perfectly except (without the piece of code above) right after starting debug session, CDC device shows up nicely in Windows 10 device manager, but trying to open COM port resulted in failure. Had to reset device to be able to use it as serial port.
DeleteWith code above, I can sit at CDC breakpoint, open COM port and debug away.
I've created a collection of example projects using STM32CubeIDE for the Blue Pill board here...
ReplyDeletehttps://github.com/miniwinwm/BluePillDemo
Nice blog thanks for posting.
ReplyDelete