Programming STM32 "blue pill" with HAL and Eclipse

 Posted by:   Posted on:   Updated on:  2018-09-14T19:26:43Z

How to program STM32 bluepill in C using System Workbench or Eclipse and HAL library offered by ST. Example LED Blink code.

The "blue pill" is an STM32F103 based development board. Although it is less popular, the board is cheaper than an Arduino Nano. More than that, STM32F103 is a device with Cortex-M3 ARM CPU that runs at 72 MHz, 20 kB of RAM and 64 or 128 kB of flash memory. The microcontroller (MCU) has USB port, two serial ports, 16 bit PWM pins and 12 bit ADC pins. It runs at 3.3V, but some of its pins are 5V tolerant.

Unfortunately programming this board is not as easy as programming an Arduino board. There is a project named STM32duino aimed at simplifying things which makes use of Arduino IDE and similar programming language. But, STM32 is a complex CPU with more functions than Arduino language offers. You can program it using Eclipse IDE and a set of libraries offered by ST. These libraries are LL (low level), StdPeriph (standard peripheral library) and HAL (hardware abstraction library). HAL uses high level API which simplify developing an application. This post will show you how to configure the development environment and write the first program with HAL that will blink an LED.

An easier alternative to Eclipse and HAL is PlatformIO and Mbed. Check it out.
Programming STM32 "blue pill" with HAL and Eclipse
The development environment is Eclipse plus a set of plugins. There are two ways of getting it up and running. If you already use Eclipse and have it installed you can just install STM32 plugins. Otherwise AC6 Tools offers a bundled installer that will take care of everything. Instructions below are based on OpenSTM32 documentation.

The Eclipse Way

I'm assuming you got Eclipse installed and running. Go to Help menu and choose Install new software. Click Add button and paste the following URL:
http://ac6-tools.com/Eclipse-updates/org.openstm32.system-workbench.update-site-v2
Give it any name you want. Click OK and wait. Select all items available in the repository (both external tools and openstm32 tools). Click Next.

Add STM32 tools repository in Eclipse
Add STM32 tools repository in Eclipse
Click Next again, accept license and click Finish. Required tools will be downloaded and installed. If Eclipse throws some security warnings, choose to ignore them and continue. At the end you'll have to restart the IDE.

If you're on Linux, you must install the 32 bits version of standard C library and NCurses.
sudo apt install libc6:i386 lib32ncurses5

System Workbench

If you don't have Eclipse installed or you want an easier way, OpenSTM32 community and AC6 Tools offer a bundled installer. Click the AC6 Tools link and choose the appropriate version for your operating system. For Linux there is a run file and for Windows there is an exe installer. Choose the right one for the OS architecture.

Windows installation is pretty straightforward. Just follow installer instructions.

If you're on 64 bits Linux, you can use the following commands in terminal:
wget -O install_sw4stm32_linux.run http://www.ac6-tools.com/downloads/SW4STM32/install_sw4stm32_linux_64bits-latest.run
chmod a+x install_sw4stm32_linux.run
./install_sw4stm32_linux.run
You should run installation in console mode because GUI requires gksudo which is not included and not recommended to use in modern distros. Press 'y' when asked about this. Press 1 repeatedly to continue installation and accept license. You can leave the path default. Follow further instructions (press O, 1, Y, 1). Unpacking will start. Somewhere along the way it will ask you about an automated installation script. Enter 'Y' to create it, because Eclipse will download some tools based on it. When installation finishes, you'll get a Desktop shortcut. Launch it from there.

On first run, it will ask for a workspace directory. Projects will be created here.

The first program

Launch Eclipse or System Workbench for STM32. Go to File - New - Project. Select C Project from C/C++ category and click Next. If everything is installed, you should be able to select Empty Project of Executable type with Ac6 STM32 MCU GCC toolchain. Give it a name and click Next. Select build configurations (debug, release) and go to next screen. Wait a little before CPU selection screen appears.

