STM32 BluePill Frameworks Evaluation

The STM32F103 BluePill, what's under the hoods of mbed, platformIO, Arduino,...

Similar projects worth following
How to get you up and running, fast, easy and with full control ?
Evaluation of the libraries, Operating Systems, Compilers and debuggers.
I started here using PlatformIO as build tool, but then due to attraction by the mbed-os the mbed cli has taken over. It is always possible to switch to an IDE for debug.
Visual Studio Code is being used as code editor and some of its plugins presented.

Useful command lines

List supported targets:
>mbed target -S
>mbed config --global toolchain GCC_ARM
>mbed config target NUCLEO_F103RB
>mbed new .
>mbed import mbed-os-example-blink
check dependencies:
>mbed ls -a
>mbed compile -c
download libs directories
>mbed deploy
add GCC to path:
>$env:Path +=";C:\toolchain-gccarmnoneeabi\bin"
check elf size:
>arm-none-eabi-size -B -d .pioenvs\bluepill_f103c8\firmware.elf
add st tools to path:
>$env:Path +="C:\tool-stlink"
>st-flash write .pioenvs\bluepill_f103c8\firmware.bin 0x08000000

Links to log entries for different steps :

pwm 'hello world' Arduino vs Mbed

Arduino not successfull here, and mbed get it out of the box.

new mbed Project from online to the command line

There we would see how to manage libraries, add blue pill support, fork and patch the mbed-os and solve the flash size problem by including the nano library flag

Where does my money go ? Check the build with a Map File GUI

A nice gui to easily check the content of the bin by file, module,...

STM32 Hello world and PS4 Joystick to servo

Here we go through a list of Hello world examples and then stick to the PS4 Joystick used by the raspberry pi to control a servo motor. This is a preparation for the RF connection and the up to 12 PWM of the Bluepill.

VSCode Configuring and Debugging

New mBed Project with PlatformIO command line

Clean and easy, but in case someone stick with mbed and wants to use mbed libraries, what's the point of learning how to use a new complete environment ?

New Arduino Project with PlatformIO command line

PIO toggle Startup and Power Consumption

Two twin BluePills are shown below for a power measure where each has a 22 Ohm resistor in series and fed with 6V for an expected drop of around 1V.

The result is measured with a cheap Hantek scope for a timing power startup profile

Other frameworks status

  • BluePill not supported
  • modified config to bluepill_f103rb.json
compil failing
  • BluePill not supported
  • testing with nucleo_f103rb
compil ok
Flash fail
mBed online
  • testing usb virtual com port
  • arm compiler
success on bluepill
mBed cli
  • testing usb virtual com port
  • gcc compiler
code > 64KB

After failing to use these libraries that are obviously compatible with the chip but platformIO still does not know that, I realised that adding a custom device or board require full understanding of this new yet another scons based build toolchain.


It is non sense to compare an OS running system to a bare metal one, this is nevertheless what you get out of the box, so nice to note that the mBed is smarter (lower power on delays) and in this case the Arduino simpler with faster startup. The OS size overhead is also of course significant, so I'm not sure if it's easy to use mBed libraries without the OS to reduce the footprint.

Pin Toggle Program:

ARM mBed gcc Arduino gcc
Code Size : Led Blink (4 lines of code) 28 KB 8 KB
Power Consumption 30 mA 41 mA
Startup 206 ms N.A

USB VCom Program:

Note that here we're comparing the same source code with two compilers

arm online gcc offline normal lib gcc offline nano lib
code size 33 KB 67 KB to be checked ~ 35KB


The build log for the test with arduino and gcc

log - 163.11 kB - 04/09/2017 at 10:08



The build log for the test with mbed and gcc

