STM32

STM32 HAL equivalent of Arduino millis()

The equivalent of Arduino’s millis() function when using the STM32 HAL is

HAL_GetTick()

The ticks occur once every millisecond, so this will also give you a millisecond timer that will overflow after some time equivalently to how millis() overflows.

Posted by Uli Köhler in Arduino, STM32

How read STM32 HRTIM master timer current counter value

The STM32 HRTIM (high resolution timer) provides a high speed counter that is suitable for benchmarks due to its high counting frequency of up to 240 MHz on the STM32H743.

You can read its current counter value using

uint32_t t0 = HRTIM1->sMasterRegs.MCNTR;

 

Posted by Uli Köhler in STM32

How to fix GCC error: unknown type name ‘size_t’ (STM32)

Problem:

When you try to compile your C/C++ project (typically a STM32 project):

C:/Users/User/MyProject/MyHeader.h:9:7: error: unknown type name 'size_t'
    9 | const size_t MySize = 15;
      |       ^~~~~~

Solution:

At the top of the file where this error occurs, add the following line:

#include <stddef.h>

 

Posted by Uli Köhler in C/C++, GCC errors, STM32

How to import existing C/C++ source files into STM32CubeIDE

In STM32CubeIDE, first create a folder for your source files to reside in. In order to do this, right click on your project and select New -> Folder:

Step 1: Create folder

In the dialog that opens, select the correct location (project & optionally subfolder) where the folder will be created. For this example, we’ll use occutils .

Step 2: Import files

Right click on the folder where you want to import the files into and click Import:

Now click General -> File system.

In the dialog that opens, select the From directory where you want to import the files from.

and click Finish. After that, your files will be included in the project.

Posted by Uli Köhler in STM32

How to fix STM32 error: expected constructor, destructor, or type conversion before __declspec(dllexport)

Problem:

When trying to compile a firmware for an STM32 microcontroller, you see a compiler error message like