Select target CPU in Eclipse
Select target MCU in Eclipse
Here, on MCU tab, choose STM32F1 series and STM32F103CBTx or STM32F103C8Tx. Blue pill boards usually come with a 128 kbytes FLASH, C8Tx type MCU. But if you choose C8Tx, the configuration tool will assign only 64 kbytes, because that's what the datasheet says. However, if your MCU is detected by ST-Link tools with 128 kbytes flash, choose CBTx. Most $2 blue pill boards have such a MCU (C8Tx with 128k). Click Next.

On Firmware Configuration screen choose HAL. First time you'll see a warning because target firmware does not exist. Click the Download button, accept license and wait.

Download target firmware for STM32 boards
Download target firmware for STM32 boards
You'll see a progress bar at the bottom of this window. Once it is done, you get to select additional software for your project, including USB support, FAT filesystem suport and RTOS operating system. By default, both StdPeriph and HAL options will also include support for LL, the low level API calls. That's a good thing, so let it selected and click Finish.

C Project with HAL for STM32
C Project with HAL for STM32
Eclipse will create all base files and folders. You will go to the project tree on the left, and open main.c from src. This is where you will place your code.

Code listing

Here is the Arduino blink sketch equivalent. Note that there is an easier way of generating initial configuration using STM32CubeMX, a graphical tool.
#include "stm32f1xx.h"
   
void SystemClock_Config(void) {
 RCC_ClkInitTypeDef clkinitstruct = {0};
 RCC_OscInitTypeDef oscinitstruct = {0};

 oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 oscinitstruct.HSEState = RCC_HSE_ON;
 oscinitstruct.HSIState = RCC_HSI_OFF;
 oscinitstruct.PLL.PLLState = RCC_PLL_ON;
 oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
 if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK) {
  while(1);
 }

 clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
   RCC_CLOCKTYPE_HCLK |
   RCC_CLOCKTYPE_PCLK1 |
   RCC_CLOCKTYPE_PCLK2);
 clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
 clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
 if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK) {
  while(1);
 }
}

int main(void)
{
 HAL_Init();
 SystemClock_Config();

 __HAL_RCC_GPIOC_CLK_ENABLE();

 GPIO_InitTypeDef gpio;
 gpio.Mode = GPIO_MODE_OUTPUT_PP;
 gpio.Speed = GPIO_SPEED_FREQ_MEDIUM;
 gpio.Pin = GPIO_PIN_13;
 gpio.Pull  = GPIO_PULLUP;

 HAL_GPIO_Init(GPIOC, &gpio);

 while (1) {
  HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  HAL_Delay(500);
 }
}
The specific MCU header is included at the beginning of code. Let's analyze main function.
HAL_Init();
SystemClock_Config();
These functions perform HAL initialization and configure system clock. The clock configuration function is taken from HAL/LL user manual UM1850 (pg. 54-55) and modified to use HSE (high speed external) clock and set PLL to 9 times HSE (9 * 8 = 72 MHz). System clock configuration enters into endless loops if configuration fails. If you don't call this, by default, MCU will use the internal RC oscillator, which is close to 8 MHz.
__HAL_RCC_GPIOC_CLK_ENABLE();
This is a macro that enables system clock for use with GPIO driver on port C. I'm enabling port C because my blue pill has the green LED connected to PC13.
GPIO_InitTypeDef gpio;
We declare a GPIO configuration structure that holds input/output type, pins, switching frequency. These are configured individually next.
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Speed = GPIO_SPEED_FREQ_MEDIUM;
gpio.Pin = GPIO_PIN_13;
gpio.Pull  = GPIO_PULLUP;
Push-pull output with medium switching frequency on pin 13 only. Multiple pins can be configured at once like this:
gpio.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_13;
The configuration is now created.
HAL_GPIO_Init(GPIOC, &gpio);
This function initializes HAL for GPIOC with the configuration provided in gpio struct. All this is equivalent to Arduino pinMode.

To blink the LED, in an endless loop, we toggle the pin and add a delay.
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(500);
Just like above, you can combine pins here too. The delay function will not work properly if system clock is not configured.

Paste the code listing in main.c and go to Project - Build Project. The binary file is in the project directory, subdir Release or Debug depending on selected build configuration and it is named as the project. It has bin extension.

