Manuals, Timing, Ham Radio, Test Equipment

Help keep this site free:
(More Info)

Blinky++ for the STM32F103C8T6 BluePill

The STM32F103C8T6 is a 32 bit microcontroller of the ARM Cortex-M3 family. 

One thing that makes this device particularly attractive is its low price, full feaure set and the availability of quality, free, unlimited development tools. Small development boards are available from AliExpress (for example) for a couple $ including shipping from China. Along with the low price of the chip itself, ST Micro offers a free development toolset with the Atollic suite (Eclipse based).

Even though the datasheet says the device has 64kB of Flash (the STM32F103CBT6 is the official 128kB variant), I have seen reports that most C8 devices are actually shipped with 128kB of Flash. The chip also has 20k of RAM and a full suite of peripherals (three USARTs, two 12 bit ADCs, I2C, USB, CAN and more. Note that CAN and USB cannot be used at the same time as they share a common interrupt handler and common RAM buffers. Newer chips in that family do not have that limitation.

Since I was looking at an upgrade path from the 8051, and after some frustration with the NXP LPC1769 (particularly the lack of enthusiasm on NXP's part and the relative lack of widespread usage in the hobby community) the ST part looked like a more interesting avenue to pursue. The main reason for upgrading from the 8051 is the availability of double precision floating point variables and math routines on the 32 bit ARM chips compared to the more limited math functions on the 8051.

Even though the F103 runs at 72MHz, it is not necessarily faster at bit twiddling than the 8051, even slower. My BluePill board in a loop can toggle a pin at around 700kHz. A Silabs 8051 running at 25 MHz can twiddle a pin at several MHz. The datasheet says some IOs can be toggled at 18MHz. It seems to depend on the way the internal ports are clocked, some are faster than others. More experimentation is needed to see the practical limitations.

The hardware

The BluePill is a small board with a limited but sufficient amount of resources: 

  • USB connector for power and virtual serial port (I have not used the USB virtual serial port)
  • 8MHz and 32,368Hz crystals
  • Reset button
  • 3.3V regulator
  • A couple of jumpers to select boot mode
  • A 4 pin Debug port
  • Most of the chip's 48 pins are brought out on headers.

I bought my first BluePill with an ST-LINK debug adapter. It is a clone of the ST Micro device of the same name and it is mostly compatible with it, but not 100%. More on this later.

The set of a BluePill board and the ST-LINK clone cost me about $8, shipping included from a US vendor. No need to break the bank for fun experimentation.

The development tools

There are a number of options to start developping with ARM chips. Most are based on Eclipse, the open source development tool developped by IBM, and gcc, the open source compiler suite from the Free Software Foundation. Some are proprietary like Keil and IAR. All are good. Please note that some tools have a free version without support, and a pay for version with support. 

I will mention briefly the Arduino IDE as it does now support a number of ARM chips. Arduino is a lot like Visual Basic was described to me almost 30 years ago. It makes the easy stuff very easy but the difficult stuff impossible. For instance, there is no debugging option with the Arduino IDE. So even though I did verify that my Bluepill board and ST-LINK adapter clone worked with the Arduino Blinky example, I did not go any farther with it.

Aside from Arduino, people on forums get into silly arguments about which tools are better, free or commercial ones but in my opinion the biggest difference between the free tools and those that cost money is support. With free tools, support is also free but not guaranteed. It does not mean support is not available, simply that you cannot ask a question today with a reasonable certainty that it will be addressed (I did not say resolved) in a day or two. With the free tools, you are at the mercy of brave souls on forums such as StackOverflow or the tool publisher's own forums.

Regardless of the tools you end up using, there is a ton of open source software available on sites such as Github. No need to go directly to Github to find software, simply google what you are looking for directly from the browser and if it's on Github, the link will be near the top.

In my case, I elected to install the Atollic suite from ST Micro. Atollic is a respected software vendor that was publising commercial tools (with a free version) for the ST Micro chips and others. ST Micro ended up buying them in 2017 and now they only offer free tools for the STM8 and STM32 families from ST Micro.

A definite advantage of the Atollic/STMicro tools over the equivalently Eclipse based NXP Tools (LPCXpresso) is that the Atollic tools are unlimited in their free version while LPCXpresso is limited in code size. Probably as a result, Atollic software for the ST Micro chips is quite a bit more popular on the Internet than NXP. I have also observed that the NXP libraries often end with while(1); when encountering error conditions while the STM equivalents make extensive use of assert() to catch misconfigurations. A much better approach in my opinion.

Atollic is Eclipse based and it is not a bad thing. For better or for worse, Eclipse pretty much dominates the desktop IDE market and not only because it is free. It is extremely powerful and well debugged. It is as if it had been designed for people who write software. Imagine that...

There is one thing you have to be careful about with Eclipse. Sometimes when setting up a new project, everything starts working and you close shop for the day and close Eclipse. When you restart Eclipse later, it may not show your project or it may display some error message about not finding the .project file. That can be scary, but it is usually related to you moving files or the workspace around, so avoid doing that. It is usually not difficult resetting everything, just go back to the start, the files are still there and it's just a matter of pointing Eclipse in the right direction.

Software installation and first run

Installing the tools from the ST web site takes a while. Anything Eclipse based will be at least 300MB before the compiler itself is downloaded, so don't be in a hurry. I have installed Eclipse based tools on many computers and it has always worked without a hitch.

The tool came with a bare bone project for the STM32F10x series. It compiled without issue but it turns out my cheap eBay ST-LINK "compatible" debug adapter would not work with the Atollic IDE. So not only was I unable to debug directly from within Eclipse as I had been used to with the NXP ARM chips I had used before, I could not even flash the chip.

It turns out ST Micro has a separate suite of tools that include a flasher which works with my ST-LINK adapter. Still no debugging but at least I can load the software. The flasher is part of a larger tool set called the ST Visual Programmer.

You may say that I am no better than with the Arduino since I can't debug but that is not the case. First, I fully anticipate resolving the issue with the ST-LINK adapter. An easy solution may be to buy the full fledged ST-LINK V2 device from ST Micro themselves, which is still pretty cheap (~$20 + shipping). Secondly, compiling and uploading the Arduino Blinky example takes A LONG TIME on the quad core i7 computer with 8GB of RAM I am using now (well over a minute).

On the other hand, my Blinky project under Atollic compiles in a few seconds (maybe 5 when making small changes) and it takes another 5 seconds to switch to the ST flasher window and flash the chip and bingo, you are in business. So when things don't work as intended (when did that happen last with software?) it is much faster to try your changes. It seems the Arduino IDE recompiles everything each time you click Upload while the Atollic tool only recompiles what's changed, but even when recompiling everything from scratch, it is still considerably faster. Not sure what's going on there.

My project

I wanted to build a simple project that has the bits I usually need in my larger projects: GPIO, UART (at least one or preferably two, covering the 9600 to 115,200 range, with Rx and Tx handled under interrupts), a millisecond timer tick, I2C (my typical I2C needs are simple and in many cases I use bit-banged I2C instead of the I2C hardware) and ADC.

I2C is typically used to access a serial EEPROM and  2x16 or 4x20 LCD and occasionally an IO expander like the PCF8574 (also used in the I2C/LCD interface). For those applications, I do not really need the I2C hardware transceiver even though accessing the LCD through such a chip is slow and at times I have been thinking of running the LCD/I2C under interrupts so that the main loop does not need to wait the ~20 to 50mS it takes to refresh a single line of the display.

Some projects use PWM and others (the smaller ones) use internal Flash for parameter storage instead of a serial EEPROM but I can do without those for now on this project.


One issue Ihave come across with ARM development is that even though a lot of stuff is available on the Internet, there are many versions of everything, and most code is published as part of a larger project. In many cases, these larger projects will have much stuff you do not need while missing what you do need, and trying to merge different projects to get the set of features you need will create additional issues. Many ARM projects are written around standard libraries. One of those is CMSIS (Cortex Microcontroller Software Interface Standard) which is a laudable effort by the ARM consortium and a number of ARM chip vendors. However, not everybody uses it and then there are different (incompatible) versions of CMSIS. Other vendors develop their own libraries. When trying to merge projects using different libraries, you will be faced with header file syndrom. It seems that you are always missing another header or another library, each file being necessary for one or two definitions or functions and before you know it, your project has hundreds of header and source files just to run Blinky. On occasion, you will also have conflicting declarations in different files that are even more time consuming to resolve.

Another issue is that the workflow that is usually recommended and that you are guided through when installing projects under Eclipse is that a lot of the code is in libraries that are intended to be common across projects. Everything you do in a workspace is shared among all the projects in that workspace. It is very tempting to create new projects under an existing workspace so that you can share the libraries but I have found that potentially very dangerous. Say you wrote a project a couple of years ago that is working fine. You want to start a new project that would be derived from that existing one, so you create it in the same workspace. You come across an issue that requires you to slightly modify a library file and now your old project does not work. It may even be a bug fix but if it breaks old working code, it is undesirable.

So my preference is to create separate workspaces for different, even related projects and simply import an existing project into a new workspace to get started.

The third issue is tool upgrade. All ARM vendors upgrade their tools regularly. What a change from the 8051where I have used two versions of the C compiler since the erarly 1990's, and the old compiler still works by the way. When you upgrade tools, the upgrade usually includes a new set of libraries which of course sometimes break old code. What do you do if you have to revise an old product and you cannot build it anymore because you upgraded your tools and you get a bunch of errors when trying to compile the old code on it?

There is a reasonable fix for that, taking advantage of the fact that you can have multiple Eclipse installations. When installing a new version, install it in its own directory so that you can keep the old version unaffected, and you can keep the old version to maintain old code. Maker sure you make a reference to the tools used in the old source code and you will be OK.

Rant finished

After quite a bit of frustration setting up the Atollic tool with my Bluepill for the reasons above, I have finally reached partial success.

I have created a standalone project with SysTick based timer under the Atollic tools version 9.2.0 (installed a couple of weeks ago). I can load the project to the Bluepill using the ST-LINK V2 flasher and the ST Visual Programmer v3.4.1. I call this project Blinky++ since it has quite a bit more functionality than the typical Blinky.

I have not been able to debug using my eBay sourced ST-LINK V2 clone but I can flash the chip using the Visual Programmer (Atollic complains it can't "verify ST device", even though the ST-LINK clone works with the Visual Programmer and with the Arduino IDE.)

Installing the project into a new workspace and configuring Eclipse

The project is zipped there:
Simply save the zip file, create a temporary folder anywhere and expand the zip file in it.

Import the project into a new workspace from within the Atollic IDE  as follows:

  1. In the Atollic IDE, click on File->New->C Project
  2. Name the project Blinky and click Finish
  3. Click on File->Import->General->File System then Next
  4. Click on the Browse button and navigate to where you expanded the ZIP file, click on the Test folder and click OK
  5. In the next window, click the box next to the Test project name. In the middle of the window, it will offer to copy the project into your Blinky folder. This is what you want, do not change any option and click Finish. It will ask you if you want to overwrite '.cproject' in folder Blinky. Click Yes to All

You need to tell Eclipse which chip you are using, so click on Project->Properties->C/C++ Build->Settings (a window may pop up saying no settings could be found. Click OK to continue). In the Target Settings tab, select STM32F1->MCU->STM32F103C8 and click OK. It will ask you if it's OK to generate new linker scripts. Click OK to this and the following couple of prompts about saving the build configuration. 

Then you have to tell Atollic where the header files are. Click on Project->Properties->C/C++ General->Paths and Symbols  and update the paths as follows:

  • click on GNU C
  • add src\cmsis, check Add to all configurations 
  • add src\core, check Add to all configurations
  • add src\startup, check Add to all configurations
  • add src\stm32f10x, check Add to all configurations
  • remove the unused folders under Libraries (if any) since there is nothing there (keep the three folders to C:\Program Files\...)
  • click on S,s,asm and add src\startup, check Add to all configurations
  • click Apply then OK

The final setting relates to the pointer targets in passing argument 2 of 'xxxx' differ in signedness [-Wpointer-sign] warning. Mainy library functions expect pointers to signed variables and the warning comes when you pass them pointers to unsigned  variables. This is usually a nuisance so I just turn them off as follows: Project->Properties->C/C++ Build->Settings click on the Tool Settings tab and scroll down to C Compiler->Miscelaneous and enter -Wno-pointer-sign in the Other options box. Click OK

Once that's done, you should be good to go. Make sure you check generating a hex file under Project->Properties->C/C++ Build->Settings->Other->Output format and check Convert build output and select Intel Hex. This will produce an Intel hex file you can use with the ST Visual Programmer.

From this point, your project should build. Click on Project->Build Project and check at the bottom of the Eclipse screen, there are two tabs of particular interest: the Console which tells you if the project built and the Problems tabs which tells you is issues were encountered.

I have pruned the source and header files down to the minimum necessary (I did include most of the libraries for the standard STM32 peripherals under the stm32f10x folder though so that it should be easy to add CAN or ADC for instance) and everything is in a couple of folders in the src folder. The only custom files are main.c, board.c, board.h, misc.c, mish.c and core_cm0.h. I believe (not 100% sure at the moment) that the other files in the build are as I downloaded them from various github locations.

The project blinks the on-board green LED using a counter in the main loop. It also toggles pin B9 at 100mS using the SysTick, which can provide fairly precise timing for your projects. USART1 is suppoorted and there is a bare bone command interpreter you can use with Putty at 9600 bauds (Tx is on pin A9, Rx is on A10). At the moment, only two commands are supported, '0' returns the firmware version and '2' returns the SysClock but it is easy to add more commands to support your project using the model provided.

No ADC or I2C yet, and the UART only has Rx under interrupts, but it is usable, as shown in the screen shot below.

This is what the project looks like with a Silabs UART-USB adapter connected to Putty on the PC:

I also posted the code on the Atollic forum there:

Feel free to register on that forum for comments. The forum is not very active but I would rather not setup a forum on my site just for this project.

Additional notes about using Eclipse

The learning curve using Eclipse is steep but it is worthwhile. The following does not replace a course at the local college or spending time on your own to learn it (my preference), but here are some of the gotchas that got me good because they were different from what I knew of development tools up to that point and assumed normal behavior.

Eclipse normally assumes that all the .c files in the project folder are fair game and will try to compile them all regardless of whether they are used or not. They may not be linked in the final executable if they are not used, so it is not a problem leaving the library files in the project tree for instance. It will take slightly longer to compile them the first time but if you do not touch them, they wont need to be recompiled and it won't hurt anything to keep them.

However, Eclipse will not normally look through all the folders for header files. In the Project Explorer window, above your source folder, there is an Include folder. This folder tells you where Eclipse will look for header files. The paths there are those that are defined for your project (see [1]) but also includes the path to the standard C libraries of the development tools themselves.If you want to create new subfolders for header files, you have to tell Eclipse where to look, either by entering their full path in the files where they are invoked, or by telling Eclipse directly where to look as described above (see [1]).

The default installation of the Atollic tools include a number of paths for header files (those I suggested you delete above). The intention is to have a common location for header files that may be shared between projects. For reasons explained above, I personally prefer to keep separate workspaces for different projects and I have found it easier to keep just the files I need for the project under a simple directory structure. You may prefer a different approach and once you are familiar with Eclipse, you may revert to the more "standard" way of working with it. 

To build your project, right-click on the project name in the Project Explorer and select Build Project.

Eclipse by default supports Debug build and Release build. You may want to include debug functionality in your Debug build that should not be included in the release build, like sending error messages through the UART. To select which type of build you want, simply right-click on the project, Click on Build Configurations and Set Active and select the one you want. If your project compiles under one build configuration and not the other, it may take a little while until you have checked all the settings to find what was different.

Sometimes Eclipse will notify that you have a number of errors or warnings in your code, yet the code compiles and produces a working executable. That may be due to corruption of metadata or an issue with the indexer. Eclipse tries to guess what the compiler will do by analysing your source code before you click Build. It is very powerful and very useful when it works because it can save you a bit of time but sometimes it gets ahead of itself, or steps on its own tail regardless of how you want to put it and gets into that mode. Google will be your friend, there is no magic solution but usually the solutions are not too painful.

Finally, some times the Project->Build Project menu entry is greyed out and sometimes when you right-click on your project, that menu choice may be greyed out. I am not sure what causes that but I have found that they are not usually greyed out together, so if one is greyed out, I use the other one. When they were both greyed out, I clicked Rebuild Project, or Clean Project then Build Project.  I am not sure what causes that but it seems to have no detrimental side effect.

Follow up

I have purchased and received the official ST-Micro ST-LINK/V2 JTAG adapter.

I had to build a cable because it only has a 20 pin ARM socket and the Bluepill needs only four wires. There is a 4 pin connector on the ST-LINK but it is for the STM8 8 bit microcontroller series.

Here is the cable adapter's schematic. I connected the 3.3V pin with the TVCC which the ST-LINK uses to determine the supply voltage to the chip. So even though the ST-LINK does not provide a 5V output, you can use it to flash a 5V powered chip.

Debugging with this is pretty convenient, thanks to Eclipse. The debugger also has a steep learning curve that is well worth it.

Code size of STM32 compared to 8051

I have completed the conversion of an entire project that was running on a Silabs C8051F587 chip to the STM32F103C8T6. At the moment, the features are the same, I have not taken advantage of the STM32 chip's double precision math features. The code size on the 8051 was about 20k and it is about 50k on the STM32. Your mileage may vary.

I was disapointed to find that the "small" library that comes with the Atollic tools (newlib-nano) does not support any floating point printing through printf(). To get floating point printing, even single precision, you need the "full" library (newlib standard,) also provided of course (go to Projects->C/C++ Build->Settings->General->Runtime Library). This added a large chunk of program flash to the needs of the project.