myheader.h:23:12: error: expected constructor, destructor, or type conversion before ‘(’ token
   23 |  __declspec(dllexport) int myfunc(

Solution:

We previously explored the same problem for Linux platforms.

__declspec(dllexport) is a Windows-specific feature and not available on non-Windows platform such as the ARM embedded API platform (e.g. STM32). In order to fix it in a compatible way with both Windows and the STM32, add the following code either in a header that is included in every file containing __declspec(dllexport) or add it in each file where the error occurs:

#ifdef __ARM_EABI__
#define __declspec(v)
#endif

This will basically ignore any __declspec() call on the preprocessor level.

By using __ARM_EABI__ specfically, the definition will not trigger for ARM platforms for Windows.

Posted by Uli Köhler in C/C++, GCC errors, STM32

How to fix STM32CubeIDE: Error in final lauch sequence – Setup exceptions (debugger)

Problem:

While trying to start the STM32CubeIDE debugger, you see the following error message just after clicking Continue :

Error in final launch sequence

Setup exceptions
Setup exceptions

Solution:

This error occurs because you clicked Continue too early. The flashing process was still underway when you clicked Continue. Therefore, the solution is to wait until the stack trace shows main() and only then click Continue.

Posted by Uli Köhler in STM32

How to fix st-flash ERROR common.c: stlink_flash_loader_run(0x8000000) failed! == -1

Problem:

While flashing an STM32 using st-flash using a command like

st-flash write build/firmware.bin 0x8000000

you see an error message like

2022-02-12T01:31:34 ERROR flash_loader.c: flash loader run error
2022-02-12T01:31:34 ERROR common.c: stlink_flash_loader_run(0x8000000) failed! == -1

See below for a full error log

Solution

Most likely your STM32 is locked (readout protection). Use OpenOCD to unlock it, see How to unlock STM32F0x using OpenOCD for an example. Adjust to your STM32 family as needed.

Full st-flash log

st-flash 1.6.1
2022-02-12T01:31:34 INFO common.c: F0xx small: 4 KiB SRAM, 16 KiB flash in at least 1 KiB pages.
file build/mom.bin md5 checksum: da211df7131de9de15f3b6c7a96176dd, stlink checksum: 0x000d0d03
2022-02-12T01:31:34 INFO common.c: Attempting to write 11108 (0x2b64) bytes to stm32 address: 134217728 (0x8000000)
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08000000 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08000400 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08000800 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08000c00 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08001000 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08001400 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08001800 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08001c00 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08002000 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08002400 erased
2022-02-12T01:31:34 INFO common.c: Flash page at addr: 0x08002800 erased
2022-02-12T01:31:34 INFO common.c: Finished erasing 11 pages of 1024 (0x400) bytes
2022-02-12T01:31:34 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
2022-02-12T01:31:34 INFO flash_loader.c: Successfully loaded flash loader in sram
2022-02-12T01:31:34 ERROR flash_loader.c: flash loader run error
2022-02-12T01:31:34 ERROR common.c: stlink_flash_loader_run(0x8000000) failed! == -1
stlink_fwrite_flash() == -1

 

Posted by Uli Köhler in STM32

How to flash .bin to STM32 using st-flash

You can use st-flash like this to flash a firmware file to the STM32:

st-flash write build/firmware.bin 0x8000000

 

Posted by Uli Köhler in STM32

How to lock STM32F0 using OpenOCD (readout protection)

openocd -f interface/stlink-v2.cfg -f target/stm32f0x.cfg -c "init" -c "halt" -c "stm32f1x lock 0" -c "reset halt" -c "exit"

This will activate flash readout protection level 1 which means you won’t be able to readout or re-write the flash. You can still perform a chip erase which will clear the readout protection – for example to flash a new firmware.

Posted by Uli Köhler in STM32

How to unlock STM32F0x using OpenOCD

openocd -f interface/stlink-v2.cfg -f target/stm32f0x.cfg -c "init" -c "halt" -c "stm32f1x unlock 0" -c "reset halt" -c "exit"

After that, you need to physically remove power from the device in order for the reset to take effect.

Note the stm32f1x is no typo. OpenOCD uses the same backend for STM32F1x and STM32F0x.

Example output:

Open On-Chip Debugger 0.11.0-rc2
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 1000 kHz
Info : STLINK V2J24S4 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.296172
Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for stm32f0x.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : device id = 0x10006444
Info : flash size = 16kbytes
stm32x unlocked.
INFO: a reset or power cycle is required for the new settings to take effect.

Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
target halted due to debug-request, current mode: Thread 
xPSR: 0xc1000000 pc: 0x080000c0 msp: 0x20000400

 

Posted by Uli Köhler in STM32

How to set pin speed/alternate function in STM32 Arduino (PlatformIO)

You can use the STM32 HAL (STM32CubeMX) even when using Arduino as a framework for STM32 boards in PlatformIO:

GPIO_InitTypeDef pinInit = {
  .Pin = GPIO_PIN_8,
  .Mode = GPIO_MODE_AF_PP,
  .Pull = GPIO_NOPULL,
  .Speed = GPIO_SPEED_FREQ_VERY_HIGH,
  .Alternate = GPIO_AF1_TIM1
};
HAL_GPIO_Init(GPIOA, &pinInit);

Use

#include <stm32f4xx_hal_gpio.h>

in order to include the HAL functions.

Posted by Uli Köhler in Arduino, Electronics, PlatformIO, STM32

How to use HAL_GPIO_Init() in modern C++ (STM32)

In modern C++, you can directly initialize structs like a GPIO_InitTypeDef, making the code much prettier and less prone to errors. The following example configures PA8 of a STM32 in alternate function 1 mode (TIM1 output).

GPIO_InitTypeDef pinInit = {
  .Pin = GPIO_PIN_8,
  .Mode = GPIO_MODE_AF_PP,
  .Pull = GPIO_NOPULL,
  .Speed = GPIO_SPEED_FREQ_VERY_HIGH,
  .Alternate = GPIO_AF1_TIM1
};
HAL_GPIO_Init(GPIOA, &pinInit);

As opposed to the old, much more verbose way of doing that:

GPIO_InitTypeDef pinInit;
pinInit.Pin = GPIO_PIN_8;
pinInit.Mode = GPIO_MODE_AF_PP;
pinInit.Pull = GPIO_NOPULL;
pinInit.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
pinInit.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOA, &pinInit);

 

 

Posted by Uli Köhler in C/C++, Electronics, STM32

How to convert PlatformIO firmware with build offset to firmware without

Some firmwares are build with a build offset to accomodate flash space (like 32k – 0x8000) for a bootloader that is started before the firmware. One of the downsides of using such a firmware is that it always depends on a compatible bootloader to be present (compatibility is mostly defined by how much flash is allocated for the bootloader)

If you want to convert a firmware to a “normal” non-bootloader firmware, this is what you’ll have to do:

  • Set board_build.offset to 0x0 – look not only in your build configuration in platformio.ini and all included files, but also look in the configuration that your config extends, if any.
  • Set board_upload.offset_address to 0x0. This mostly affects uploading with a debugger, but you should always keep this information consistent because debugging that is a huge nightmare.
  • Edit the specific linker script your firmware is using and set the flash offset appropriately:

Look for the MEMORY section like this:

MEMORY
{
FLASH (rx)      : ORIGIN = 0x8008000, LENGTH = 512K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
}

As you can see in

FLASH (rx) : ORIGIN = 0x8008000, LENGTH = 512K

the flash for this STM32 (example) is not at the MCU’s flash address 0x8000000, but at 0x8008000 – basically, the linker is told to skip the 0x8000 (32k) the bootloader occupies (else, it would overwrite the bootloader.

Change this to your MCU’s flash adress. For ARMs like the STM32, this is typically 0x8000000.

Now recompile and your firmware should work without the bootloader.

Posted by Uli Köhler in Embedded, PlatformIO, STM32

Implementing STM32 DFU bootloader firmware upgrade in Marlin using M997

Marlin implements the M997 command which is intended to switch the mainboard into a firmware upgrade mode.

All STM32 variants have an integrated (hard-coded – so no need to flash it yourself) bootloader that is notoriously difficult to active.

However, Marlin implements M997 on the STM32 as just a reboot:

void flashFirmware(const int16_t) { HAL_reboot(); }

This only works if you are using a custom bootloader on your board – however, it does not use the STM32 integrated bootloader.

The following code was tested on the STM32F446 (BigTreeTech Octopus V1) but should work on any STM32 variant. It is based on previous work by Dave Hyland on StackOverflow. Replace the default flashFirmware() function in Marlin/src/HAL/STM32/HAL.cpp

void flashFirmware(const int16_t) {
    HAL_RCC_DeInit();
    HAL_DeInit();

    __HAL_REMAPMEMORY_SYSTEMFLASH();

    // arm-none-eabi-gcc 4.9.0 does not correctly inline this
    // MSP function, so we write it out explicitly here.
    //__set_MSP(*((uint32_t*) 0x00000000));
    __ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");

    ((void (*)(void)) *((uint32_t*) 0x00000004))();

    // This will never be executed
    HAL_reboot();
}

Note that we left a HAL_reboot() call as a safeguard at the end, just in case the previous calls fail.

On my BigTreeTech Octopus V1 (STM32F446), by using this code, you can successfully enter the integrated DFU bootloader.

Also see our previous posts on how to use the STM32 in DFU bootloader mode:

Posted by Uli Köhler in 3D printing, C/C++, STM32

How to flash STM32 PlatformIO firmware using dfu-util

First, you need to find the correct firmware file. dfu-util will flash firmware.bin, not firmware.elf. You can find firmware.bin in

.pio/build/[PROFILE_NAME]/firmware.bin

inside your project folder. [PROFILE_NAME] is the name of the build profile you’re using, i.e. the name of the section in platformio.ini. For example:

.pio/build/BIGTREE_OCTOPUS_V1/firmware.bin

Now flash using dfu-util:

dfu-util -a 0 -D .pio/build/PROFILE_NAME/firmware.bin -s 0x08000000

Flags:

  • -a 0. The STM32 appears as four different devices in dfu-util (see dfu-util --list): The flash, option bytes, RAM etc each appear as a separate device. We only care about the flash device, which is always the first (index 0) of those devices, at least in every board I have seen so far
  • -D [filename]Download the firmware to the device
  • -s 0x08000000: Flash at address 0x08000000 which is the address of the STM32 flash.
Posted by Uli Köhler in Embedded, PlatformIO, STM32

How to exit/reset STM32 DFU bootloader

Both dfu-util and dfu-tool can flash firmware, but their current versions can’t reset the STM32 from DFU mode to run the application.

I found that using MicroPython’s pydfu.py is able to reset the. Note that currently I use pydfu.py only for resetting, not for flashing (but that might change in the future).

Download using

wget https://raw.githubusercontent.com/micropython/micropython/master/tools/pydfu.py

Install the PyUSB dependency using

sudo pip3 install pyusb

And then reset the STM32 in DFU mode:

python3 pydfu.py -x

 

Posted by Uli Köhler in STM32

How to flash Marlin on BigTreeTech Octopus V1 using debug adapter

In order to flash the Bigtreetech Octopus V1 using my STLinkv2 debug adapter, I needed. First we need to note that the first 32k of flash memory are occupied by the bootloader (0x08000000 to 0x08008000). So we need to flash the firmware at address 0x08008000. By default, this is not configured correctly in Marlin.

Open ini/stm32f4.ini and edit the [env:BIGTREE_OCTOPUS_V1]:

[env:BIGTREE_OCTOPUS_V1]
platform           = ${common_stm32.platform}
extends            = stm32_variant
board              = marlin_BigTree_Octopus_v1
board_build.offset = 0x8000
board_upload.offset_address = 0x08008000
build_flags        = ${stm32_variant.build_flags}
                     -DSTM32F446_5VX -DUSE_USB_HS_IN_FS
upload_protocol = stlink

Note that you absolutely need to re-flash the bootloader in case you accidentally flashed with the old configuration. Follow the official documentation in order to flash the bootloader. I flash usin STM32CubeProgrammer 2.7.0 (2.8.0 does not work) on both Linux and Windows.

The [env:BIGTREE_OCTOPUS_V1_USB] will be updated automatically as it includes [env:BIGTREE_OCTOPUS_V1]

Posted by Uli Köhler in 3D printing, Electronics, STM32

How to fix PlatformIO serial monitor scrambled output

Problem:

When using the Monitor function of platformIO, you see strange characters instead of strings being printed, for example:

)�
�␜ܠ��J��1��1!y��!���!��

Solution:

This issue almost always appears due to the Monitor function using the wrong UART speed. You can see from the log in our screenshot above:

--- Miniterm on /dev/ttyUSB0  9600,8,N,1 ---

that PlatformIO is using 9600 baud in this case – but your microcontroller is sending data at a faster speed (or, rarely at a slower speed).

Most firmwares using serial IO use 115200 baud, so that’s what I’d recommend to try first, but if that doesn’t work, look out for config options named baud rate or similar, or for lines of code like

Serial.begin(57600);

in the firmware.

In order to change the Monitor UART speed, open platformio.ini and add

monitor_speed = 115200

Full platformio.ini example for ESP32:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

After that, restart the Monitor function.

Posted by Uli Köhler in Arduino, Electronics, Embedded, ESP8266/ESP32, PlatformIO, STM32

How to implement 1MHz interrupt in PlatformIO / Arduino on STM32

In our previous post Minimal STM32 HardwareTimer PlatformIO / Arduino timer interrupt blink example we showed how to use HardwareTimer to blink the onboard LED of our STM32F407 board using a timer interrupt.

In this post, we’ll provide an example of how to use HardwareTimer and have a really fast interrupt which runs at 1 MHz – in other words: one million times per second.

#include <Arduino.h>

HardwareTimer timer(TIM1);
bool ledOn = false;

void OnTimer1Interrupt() {
    ledOn = !ledOn;
    digitalWrite(PC13, ledOn ? HIGH : LOW);
}

void setup() {
    pinMode(PC13, OUTPUT);
    // Configure timer
    timer.setPrescaleFactor(21); // Set prescaler to 21 => timer frequency = 168/21 = 8 MHz (from prediv'd by 1 clocksource of 168 MHz)
    timer.setOverflow(8); // Set ARR to 8 => timer frequency = 1 MHz
    timer.attachInterrupt(OnTimer1Interrupt);
    timer.refresh(); // Make register changes take effect
    timer.resume(); // Start timre
}

void loop() {
}

Note that when running such a quick interrupt, you can’t do all too much within the interrupt before the next time the interrupt will run.

Posted by Uli Köhler in C/C++, PlatformIO, STM32