Binary upload

You got a binary file by building the project. Go ahead and connect blue pill to ST-Link. If the board is powered from another source, do not connect the power pin from ST-Link anymore. Plug ST-Link into the USB port.

Linux

To be able to upload binary to the blue pill using ST-Link, udev rules must be installed. You can get the rules as well as ST-Link command line tools from Arduino_STM32. You need to download the entire repository, then go to tools/linux64 or tools/linux32. Run ./install.sh for udev rules. Keep stlink folder (you could copy all files from it to /usr/bin because those are ST-Link programming tools that we'll use next). You don't need anything else from this repo.

First of all, run st-info --probe. You should see your device detected, the flash and RAM size. Next, write the binary to the flash using:
st-flash --reset write ~/workspace/project/Release/project.bin 0x8000000
Adjust paths for the binary file you have. Because you installed udev rules, no root permissions are required.

Windows

Download ST-Link Utility from ST and upload the binary with it. The instructions are the same as uploading the bootloader from here - Windows section.

Once it is done, you should see the LED blinking.

Conclusion

Programming STM32 blue pill with HAL and Eclipse IDE is more difficult than using Arduino IDE. However, you have more control over the MCU and more space for your program because you don't need a bootloader. Once you have Eclipse or System Workbench set up you can go straight to writing code.

9 comments :

  1. All good until flashing

    LED went dark, stays dark...

    ReplyDelete
    Replies
    1. Which LED? From the blue pill or from the programmer?

      Delete
    2. Working great now, thanks

      I do have no idea what changed but after the about 10th attempt it justed started working reliably o.O

      Delete
    3. Thanks for the very quick reply,

      the blue pill's LED.

      Not your tutorial's fault, noticed now that the release binary had been created once and then never changed until it just started working, despite being updated and building fine.

      Well, it fixed itself, I'm happy.

      Thanks for the great, easy to follow tutorial. Still, you might want to move the step on installing the stlink tools higher up, got confused for a bit when you explained the difference between the c8tx and cbtx

      Delete
  2. Thanks for the quick tutorial. I am not using blue pill but a similar prototype board, STM32F103Cx DEMO BOARD v2.2.I had an issue compiling the code which is at the point of stating that
    if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
    it was suggesting i should use FLASH_LATENCY_0 which i did and it compile successfully. Can you help with why it is so?

    ReplyDelete
    Replies
    1. Flash memory is slower than CPU. Therefore, depending on CPU clock, it may be necessary to add some wait states for flash. See the Reference Manual, bottom of page 58. Also note that latency should be chosen by HCLK, not SYSCLK as the manual claims, as noted here. Probably you have configured a slower HCLK, that requires no latency at all (FLASH_LATENCY_0).

      Delete
  3. yes! it also works in Arduino IDE too!

    ReplyDelete
  4. Hello,
    I am using an STM32F103c8T6 (Blue Pill)
    LED at PC13 does not blink after uploading the code and shifting to operating mode (Boot0:0, Boot1:0).
    Tried uploading a couple of times now.

    Thanks!


    ReplyDelete
  5. Hey there,

    i had the same problem as others that my led would not blink.

    I did some debugging and it seemed like i was stuck in an endless loop the debugger called something like WWDG interrupt. This seemed unlikeley enough, having the WWDG not enabled, so i did some googeling and found a post that stated, that the code optimizer was optimizing all endless loops into one, and I could actualy not be stuck in a WWDG interrupt but possibly encountered a hard fault.
    Some more googeling revieled that one has to add this function

    void SysTick_Handler(void){
    HAL_IncTick();
    }

    when using the HAL_Delay function.

    With that the programm run as expected.

    This is also documented on page 1184 of "Description of STM32F1 HAL and low-layer drivers":
    "3. Add HAL_IncTick() function under SysTick_Handler() ISR function to enable polling process when usingHAL_Delay() function".

    So my best estimate what happened is, that SysTick_Handler() is not actually implemented, so I ran into a hard fault, but i didn't really investigate.

    I hope that can help some of you also.

    Best Michael

    ReplyDelete

Please read the comments policy before publishing your comment.