Launched in 2007, the STM32 range of microcontrollers from STMicroelectronics feature a 32-bit Arm Cortex-M core (Cortex-M0, Cortex-M0+, Cortex-M3, Cortex-M4, Cortex-M7, or Cortex-M33) flash memory, static RAM, debugging interface, and various peripherals. These powerful microcontrollers can be found as the 'heart' of a number of development boards, which will be covered on this page, giving the user a lot of processing power in small form and at low cost.
Please see the following video for a more detailed introduction to STM32 and a brief look at a few of the boards available:
You can email me at james.boshikoopa@gmail.com
New: STM32VLDISCOVERY MB913C (5/2/25)
STM32 Arduino Minimum System Development Board (28/9/24)
Read on to learn about various STM32 development boards I have come across as well as projects to get to grips with the STM32 family.
Images on this page can be downloaded from the bottom of the page for better viewing.
Development boards featuring STM32 microcontrollers give the user a deep dive in the world of electronics, and take away some of the difficulty in getting that first foot on the ladder. From the basics like blinking an LED, to responding and logging data from sensors, to communicating with devices over Wi-Fi, the possibilities are almost limitless. Each development board will have a range of features for the user's convenience, not just from what the microcontroller itself offers (speed, memory, I/O, etc.), but also the components included on the board, such as lights, switches, sensors, displays, and so on.
If you are interested in making your own STM32 based board please see the Build a development board section.
I bought this board back in 2018 from eBay for about £3, advertised as 'STM32F103C8T6 ARM Cortex M3 STM32 System Development Board Arduino mbed' but wasn't aware at the time that it was more commonly known as the 'Blue Pill' (due to the board's colour). Unfortunately, I didn't add my experiences of the board to my site when I first got it and I've lost my original notes, so now I've returned to the board I've had to do so afresh, although I do recall first time round I had some difficulty getting the board to work. Unfortunately, second time round I also had difficulty despite eventual success and at least I've now publicly documented my experiences.
There is no brand or model identification on the board (at least on mine) except 'STM32' near the microcontroller, which is a STM32 F103C8T6 (Arm Cortex-M3 based), it appears to be a genuine part but some boards do have a fake part. Please see:
https://github.com/keirf/greaseweazle/wiki/STM32-Fakes
Along both long edges are 20 labelled connections for I/O and power of which headers can be soldered to (in my case two yellow headers were supplied, which I soldered to the board).There is a micro USB port located on one of the board's short ends, and a single 4-way black header on the other end, which has the pinout labelled on both sides of the board. Near the micro USB are x2 3-way yellow headers, both labelled 0 on the left and 1 on the right, and BOOT0 above the top one, BOOT1 below the bottom one, with a jumper fitted on each one. Under those headers is a reset switch. Toward the other end to the left of the black header is a PWR LED and PC13 LED (user LED, similar to the 'L' LED on an Arduino).
Please note that some Blue Pill boards have USB-C and other features different from the original incarnation that I have.
Because I thought it would be the easiest way to program the board and as I assumed I had done so before, I tried to use the Arduino IDE to program it. To be able to use the Arduino IDE you need to install STM32 via the Boards manager, as outlined on this site:
Once that is done you can select the board in the Arduino IDE (note: I'm using Arduino IDE V2.1.1): Tools->Board->STM32 MCU based boards->Generic STM32F1 series. Also set the Board part number (Tools->Board part number...). For example, I selected 'BluePill F103C8'. Set USB support to CDC (generic "Serial" supersede U(S)ART) (Tools->USB support) and Upload method to HID Bootloader 2.2 (Tools->Upload method). Remember to also set the port (Tools->Port). Oddly, when I plugged in my board, Windows detected it as 'Maple' (incidentally, there are other Cortex-M3 based boards with that name), and COM11.
When I opened up the Blink example (File->Examples->Basics->Blink) and tried to upload it I got the error:
Failed uploading: uploading error: exit status 1
Despite it going through the motions. So possibly the Arduino bootloader isn't present on the board and I needed to put it on it. I found that there are some Blue Pill boards that already have the Arduino bootloader preloaded so it's important to check that when buying one if your intention is to use it as an 'Arduino'. However, we can put the Arduino bootloader on the board, such as by following this tutorial:
https://microcontrollerslab.com/program-stm32-blue-pill-through-usb-port-bootloader/
I had a number of USB-TTL serial converters and the one I used showed up in the Windows Device manager as 'Silicon Labs CP210x USB to UART Bridge'. I first tested it before even connecting to the Blue Pill by putting a shunt on TX ad RX and then plugging the converter into the computer's USB. Using PuTTY I selected 'Serial' and entered the COM port number of the converter in the 'Serial line' box and clicked the 'Open' button. Typing caused the characters to appear in the window and the data LED to flash on the converter board, suggesting it was working.
So I moved on with the tutorial. Note that the STM32 Flash loader that the tutorial says to download has been replaced with STM32CubeProgrammer and since I had already downloaded it I tried to use it instead but it wouldn't detect the target and I also had same problem using STM32 Flash loader. It turns out the issue was with the USB to serial converter so I tried my Prolific PL2303 but on Windows 10 it shows in the device manager as 'phased out' and is unusable. However, I followed these instructions:
And the converter now works although restarting my computer will likely revert it back to the previous driver.
Continuing with the tutorial: don't forget to set BOOT0 to the '1' position before programming the bootloader and put back to the '0' position before plugging it back into your PC. However, even with the bootloader now installed on the Blue Pill, it still failed to upload an Arduino sketch. I tried by chance setting the Upload method to 'Maple DFU Bootloader 2.0' and Windows suddenly detected the board as 'BluePill F103C8' and when I tried uploading the sketch again it worked. Note: for me, the Blue Pill didn't show up as 'Maple Mini' in the Arduino IDE as the tutorial suggests.
Oddly, although the Arduino IDE reported that it couldn't reset the device after uploading the sketch, the LED (PC13) was blinking as expected. Note that the blink sketch uses LED_BUILTIN but I didn't need to alter it to 'PC13' as the tutorial says to do. Note also that PC13 is connected to 3.3V via a resistor rather than to GND, so turning the pin on (high) will turn the LED off, not on as with a typical Arduino's on-board 'L' LED.
My second STM32 board, the Nucleo-64 (NUCLEO-C031C6) from STMicroelectronics, was purchased from Mouser in 2023 for £8.46 ($10.65), and packs a lot for the small price. Note that while there are variations of the Nucleo-64, each offering different features, the focus will be mainly on the NUCLEO-C031C6. The board uses a STM32C031C6 microcontroller with features including:
Arm Cortex-M0+ 32-bit core running at 48MHz.
12KB SRAM
32KB flash program memory
45 I/O and a number of common interfaces (I2C, SPI, USART)
12-bit ADC
RTC (Real-Time Clock)
My Nucleo-64 came in a small brown box and as well as the board itself there was a leaflet with a QR code linking to the technical information, resources, etc. The link is:
www.st.com/en/evaluation-tools/nucleo-c031c6.html
Here are some useful links...
Datasheet for the various Nucleo-64 boards:
https://eu.mouser.com/datasheet/2/389/en_DM00105918-1501215.pdf
User manual for the NUCLEO-C031C6:
https://www.st.com/resource/en/user_manual/um2953-stm32-nucleo64-board-mb1717-stmicroelectronics.pdf
Schematic for the NUCLEO-C031C6:
The board features both Arduino (Uno V3) compatible I/O pins in the form of the familiar female headers (which also extended downwards from the board's underside) and a new standardized ST connector (Morpho) via male connectors on the board's edges and also extend downward, giving access to all I/O available from the microcontroller. Considering the Nucleo-64 is about half the price of an Arduino Uno but much more powerful you can see how good value it is, however, there is one thing to keep in mind. The Nucleo-64's I/O pins operate at 3.3V, unlike Arduino Uno's I/O which run at 5V, and although most of the Nucleo-64's I/O pins are 5V tolerant (marked with ‘FT’ in the STM32C031C6 datasheet) they won't output more than 3.3V, which may cause incompatibility with some Arduino shields.
Most Arduino shields designed for the Uno should fit the Nucleo-64 board and the hats on the on-board buttons can be removed to avoid getting in the way of an attached shield.
The board has four LEDs which are for USB communication (LD1, red/green), over current (500mA) warning (LD2, red), powered by 5V source (LD3, green), and user/Arduino (D13) LED (LD4, red). Additionally, there are two push buttons, USER (B1) and RESET (B2).
Here’s a guide if you want to use the board with the Arduino IDE:
https://www.instructables.com/Quick-Start-to-STM-Nucleo-on-Arduino-IDE/
Since I didn't already have the IDE installed on the computer I wanted to use I went with the newest Arduino IDE at the time V2.1.1. Following the guide, everything was in the same place in the new IDE but when I got to the part where you need to install the STM32 Core board the IDE warned that it was deprecated and advised to install a new package index. You can't copy and paste it from the window but for your convenience here is the URL I had to manually copy:
https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
Then I continued with the tutorial and installed the 'STM32 MCU based boards' V2.6.0 since that includes my board. When I plugged the board into my PC via the micro USB, Windows detected it and installed it. Interestingly, the board shows up as a removable storage drive (E: on my computer) having 104KB of 124KB free, formatted as FAT. On the drive are 2 files, DETAILS.TXT and MBED.HTM. With the board plugged in and installed, LD1 is lit red, LD3 is lit green solid and LD4 blinks rapidly (the preloaded 'blink' example, it would appear).
In the Arduino IDE I chose my board using Tools->Board->STM32 MCU based boards->Nucleo-64 and set the port it's connected to using Tools->Port. Selecting Tools->Get Board Info returned with the board's VID, PID and SN (BN unknown). The examples for my board, found at File->Examples-> and listed under Examples for Nucleo-64 were complicated, so I avoided them for now and went with the simple blink example. It uploaded very quickly, and the IDE reports there is 32768 total bytes for program storage and that it uploaded on NOD_C031C6 (E:). LD1 goes red when uploading a sketch. However, after the sketch uploaded, no LED on the board was blinking. However, I tried the IWDG_Button example (IWatchdog->IWDG_Button) and that worked. It demonstrates the use of a watchdog, blinking LD4 a few times every 10 seconds if the user button isn't pressed. I tried the simple blink example again and now it was working, so I'm not sure what went wrong there.
I got this so-called 'STM32 Arduino Minimum System Development Board' from PCBWay effectively for free during their 10th anniversary in which they were giving away beans. I spent 360 beans to buy the board, currently on PCBWay's site it sells for $3 (£2.24). The product page is:
The board looks somewhat similar to the Blue Pill (see Blue Pill section) but with a different arrangement of components and a black PCB, searching online some people call similar looking boards to the one I bought 'Black Pill', but according to this site the actual Black Pill is quite different:
https://stm32world.com/wiki/Black_Pill
Confusingly, on the previously linked to PCBWay page it states:
"There are parts CH32 CHIP board,if you need STM32F103C8T6 please make a note"
But yet the board uses a STM32F103C8T6.
The board I received came with two 20-pin male headers. On the top side of the PCB we have:
Micro USB connector
BOOT0 and BOOT1 3-way male headers with shunts
RESET button
STM32F103C8T6 Arm 32-bit Cortex M3 with 64Kb flash 20KB SRAM
8MHz crystal
C2KC56BS 32kHz oscillator
Red PWR LED and green PC13 LED
4-way male header for programming/debugging, the pinout is on the underside (3V3, SWIO, SWCLK, GND)
‘STM32’ is written near the IC
When I plugged the board into my laptop running Windows 11 it said 'the USB device has malfunctioned'.
I downloaded and installed STM32CubeProgrammer from:
https://www.st.com/en/development-tools/stm32cubeprog.html
You will need to log in/create an account, installing the software also installs drivers as well as well as STM32CubeProgrammer but I still got the same USB error.
I found this tutorial for using the board with the Arduino IDE:
https://www.instructables.com/How-to-Program-STM32F103C8T6-With-ArduinoIDE/
You need to move the BOOT0 shunt to position ‘1’, which is supposed to put the STM32 into DFU mode but when I plugged the board in I got the same USB error as before.
Next, I tried an approach that I used on my own STM32 board I made (see the Build a development board section), following this tutorial to use a Nucleo-64 board (NUCLEO-C031C6) as a programmer for the STM32:
https://time4ee.com/articles.php?article_id=101
Note that BOOT0 and BOOT1 need to be in ‘0’ position. There is no NRST on the STM32 board.
I opened up STM32CubeProgrammer, in the drop-down to right of the window it has ST-LINK selected, clicking the Connect button successfully connected and the memory was shown as all FFs, suggesting there was no firmware. I selected CPU (MCU Core) from left of the window, it responded to the various buttons (Halt, Run, etc.). On the registers page I selected STM32F103 and it displayed the various register values. This is a good sign that the MCU works and is genuine (some fake STM32s cant be debugged, apparently), there just isn't any firmware loaded. Looking online there was confirmation that STM32 boards won't be detected by an O/S as a USB device if the STM32 isn't running firmware, since the USB is provided by the STM32 rather than an additional, dedicated, chip.
I then clicked the Disconnect button and switched to the Arduino IDE and opened the example Blink sketch. I set the board to 'Generic STM32F103C series', port to the Nucleo-64 COM port, left variant at default (64K), upload method to STLink. When i tried to upload it complained about Java not being recognised so I closed the Arduino IDE, installed Java and opened the IDE and the Blink sketch again, making sure the settings where as previously selected. Although it successfully uploaded, the PC13 LED wasn't flashing. I changed LED_BUILTIN to PC13, uploaded again but still no flashing LED.
I closed the arduino IDE and in STM32CubeProgrammer I connected again, I went to the Memory & File editing page and clicked the Read button and it was still blank. As a test, I clicked on the Read drop-down, selected Fill memory, and changed Size (bytes) to 0x10, and clicked the Fill memory button. It responded with ‘The filling memory operation achieved successfully’ and it showed 0’s on the first row. I clicked the Read button and the zeroes remained, so clearly there was communication with the STM32.
Looking online it seems that the issue may be that it was the wrong hardware selection - the suggestion was to use BluePill F103C8, which wasn't available as an option in the Arduino IDE (at least not for me). So I installed a different STM32 board, one I had used previously for the Nucleo-64:
Use following URL for the Additional boards manager URLs (File->Preferences…):
https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
Then I called up the boards manager (Tools->Board->Boards Manager…), searched for STM32 and installed 'STM32 MCU based boards by STMicroelectronics'. I opened up the Blink example and set the board to Generic STM32F1 series, Board part number to BluePill F103C8, Upload method to STM32CubeProgrammer (SWD). I also set the port number to the Nucleo-64 COM port. Note that if you hover over LED_BUILTIN in the Blink sketch it comes up with #defined as LED_GREEN, which matches the actual board.
After uploading the green LED was flashing.
Back in STM32CubeProgrammer and connecting to the board via the Nucleo-64 it showed that the program memory now contained actual data. When the Nucleo-64 is connected, the LED on the PCBWay board no longer flashes as the MCU is halted. Going to the CPU (MCU core) page, clicking Run caused the blinking to resume. Of course we can use the Halt button, as well as Step, and continue the program by clicking Run.
After disconnecting the board from the Nucleo-64, I plugged the PCBWay board into my laptop and the green LED was flashing as before but Windows still said it was an unrecognised USB device. It is possible to put the Arduino bootloader on the STM32 so that the board can be programmed through USB rather than using an ST-LINK programmer (such as provided by the Nucleo-64). However, I’ve only done that by following a tutorial using a USB to UART adapter, which would require soldering the header pins. Perhaps it's possible to put the bootloader on via ST-LINK but for now I know the board works.
I came across the STM32VLDISCOVERY Discovery kit board from an eBay joblot but as of 2025 the board is still in active production, selling for $10.32 (£8.24). The particular version I got is MB913C, with MB913 it would appear being the model number and the 'C' being the revision, there is at least also a MB913B revision.
The product page can be found at:
https://www.st.com/en/evaluation-tools/stm32vldiscovery.html
It has a brief specification:
STM32F100RBT6B microcontroller, 128 KB Flash memory, 8 KB RAM
On-board ST-LINK with selection mode switch to use the kit as a stand-alone ST-LINK (with SWD connector)
Designed to be powered by USB or an external supply of 5 V or 3.3 V
Two user LEDs (green and blue)
One user push-button
Extension header for all QFP64 I/Os for quick connection to prototyping board or easy probing
By clicking on the Documentation page you will find various downloads, the 'UM0919 STM32VLDISCOVERY STM32 value line Discovery' User Manuals is a very good place to start and has schematics starting on page 19, you can also find schematics downloadable from the CAD Resources tab on the product page.
Page 5 of the user manual shows the layout of the various components of the board, of which I've summarised the LEDs and buttons below:
LD1 (red) COM indicates communication between PC and ST-Link.
LD2 (red) PWR indicates that the board is powered.
LD3 (green) PC9 connected to I/O PC9.
LD4 (blue) PC8 connected to I/O PC8.
B1 USER connected to I/O PA0
B2 RST connected to STM32 reset.
On page 10 we can see that to use the on-board ST-Link the CN3 jumpers need to be on, to use ST-Link for external applications through CN2, the CN3 jumpers must be off.
On page 3 it has getting started information:
1.Connect the STM32F100 Value line discovery board to a PC through an USB cable to power the board.
2.Press the user button B1 (on bottom left corner of the board).
3.Observe how the green LED LD3 blinking changes according to user button B1 clicks.
4.Each click on User button B1 is confirmed by the blue LED LD4.
It then goes on to say visit www.st.com/stm32-discovery, download the getting started documentation and STSW-STM32078 (free software examples). I found STSW-STM32078 at:
https://www.st.com/en/embedded-software/stsw-stm32078.html
Which I downloaded - you need to log in or provide details to get the link to the software. After extracting, I double-clicked Release_Notes.html, which opened a browser page giving an overview but no instructions as such. It looks like to use the examples you need to open the projects. So I went to the documentation:
https://www.st.com/en/embedded-software/stsw-stm32078.html#documentation
And downloaded 'AN3268 STM32VLDISCOVERY firmware package'.
In the 'Package structure' section of the user manual it says to download the STM32vldiscovery_package from http://www.st.com/stm32vldiscovery, the STM32vldiscovery_package is contained in STSW-STM32078. Although the PDF explains what each demo does it doesn't say how to open or run them. If you look at one of the examples, such as GPIOToggle (en.stsw-stm32078\an3268\stm32vldiscovery_package\Project\Examples\GPIOToggle) you will see a readme, which explains how to use the example by creating a new project and adding the necessary files.
I downloaded STM32CubeIDE as it seemed compatible with the board, which you can get from:
https://www.st.com/en/development-tools/stm32cubeide.html
I downloaded the Windows version (STM32CubeIDE-Win) V1.16.1, the most recent version at the time, and after installing, I launched the app.
I created a new project by going to File->New->STM32 Project. In the Target Selection window I clicked the Board Selector tab, then clicked Discovery Kit check box under type, STM32F1 under MCU / MPU Series, which left one board listed: STM32VLDISCOVERY with Mounted Device STM32F100RBT6B. I clicked on the board in the Boards List and you will see the board appear in large form above with the spec. I clicked the Next button, and entered a project name, I left the options at default (C/Executable/STM32Cube), and clicked the Finish button. A Board Project Options box popped up asking 'Initialize all peripherals with their default Mode?', I clicked the Yes button. Then there was another pop-up, this one asking 'Device Configuration Tool editor is associated with Device Configuration Tool perspective. Do you want to open this perspective now?'. I didn't know the correct answer so I clicked the Yes button.
A pop up appeared 'User Authentication Manager' asking to log in to download a software package. I clicked the OK button and then a 'Code Generation' pop-up appeared saying that 'Code generation could not be done most probably because the necessary firmware package is missing. Not able to complete STM32Cube project creation. See Firmware Updater for settings related to firmware package installation'.
I found a solution:
"1) From this page https://www.st.com/en/embedded-software/stm32cubef4.html download two zips (STM32CubeF4 and Patch-CubeF4)
2) Unpack first en.STM32Cube_FW_F4_V1.24.0.zip to Repository folder
3) Then unpack en.patch_cubefw_f4.zip to the same folder with file replacement"
Note: the versions I downloaded were newer versions.
It wasn't specified whether I needed to close STM32CubeIDE but i did anyway.
Note: Repository folder should be located at C:\users\yourname\STM32Cube\repository where 'yourname' is your computer account name.
The first one I extracted was en.stm32cubef4-v1-28-0.zip but the Windows File Explorer's built-in extractor crashed File Explorer so I had to use 7-Zip. Next I extracted en.stm32cubef4-v1-28-1.zip. I then reopened STM32CubeIDE and I tried creating the project again with a new name but it failed in the same way. The solution was simple - I just needed to log in to my ST account within STM32CubeIDE, which you can do using the menu option to the right of the Help menu. I created the project again and it succeeded. Note that you can have multiple projects in a single workspace so I removed the other projects.
In the image below you can see the project open in STM32CubeIDE showing the 'Device Configuration Tool perspective':
I tried building the project just to make sure there were no more complications using Project->Build All. If it pops up 'This file extension is associated with C/C++ perspective. Do you want to open this perspective now?', click the No button.
It built without errors, producing GPIO_test.elf (used for debugging). I tried copying over the contents of main.c from GPIOToggle (from the download) to the project, replacing what was already there, but I couldn't get it to build due to errors. I fixed the errors but doing the following:
Project->Properties
C/C++ Build->Settings
Under Tool Settings select MCU/MPU GCC Compiler->Include paths
Click Add... under Include paths (-I)
Navigate to:
en.stsw-stm32078\an3268\stm32vldiscovery_package\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
Click OK button.
Add again but for en.stsw-stm32078\an3268\stm32vldiscovery_package\Utilities
Which will fix missing headers stm32f10x.h and STM32vldiscovery.h
However even after doing that there were still lots of other errors complaining about undeclared functions which I couldn't resolve, so I reverted to the original main.c contents. I had to do some digging online but to simply toggle LD4 on/off I put the following code in the while (1) loop in main():
HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);
HAL_Delay(500);
Which built without problems using Project->Build All.
When I plugged the board into my PC the PWR (LD2) LED came on, and the green and blue (LD3 and LD4) LEDs flashed in turn. The board showed up as a 30.9MB write protected drive in Windows containing 3 HTML files (which look to be help files).
Then it should be a matter of going to Run->Run but it came up with error: 'No ST-LINK detected!". I made sure the CN3 jumpers on the board were fitted so it uses the on-board ST-Link.
It looks like the issue is the board uses ST-LINK V1, which isn't supported by STM32CubeIDE. I found this out because I opened STM32CubeProgrammer and it popped up the 'not supported error'. If you really wanted to debug, you could use alternate software, such as IAR, although that only has a free trial. For a product that’s still ‘supported’ it’s a set back not be able to use a standard feature with a current IDE.
Googling confirmed the issue and I came across:
https://community.st.com/t5/stm32-mcus-boards-and-hardware/does-it-support-st-link-v1/td-p/369026
You can still perform "flash and run without debug" with ST-LINK V1 in STM32CubeIDE using ST-LINK_CLI.exe utility, check this thread:
Here's what the site says to do:
"install st-link utility
in stm32cubeide open Project→ Properties→ C/C++ Build→ Settings→ tab "Tool Settings" → MCU Post build outputs check "Convert to Intel Hex file"
in Run → Debug Configurations double-click on first line "C/C++ Application" to create new configuration. Under the tab "Main" set "C/C++ Application" to C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe, under the tab "Arguments" set "Program arguments" to -c SWD -P ${project_loc}\${config_name:${project_name}}\${project_name}.hex -Rst, under the tab "Common" check "Display in favorites menu" – "Run"
in Window → Preferences → General → Keys set Command "Run" Binding to Ctrl+F11
Now after writing some code you can perform build and run by pressing Ctrl+B and then Ctrl+F11. It is very convenient, because you do not need to open st-link utility manually, "flash and run" is performed by pressing Ctrl+F11 hotkey without leaving CubeIDE."
As for STM32 ST-LINK utility you can get it from:
https://www.st.com/en/development-tools/stsw-link004.html
Although I followed the instructions previously mentioned, when I pressed Ctrl+F11 it still complained 'No ST-LINK detected!".
So I opened the ST-LINK utility, plugged in the board and clicked Target->Connect, which was successful. Now the board's PC8 LED was on solid and the COM LED was perodically flashing. The utility reported:
19:56:01 : ST-LINK SN : ST-Link/V1_on_E:
19:56:01 : V1J11S0
19:56:01 : Connected via SWD.
19:56:01 : Connection mode : Normal.
19:56:01 : Debug in Low Power mode enabled.
19:56:01 : Device ID:0x420
19:56:01 : Device flash Size : 128KBytes
19:56:01 : Device family :STM32F100xx Low/Medium density Value Line
I went to File->open File... and selected the .hex file in the Debug folder of the GPIO test project set up in STM32CubeIDE.
Then I did Target->Program... and clicked the Start button on the pop-up. It reported it had programmed in 578ms.
I then disconnected using Target->Disconnect but the LED wasn't flashing as I had programmed. It turns out I had managed to remove the toggle code from the while (1) loop, so I put it back in and built again.
Using the ST-LINK utility I programmed the (now updated) hex file again and PC8 LED was now flashing.
So STM32CubeIDE can indeed be used to create and build projects for the board and the ST-LINK utility can be used to program the board. The ST-LINK utility does have some very basic debugging features too. But using a different IDE would be another potential solution to having to use separate programs to build, program, and debug. Of course, for simple tests it may be enough just to flash the board without debugging.
Although I had already had experience with a number of STM32 development boards I thought it would be a worthwhile project to make my own, especially after I bought from Temu two STM32F030F4P6 chips for £2.38 ($2.96). Granted, I could get the chips for £1 ($1.24) each from RS electronics but there was a minimum order of 100, Mouser had them for 80p ($0.99) each with no minimum order but you need to spend £30 ($37.27) to get free shipping, whereas Temu requires £15 minimum spend but due to the price dropping after purchase I ended up getting it even cheaper (Temu didn't give an exact breakdown as there were multiple items that lowered in price since I bought them but effectively I got one chip for free). Of course, there was the risk that the chips from Temu could be fake, even with the single (positive) review at the time of buying them, but having received and tested them they appear to be genuine and working.
Here is a link to the chip's datasheet:
https://www.st.com/resource/en/datasheet/stm32f030f4.pdf
And a brief summary of the IC's specification:
32-bit Arm Cortex-M0 CPU 48MHz maximum.
16KB flash.
4KB SRAM.
12-bit ADC (9 external channels, 2 internal).
RTC calendar/alarm.
15 GPIOs.
x1 I2C/x1 USART/x1 SPI.
Serial wire debug (SWD).
The chip's package is TSSOP20 and measures just 6.5mm x 6.4mm, and each pin is 0.3mm wide, so not breadboard or prototype board friendly. Fortunately I had purchased some TSSOP-20 adapter boards to convert between the SMD footprint to the much easier to handle through-hole 2.54mm standard. If you plan to do a similar thing yourself but don't have much experience with SMD I recommend researching different SMD soldering techniques and practising on some cheap ICs first. However, I'll go through how I soldered the chip:
What I did was clean the adapter board with isopropyl then added liquid flux to the chip pads, then using a soldering iron with small bit I applied solder to the chip pads, ensuring any shorts were removed. Next I soldered male headers to the adapter board underside using breadboard to hold them in place while I soldered (once you have finished soldering, the adapter board is in the breadboard ready to be tested). The most difficult part was next: holding the chip with tweezers while I heated one corner pin to solder it - it really helps to have steady hands and use a microscope which indeed I used. After soldering the opposite corner pin I used flux across the pins and soldered each pin individually at the point where the pin touches the pad. Once all the pins were soldered I checked for continuity and shorts and removed any bridges I found.
I have put together a schematic of the circuit I used initially on breadboard with the intention to solder to a prototype board.
As you can see the circuit is fairly simple, the STM32 (U1) is powered off 3.3V, a switch (SW1) selects the boot mode (which can just be a 3-way header with a shunt), and an LED (D1) gives conifrmation that power has been applied. NRST has an internal pull-up but a capacitor (C3), as recommended in the IC datasheet, helps prevent false trigerring of the reset line. Because the STM32 can run off either an internal or external timing element the intention is that an external resonator or crystal can be plugged into connector J1 but if the internal clock is used then PF0 and PF1 are free to be used as GPIO. Because a typical resonator has the necessary built-in capacitors it's more convenient than a crystal, which would require external capacitors to be added but a crystal has the advantage of being more stable than a resonator. The various GPIO, power, and RST can be routed to headers.
When I was first testing the STM32 I powered the circuit using a Waveshare PL2303 USB UART module with its VCCIO shunt set to 3.3V, allowing it to provide 3.3V on the VCCIO pin and operate as a 3.3V UART device; as well as powering the STM32 it also communicates with the chip. I plugged the PL2303 module into my Surface Pro and then opened STM32CubeProgrammer, making sure the Port selection in UART configuration was set to the PL2303 module COM port (plugging it in after the app is opened means it can't be selected). I didn't change any of the default settings which are 115200 baud, parity Even, RTS 0, DTR 0. In the log window I saw some promising info:
Activating device: OK
Chip ID: 0x444
BootLoader protocol version: 3.1
In the RM0360 Reference manual:
It says the Chip ID should be 0x444 for STM32F030x4, so it appears to be reading correctly from the chip. However, in the STM32CubeProgrammer log window I also got:
Warning: Device is under Read Out Protection
Response received from device: NACK
Error: GETID command not acknowledged!
Reemission of GetID command
Disconnected from device.
This also happens if I clicked on the Read button. It's also odd it says GETID not acknowledged even though it got the chip ID.
I tried using a lower baud (9600) but that made no difference. I also tried uploading using the Arduino IDE, with Board set to Generic STM32F0, Board part number: STM32F0 Demo board (HSE 8MHz), Upload method: STM32CubeProgrammer (Serial) but got the same error Warning: Device is under Read Out Protection.
Please note:
HSE=high-speed external clock.
HSI=High-speed internal oscillator.
Next, I followed this guide for using the Nucleo's on board ST-link programmer with an external STM32 board:
https://time4ee.com/articles.php?article_id=101
Using STM32CubeProgrammer I could access the MCU core page, Run, Halt, and Reset. If I did halt, I could step, and I could see registers change such as the PC. But if I clicked Read Core Reg it got stuck, although I could do other operations. On the Option Bytes page clicking Apply or Read never completed. All this was tested with Boot0 (pin 1) connected to 3.3V. ST32CubeProgrammer shows in the target information panel (see below) that the device is STM32F03x, device ID is 0x444, Rev 1.0, 16KB flash, Cortex-M0, bootloader version 0x10.
Looking into the read issue further I came across this post:
Which explains that you only need to put the microcontroller into bootloader mode if you're going to program it over the UART, using the bootloader. Generally speaking, you can program the microcontroller over SWD at any time - SWD or Serial Wire Debug is the interface being used between the Nucleo and the STM32.
I had done the basic checks, making sure the STM32 was getting 3.3V on VDD and VDDA, referenced to GND. I found it odd that I could interact with the STM32 using STM32CubeProgrammer only when boot0 was connected to +3.3V, not 0V, I did also try using a resonator connected to the STM32 and boot0 connected to GND but could not halt the CPU nor step through it like I could when boot0 is connected to +3.3V, but that may be because the flash was empty.
There was also the possibility the chip was fake but its markings matched up with images of the same chip found online and it read back the correct chip ID. I even looked at the chip under UV light and didn't see anything suspect. Of course it's possible I could have damaged the chip during soldering or the possibility that the chip was a factory reject and only partially working.
The fix I found while looking online was to do the following:
In ST32CubeProgrammer I clicked on the Option Bytes shortcut at the side, expanded Read Out Protection, changed the RDP value from 0 to AA (Level 0, no protection) and clicked Apply, which was successful. I then went to Memory and file editing, clicked Read and it successfully read in the memory (address set to 0x8000000), which was blank as expected (all FFs). Considering I couldn't read before, it seems the read issue was fixed. How the protection option got set in the beginning is a mystery.
Note: this was with boot0 at GND.
I unplugged the board, plugged back in, clicked Connect and this time no read error popped up. Also, under Option Bytes, clicking on Read worked whereas before it had hung. The only odd thing is LD1 on the ST-link part of the Nucleo kept flashing red fast while ST32CubeProgrammer is open, which it did before and I assumed was due to not being able to read from the MCU. Apparently it could be a driver issue but it works as intended so doesn't appear to be a problem.
Now that I had removed the read issue I tried programming using the Arduino IDE to allow programming with minimal difficulty. I opened the Blink example (Basics->Blink), hovering over LED_BUILTIN I could see it was set to PA4, so I connected an LED with limiting resistor (I used 1K) from PA4 (pin 10) to GND. Note: boot0 set to GND.
I had saw online that it was recommended to use the 'underscore' versions of the pins, e.g. PA_4, and that is what I have used mostly but with a bit of experimentation I have worked out the full details. It appears that the underscore and non-underscore versions can be used interchangeably when a pin is used as an analog input, example both PA0 and PA_0 work. But an analog capable pin when used as a digital input or output must use the non-underscore version, example PB_1 won't work but PB1 will. For digital only pins, either version can be used with the exception of PF0/PF1; PF_0/PF_1 don't work.
In the IDE I set board to STM32 MCU based boards->Generic STM32F0 Series and Board part number to STM32F030F4 Demo board (HSI internal RC oscillator), and Upload method to STM32CubeProgrammer (SWD). I connected the ST-link to my Surface (the PA4 LED was on), and in the Arduino IDE set the port number appropriately and clicked Upload. After compiling and uploading, the PA4 LED was flashing as expected. In the IDE output I could it had correctly detected the ST-link as NUCLEO-C031C6, Blink.ino.bin is opened and parsed from 0x08000000, and the program is run from address 0x8000000.
I closed the IDE and opened STM32CubeProgrammer, clicked Connect and it did an automatic read and displayed memory contents from 0x08000000, which not surprisingly weren't blank. The PA4 LED was now off so perhaps the CPU was automatically halted. Going into the CPU section, clicking the Run button causes PA4 LED to continue blinking. We can click the Halt button and the LED will stop blinking, we can click the Step button and watch the PC value change (see image below). We can click Run again to resume blinking.
The next test was to try another I/O pin, this time, PA5 (pin 11), but also to try out toggling the pin at a different speed (which any GPIO should be suitable for). I modified the Blink example to use PA5 but removing both delays to toggle the pin on/off as fast as possible. Using digitalWrite() is slow but an easy way to do the test. Using my multimeter set to frequency on the PA5 pin and GND I got a reading of 220.6KHz. I then programmed the STM32 again but this time I set the Board part number to STM32F030F4 Demo board (HSE 8Mhz) and connected an 8MHz resonator, pins 1 and 3 to STM32 pins 2 and 3, resonator pin 2 to GND. After uploading the sketch again (since I changed from internal to external clock) I got a frequency reading of 223KHz, which wasn't much faster than the using HSI. This appears to be because the default internal RC oscillator is 8MHz and that's what the board part number STM32F030F4 Demo board (HSI Internal RC oscillator) uses. The advantage of using the internal oscillator is that it frees up two GPIO pins but the internal oscillator isn't as stable not accurate as using external quartz crystal/resonator.
For faster speed toggling we could use the digitalWriteFast library (don't forget to install it if you don't already have it):
#include <digitalWriteFast.h>
void setup() {
pinMode(PA_5, OUTPUT);
}
void loop() {
digitalWriteFast(PA_5, HIGH);
digitalWriteFast(PA_5, LOW);
}
Using the internal clock setting resulted in 283.3KHz, and external 8MHz resonator 287.5KHz.
To toggle even faster we can do direct port manipulation:
void setup() {
pinMode(PA_5, OUTPUT);
}
void loop() {
GPIOA->ODR|=0b0000000000100000;
GPIOA->ODR&=~(0b0000000000100000);
}
Using the internal clock resulted in 903.2KHz and external 8MHz 954.7KHz. Note that I did also confirm these frequency measurements with my oscilloscope.
Something to keep in mind is that there is a delay between the end of loop() and executing the first instruction back at the start of loop(), that is, the pin stays off longer than it is on. If we do successive pin toggling before the end of loop() we can get a higher speed. So if we changed loop() to:
void loop() {
while (true) {
GPIOA->ODR|=0b0000000000100000;
GPIOA->ODR&=~(0b0000000000100000);
}
}
Because the while() loop always executes the program never gets to the end of loop() and thus we can toggle the pin faster: on internal clock 3.192MHz, external 8MHz 3.182MHz.
Next, I did a digital input test by writing a sketch which responds to a switch to light an LED whenever the switch is pressed. It requires an LED with a 1K limiting resistor to PA6 (pin 12) and GND, and switch to PA7 (pin 13) and 3.3V. Here is the code:
const int inpPin=PA_7; //Input pin
const int outPin=PA_6; //Output pin
void setup() {
// put your setup code here, to run once:
pinMode(inpPin,INPUT_PULLDOWN);
pinMode(outPin,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
if (digitalRead(inpPin)) {
digitalWrite(outPin,HIGH);
}
else {
digitalWrite(outPin,LOW);
}
delay(500);
}
It sets up the single input and output in setup(), using INPUT_PULLDOWN to enable an internal pull-down resistor. In loop(), if the input is HIGH (the switch is pressed) the LED is turned on otherwise it is turned off. I purposely added a 0.5s delay just to help show it is indeed code controlling the LED, as consequence the LED won't react immediately when you press the switch, however, similarly the LED will stay on briefly when releasing the switch.
The STM32 has a number of pins that can behave as analog inputs, the particular one we are dealing with has 9 external sources, ADC_IN0 to ADC_IN9 except ADC_IN8. We can for example use PA0 (ADC_IN0), pin 6. Note that the ADC_INx pins are 3.3V pins.
I wrote a sketch to get the analog value from PA0 and output it to the serial port. However, unlike on a typical Arduino where we can program and access the serial port from a single USB port, the STM32 setup that we're using doesn't work that way. Instead we have to connect a USB to UART adapter to the STM32. I used a Waveshare PL2303, with the VCCIO shunt on 3.3V so it operates in 3.3V mode. It’s connected as follows:
STM32 PL2303
GND (pin 15) GND
PA3/USART1_RX (pin 9) TXD
PA2/USART1_TX (pin 8) RXD
Note: for this test we only actually need to connect to the STM32’s TX pin but we will use the RX pin in the next sketch so it can be connected as well.
Connect a potentiometer (10K or 100K should be fine) with its middle pin connected to STM32 pin 6, and the other two connections to GND and 3.3V respectively. This is the code:
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue=analogRead(PA_0);
Serial.println(sensorValue);
delay(1000);
}
After uploading the sketch to the STM32, open PuTTY or a similar program, and open a serial connection for your USB-UART board, set to 9600 speed. You should see a value being printed every second, which increases/decreases as you turn the wiper pot one way or another. The lowest value, 0, represents 0V and the highest, 1023, represents 3.3V. Your pot, however, may not have perfect resistance range so you may not see the full range of values but you can connect PA0 to GND to see 0 or to 3.3V to see the maximum value, but even then you may not see 1023. Indeed, I was only see 1021 when PA0 connected to 3.3V and measuring with my voltmeter I could see the supposed 3.3V rail was only 3.1V, possibly a decoupling issue. I connected the VCCIO pin (3.3V out) from the PL2303 to the STM32 PA0 pin and saw 1023 in PuTTY so indeed the issue was a sagging power rail.
Considering the STM32 has 12-bit ADC you may wonder why the analog value maxes out at 1023, this is because by default it's set to 10-bit resolution. If you want 12 bit resolution put the following in setup():
analogReadResolution(12);
Next, 2-way serial communication: have the USB to UART adapter connected as before, and an LED with series limiting resistor between PB1 (pin 14) and GND. Here is the sketch:
const int outPin=PB1; //Output pin
void setup() {
Serial.begin(9600);
pinMode(outPin,OUTPUT);
Serial.println("Serial started.");
}
void loop() {
if (Serial.available()>0) { //Serial available?
int charIn=Serial.read();
if (charIn=='y') {
digitalWrite(outPin,HIGH);
Serial.println("Turning LED on.");
}
else {
if (charIn=='n') {
digitalWrite(outPin,LOW);
Serial.println("Turning LED off.");
}
}
}
}
Using PuTTY or similar program open a serial connection set to 9600. If you type a ‘y’ the LED will turn on with accompanying message, typing ‘n’ will turn the LED off with appropriate message. Only lowercase characters are accepted and other keys won't do anything.
The last test I did before soldering up a full board was to test the oscillator pins as GPIO using the following sketch, which illuminates alternately an LED (with series limiting resistor) connected to PF0 (pin 2) and PF1 (pin 3) respectively:
const int outPin1=PF0; //Output pin
const int outPin2=PF1; //Output pin
void setup() {
pinMode(outPin1,OUTPUT);
pinMode(outPin2,OUTPUT);
}
void loop() {
digitalWrite(outPin1,HIGH);
digitalWrite(outPin2,LOW);
delay(1000);
digitalWrite(outPin1,LOW);
digitalWrite(outPin2,HIGH);
delay(1000);
}
Don't forget to remove the resonator/crystal connected to PF0 and PF1 for the sketch to work, you don't even need the external timing component to program the STM32.
To give an idea of what's possible with STM32 boards please see this video:
All content of this and related pages is copyright (c) James S. 2023-2025