log - 610.72 kB - 04/08/2017 at 18:29


  • 1 × STM32 BluePill

  • STM32 Hello World and PS4 Joystick to Servo

    Wassim05/13/2017 at 18:49 0 comments

    Git Repo for the Hello world samples

    Samples Content

    • 01_pio_mbed_BlinkLed : using mbed from PlatformIO
    • 02_pio_arduino_BlinkLed : using Arduino from PlatformIO
    • 03_pio_mbed_Pwm : pwm signal on pin PB_4 with 20 ms period
    • 04_pio_mbed_uart : 2 UARTS Serial3 for log and Serial2 with uart callback echo character
    • 05_pio_mbed_nRF : Not finished, mbed libraries from within platformIO was a bit confusing
    • 06_mbed_cli_Hello_BluePill : Switching to the mbed command line (using version 2 here)
    • 07_mbed_cli_os_Hello_BluePill : switch to the os which is version 5
    • 08_mbed_cli_os_BluePill_Target : adapted the mbed-os to compile for the Bluepill target
    • 09_mbed_cli_nRF : STM32 with the #Home Smart Mesh RF configuration
    • 10_hello_servomotor : simple servo motor examples
    • 11_servo_uart_control : UART interface to control a servo motor from a Raspberry Pi using a Playstation 4 Joystick, the Raps code is here. Note that the PWM is 16 bits and the Joystick refresh rate is 10 ms for a 20 ms servo period, so the control cannot be more fluent.

    Testing the Servo UART protocol

    • Below we can see the binary command going out of the Raspberry pi, the anylzer is beeing smart here changing the values randomly to characters or ascii code depending on his wish.
    • The STM32 with its 72MHz handles an UART callback in 21 us. 4x times faster than one character duration. The last interrupt contains the printf which is in text so takes much longer ~ 1.5 ms.
    • Still 8.5 ms are free in the 10 ms period in which the Raspberry pi is sending new servo position commands.
    • Every 10 ms the rasp polls the joystick and if there is an update, sends a new servo command.

  • Build results analysis : GUI to check the MAP file

    Wassim04/30/2017 at 11:08 0 comments


    • we've seen in the main details of this project different build size results for the same source code depending on the build environment.
    • When the Flash size does not fit the build size any more, well, the whole concept of the dev kits selection breaks down and we have to opt to a more expensive device, in the case of the Bluepill, that can really hurt.


    • Start by having a look inside the build result, first a size summary
    arm-none-eabi-size -B -d -t .\Bluepill_hello.elf
       text    data     bss     dec     hex filename
      55240    2496     872   58608    e4f0 .\Bluepill_hello.elf
      55240    2496     872   58608    e4f0 (TOTALS)

    Yes, but that does not help, well the next level of details is to look into the map file,

    • First you have to generate it by passing the right command to the linker, the "-Map" below
    LD_FLAGS :=-Wl, -Wl,--gc-sections -Wl,--wrap,main -Wl,--wrap,exit -Wl,--wrap,atexit -mcpu=cortex-m3 -mthumb
    • Basically, we're done, but the result looks so ugly, how could any human understand anything ?

    • Hopefully some smart people thought about this problem, and provided an out of the box, easy to use solution to display all the details at all levels, libs, modules,... The magic AMAP tool from sikorskiy.

    I just had to drag and drop the map file, it complies with the "intuitive" qualification, and also with the "flexibility" as it works with command lines. It shows all results of size by Module, by file, by section.

    It is also possible to sort by size:


    • Contrary to my expectations, the memory was not eaten by the mBed, but by the libc.a.
    • The AMAP is a great tool to figure out what went wrong in the build chain
    • Bad news here, if you were expecting all the magic to work for you by adding optimization flags to do everything, well this does not look to be the case here, so many questions raise,
    • do we rebuild the library or do we link it as is ? And there come more questions,
    • which magical build toolchain are we using ?
    • What does platformIO do behind the scenes, how does mbed online generate its makefile ?
    • Finally to resolve all of these questions, I'll try to stick with more standard build chains that I can understand, better than have easy to use ones, which modification gets much harder than the well documented existing ones.

  • pwm 'hello world' Arduino vs Mbed

    Wassim04/15/2017 at 12:13 2 comments

    I expect the Arduino to be easier, was in a hurry to see some pwm output, so I started with it.

    Note that I'm testing with PB4 which after checking the pinout (at least), does support the hardware pwm functionnality, I'm not interested in any soft pwm, and I also expect libraries to do the necessary configuration for me.

    new Arduino Project

    • Create the project
    pio init --board bluepill_f103c8 --project-option="framework=arduino"
    • Add the main.cpp
    #include <Arduino.h>
    void setup()
      pinMode(PC13, OUTPUT);
      pinMode(PB4, PWM);  
    void loop()
      digitalWrite(PC13, HIGH);
      digitalWrite(PC13, LOW);

    Result = Fail !

    Fail !It keeps hanging, no LED plinking, well, you could debug it, but no, welcome to Arduino, I do not have serial connected to my board (early dev phase) and USB is out of flash size.

    After some googling I found another API for PWM :

    this is a uint16 api, looks more promising

    Result = Fail !

    Is this a framework supposed to be easier for newbies ? Not even the simplest peripheral has a unified API, why do we say that the STM32 is supported by this framework then, if I have to manipulate registers to get my pwm to run ?

    new Mbed Project

    • Create the project
    pio init --board bluepill_f103c8 --project-option="framework=mbed"
    • Add a main.cpp
    #include "mbed.h"
    DigitalOut myled(PC_13);
    PwmOut my_pwm(PB_4);
    int main() 
            myled = 1; // LED is ON
            wait(0.2); // 200 ms
            myled = 0; // LED is OFF
            wait(1.0); // 1 sec
    • research steps, googling "mbed pwm", first hit had a note to go to the latest pwm API page, and there, surprisingly, a simple example !!! not like all supposedly professional APIs where of course, who needs simple examples.
    • compile and flash

    >pio run
    >pio run -t upload
    Result = Success

    The LED is blinking, the quick measures show correct behavior of the PWM pio, did not check it with oscillo yet, but sounds correct.


    Arduino (-1)

    Mbed (+1)

    PlatformIO (+1)

    The context of this project is the STM32 Bluepill, Arduino might be better for 8bits or AVR, but for the Bluepill, mbed defeats arduino on its own field of excellence which is the simplicity of use for the very simple peripherals. PlatformIO here again shows how easy it is to compare different frameworks by still using the same commands.

  • new mbed Project from online to the command line

    Wassim04/14/2017 at 09:00 0 comments

    mbed versioning mess

    Even after reading about it, it took sometime to realize that version break changed the component name, so we have :

    mbed mbed 2 library
    mbed-os mbed 5 os and libraries

    New mbed online Project

    To create the project online, simply follow the link and click on import into Compiler

    • Update all libraries and dependencies (right click update)
    • compile
    • a bin file is automatically downloaded, ready to flash but by your own

    No need to comment, out of the box compilation

    Funny enough, the result is 1 KB beyond the Free Keil MDK limit, so won't be able to use the free version to recompile it offline.

    STM32F103C8T6_USBSerialNUCLEO_F103RB.bin 33 KB

    Export to the free world

    The export is very simple, but note that you're moving from the arm compiler into the gcc compiler, and that won't be without consequences.

    • The exported project has a makefile that you can compile by calling make
    • make sure an arm gcc toolchain is within our path
    • could be the official install "C:\Program Files (x86)\GNU Tools ARM Embedded\5.4 2016q3\bin"
    • or even the platformIO toolchain "C:\Users\User\.platformio\packages\toolchain-gccarmnoneeabi\bin""

    After the build, what a surprise !!!!!

    PS D:\Projects\STM32\mbed\STM32F103C8T6_USBSerial> arm-none-eabi-size -B -d -t .\BUILD\STM32F103C8T6_USBSerial.hex
       text    data     bss     dec     hex filename
          0   68320       0   68320   10ae0 .\BUILD\STM32F103C8T6_USBSerial.hex
          0   68320       0   68320   10ae0 (TOTALS)
    STM32F103C8T6_USBSerial.bin 67 KB

    As you might have noticed that goes beyond the Bluepill Flash size.

    • That the export from arm compiler to gcc doubles the code size is somehow impressive, is the arm compiler that efficient or is this a misconfiguration ?
    • Answer to this question lay in the library, after the AMAP analysis tool allowed me to figure out that it's a library problem, a quick search resulted in such links : an explanation is here.
    • Possible solution : check how to include other libs than the compiler default ones, stack overflow post.

    Next steps will cover creating mbed cli and platformIO projects and try to manage the dependencies "mbed-STM32F103C8T6" and "USBDevice_STM32F103" to make them work. Understanding how to modify the environment parameter is crucial for such cases that require optimization.


    The idea here is not to create a tutorial on how to use mbed CLI, for that and other install and use steps please refer to the up link. Here is meant to have a quick view on possibilities and a reminder for steps and commands.

    To use the GCC (Free and open), one way is to configure a system variable


    or simply in ""

    # GCC ARM
    GCC_ARM_PATH = "C:\Program Files (x86)\GNU Tools ARM Embedded\6 2017-q1-update\bin"

    import an existing project with mbed CLI

    >mbed import
    >cd mbed
    >mbed update
    >cd ..
    >mbed compile -t GCC_ARM -m NUCLEO_F103RB

    Not updating it gets a compiler error, I don't know if this is a dependency mistake or a configuration error.

    The target "BLUEPILL_F103C8" not recognised (only recognized in platformIO) you have to build for the Nucleo. Reason behind this is that the Blue pill does not have an mbed drag and drop ability, I find this reason funny. so here the hack is the already patched main including the right header before mbed.h and very important is to call yourself the confSysClock();

    #include "stm32f103c8t6.h"
    #include "mbed.h"
    int main() {
        confSysClock();     //Configure system clock (72MHz HSE clock, 48MHz USB clock)

    Better way to import a project by knowing what is going on

    clone the complete repo or just copy the content of the sub directory test project, note you can also create a new project this way which I find more convenient as the whole thing is just around 1 KB.

    The ".mbed" contains all the magic, tool chain, target,...

    Read more »

  • new Arduino Project with PlatformIO command line

    Wassim04/14/2017 at 08:15 0 comments

    • >pio init --board bluepill_f103c8 --project-option="framework=arduino"
    • then update content of platformio.ini

    Content of the platformio.ini

    platform = ststm32
    board = bluepill_f103c8
    framework = arduino
    The main.cpp
    #include <Arduino.h>
    void setup()
      pinMode(PC13, OUTPUT);
    void loop()
      digitalWrite(PC13, HIGH);
      digitalWrite(PC13, LOW);
    The compiler is the same "arm-none-eabi-g++" and the result is
    arm-none-eabi-size -B -d .pioenvs\bluepill_f103c8\firmware.elf
    text	   data	    bss	    dec	    hex	filename
    6284	   1920	    312	   8516	   2144	.pioenvs\bluepill_f103c8\firmware.elf
    So the Flashed code size is : 8 KB

  • VSCode Configuring and Debugging

    Wassim04/14/2017 at 08:06 0 comments

    Configuring Includes in VSCode

    In VSCode you'll see the "mbed.h" underlined in green as not found

    • press "ctrl+shit+p" and click on "Edit Configurations"

    • Under the includePath of your matching operating system, add the include
                "name": "Win32",
                "includePath": [
                    "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*",
                "browse": {
                    "limitSymbolsToIncludedHeaders": true,
                    "databaseFilename": ""
    You should now be able to navigate, such as right click and the "Go to Definition" would open the file for you in VSCode

    Before debugging

    Debugging with VSCode (Start is right then got stuck)

    well, haven't we seen this tool somewhere already ? Going back to the ".platformio\packages\tool-stlink" we find all of

    st-flashthe flash utility used with the command line above
    st-inforetrives information (flash, srma,... see help)
    st-utilthis is the magic utility that changes your ST-Link HW+SW into a gdb server
    • run "st-util" from the command window (outside VSCode)
    • From VSCode, click on "Debug" icon or menu, then click on config

    I'm using this configuration

        "version": "0.2.0",
        "configurations": [
                "type": "gdb",
                "request": "launch",
                "name": "Debug Microcontroller",
                "target": "extended-remote /dev/cu.usbmodem00000000",
                "executable": ".pioenvs/bluepill_f103c8/firmware.elf",
                "cwd": "${workspaceRoot}",
                "autorun": [
                    "monitor tpwr enable",
                    "monitor swdp_scan",
                    "attach 1",
                    "load .pioenvs/bluepill_f103c8/firmware.elf"
            "type": "gdb",
            "request": "attach",
            "name": "Attach to gdbserver",
            "executable": ".pioenvs/bluepill_f103c8/firmware.elf",
            "target": ":4242",
            "remote": true,
            "cwd": "${workspaceRoot}"

    With this, you can connect to the gdb server, load the program, but then I failed to step, I got an error, so here's where any help would be appreciated. I think the platformIO are working on an IDE with an integrated debug, well I bet it is the continuation of this process. But with the useful correct configuration that I'm probably missing.

  • ​New mBed Project with PlatformIO command line

    Wassim04/14/2017 at 07:59 0 comments

    Project creation

    • Create an empty directory, here called "test_pio"
    • what I usually do is "right click" "Open with Code"

    • in VSCode I have 3 plugins installed
      • C/C++
      • Native Debug
      • PlatformIO

    Actually, I'm not sure if the PlatformIO plugin is needed here, as I work with the command line, if I open any terminal outside VSCode and I type "pio", I get the help, so one way or another, make sure that opening a terminal in VSCode at least, allows pio to run:

    • Get familiar with the command lines for example by running :
    test_pio> pio boards
    test_pio> pio device list
    Hardware ID: USB VID:PID=0483:374B LOCATION=1-10
    Description: STMicroelectronics STLink Virtual COM Port (COM6)
    Note that the device list should show the STLink if it is connected
    • I'm using a Nucleo-F030 but any other could fit using its ST-LinkV2-1
    • Check lots of wiki on the web on how to connect the BluePill STM32 and don't forget the Reset PIN

    • As you have checked the names in the help boards already the command to start a new project is "pio init --board bluepill_f103c8" which results in the following output
    test_pio> pio init --board bluepill_f103c8
    The current working directory D:\Projects\STM32\platformio\test_pio will be used for project.
    You can specify another project directory via
    `platformio init -d %PATH_TO_THE_PROJECT_DIR%` command.
    The next files/directories have been created in D:\Projects\STM32\platformio\test_pio
    platformio.ini - Project Configuration File
    src - Put your source files here
    lib - Put here project specific (private) libraries
    Project has been successfully initialized!
    Useful commands:
    `platformio run` - process/build project from the current directory
    `platformio run --target upload` or `platformio run -t upload` - upload firmware to embedded board
    `platformio run --target clean` - clean project (remove compiled files)
    `platformio run --help` - additional information
    • One single important file was created (other directories less important) which is the platformio.ini
    platform = ststm32
    board = bluepill_f103c8
    framework = mbed

    The default framework selected was the mbed, but the bluepill_f103c8 is also supported by the arduino

    • create a new file under src called "main.cpp" with this content
    #include "mbed.h"
    DigitalOut myled(PC_13);
    int main() 
            myled = 1; // LED is ON
            wait(0.2); // 200 ms
            myled = 0; // LED is OFF
            wait(1.0); // 1 sec

    Inside of PlatformIO

    Now part of the mystery of platformIO is beeing revealed, if we navigate to where the framework-mbed is we find the rest of the company, and it tells already that the arduino is using the stm32duino, the tool-stlink that we'll see later on,...

    Before compiling, how did the magic of the platformIO got to know the PC_13 that I set for the LED ?


    from which here is an extract, PIOs are defined as enums, and this was done for us by Mr mBed.

    ******************************************************************************* */ 
    #ifndef MBED_PINNAMES_H 
    #define MBED_PINNAMES_H 
    #include "cmsis.h" 
    #include "PinNamesTypes.h" 
    #ifdef __cplusplus extern "C" { 
    typedef enum { PA_0 = 0x00, PA_1 = 0x01, PA_2 = 0x02, PA_3 = 0x03,

    Still before hitting compile, how is the compiler going to know which cpu do we use, on the main, we only included mr mBed. Well that is something done for us by the nice platformIO people here, who leverage the powers of python, and json files for configuration which keep us in familiar environment with the VSCode which configuration is also json, not sure if that's related but that's currently the fashion.

    looking at the file .platformio\platforms\ststm32\boards\bluepill_f103c8.json there is the rest of the magic that's going to help our compiler

      "build": {
        "core": "stm32",

    Read more »

View all 7 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates