Creating custom board for STM32F429ZGT6

Hi Everyone,

I just found recently about Platformio and I think it’s a great initiative. I have myself designed production grade STM32F429 board made for audio DSP purposes and I would like to create a board configuration for it.
Documentation is very brief on how to create custom board config and I’m trying to learn from github.

It would be great if someone experienced can help me in that process as some steps seem to be unclear.

My board has STM32F429ZGT6 MCU as you can figure out from subj. It requires external debugger like STlink.
Board itself has 256MB external RAM chip, I2S codecs and external connectors for I2C, SPI, UARTs, GPIOs and bunch of other stuff.

Right now I have created my myboard.json inside ./platformio/boards directory, installed ststm32 platform and I’m able to list it my board file trough pio boards

As a next step is I need is to refine the cofiguration within the json.

Im using these two files as references:

from these files I cannot understand what should maximum_ram_size and maximum_size fields be in my case. The values in references do not match. According to datasheet STM32F429ZI discovery board should have 2MBytes Flash memory and 256 Kbytes RAM.

Can someone explain me how does this maps to

“maximum_ram_size”: 262144,
“maximum_size”: 2097152,

specified in disco_f429zi.json

Currently my json looks like this:

{
  "build": {
    "cpu": "cortex-m4",
    "extra_flags": "-DSTM32F4 -DSTM32F429xx",
    "f_cpu": "180000000L",
    "mcu": "stm32f429zgt6",
    "product_line": "STM32F429xx"
  },
  "debug": {
    "default_tools": ["stlink"],
    "jlink_device": "STM32F429ZG",
    "openocd_target": "stm32f4x",
    "svd_path": "STM32F429x.svd"
  },
  "frameworks": ["stm32cube", "cmsis", "freertos"],
  "platforms": ["ststm32"],
  "name": "BDSP",
  "upload": {
    "maximum_ram_size": 262144,
    "maximum_size": 2097152,
    "protocol": "stlink",
    "protocols": ["jlink", "cmsis-dap", "stlink", "blackmagic", "mbed"]
  },
}

If someone can review other fields as well and tell me if It seems to be correct - I’d really appretiate. Im completely new to the platform so hoping alot on community help to bypass wasting time on errors in configuration

freertos is not a supported framework in the PlatformIO sense – only the ones that have builder scripts are supported. Of course one can use e.g. STM32Cube with a FreeRTOS library, but that is then framework = stm32cube as a project base, not framework = freertos.

As an improvement you can add e.g. -DHSE_VALUE=8000000UL into this so that the HSE external crystal frequency (example here: 8MHz) is always correct in the build system. Otherwise you might be running into issues like PlatformIO FreeRTOS is slower.

Boards do not have platforms field, remove this line.

This is not syntactically valid because of the , at the end. If it’s the last element in the object, don’t add a ,, otherwise it will be expecting the next element.

You are also missing the informative fields

in the definition.

Beware of a current bug in auto-generated linker scripts for STM32: It will set the initial SP to RAM begin + maximum_ram_size, leading to a possible crash on startup if SP lands in a memory address that is not RAM (ARM versus Thumb - #11 by maxgerhardt). Use an explicit good linker script in the project as described in PlatformIO FreeRTOS - #10 by maxgerhardt.

I don’t see any further issues beyond that.

Thanks for detailed guidance.

I fixed my file to look like following:

{
  "build": {
    "cpu": "cortex-m4",
    "extra_flags": "-DSTM32F4 -DSTM32F429xx -DHSE_VALUE=8000000UL",
    "f_cpu": "180000000L",
    "mcu": "stm32f429zgt6",
    "product_line": "STM32F429xx"
  },
  "debug": {
    "default_tools": ["stlink"],
    "jlink_device": "STM32F429ZG",
    "openocd_target": "stm32f4x",
    "svd_path": "STM32F429x.svd"
  },
  "frameworks": ["stm32cube", "cmsis"],
  "name": "BDSP",
  "upload": {
    "maximum_ram_size": 262144,
    "maximum_size": 1048576,
    "protocol": "stlink",
    "protocols": ["jlink", "cmsis-dap", "stlink", "blackmagic", "mbed"]
  },
  "url": "http://ericasynths.lv",
  "vendor": "Erica Synths"
}

Now I can see in VScode in project wizard my board. I’ve created new project and my ini file is looking like this

; PlatformIO Project Configuration File

;

; Build options: build flags, source filter

; Upload options: custom upload port, speed and extra flags

; Library options: dependencies, extra library storages

; Advanced options: extra scripting

;

; Please visit documentation for the other options and examples

; https://docs.platformio.org/page/projectconf.html

[env:erica_black_dsp]

platform = ststm32

board = erica_black_dsp

framework = stm32cube

I suppose I should add other ini fields myself, like debugger

I made up right now this:

[common_env_data]
build_flags =
    -D VERSION=1.2.3
    -D DEBUG=1
    -Wall
    -mcpu=cortex-m4
    -ffunction-sections
    -fdata-sections
    --specs=nosys.specs
    -fstack-usage -MMD -MP
    -std=c++17
    -g3
    -D DEBUG
    -D USE_HAL_DRIVER
    -D STM32F429xx
    -mfloat-abi=hard
    -mfpu=fpv4-sp-d16
    -mthumb



[env:erica_black_dsp]
platform = ststm32
board = erica_black_dsp
framework = stm32cube

; Build options
build_flags =
    ${common_env_data.build_flags}

; Serial Monitor options
monitor_speed = 115200
monitor_flags =
    --encoding
hexlify

I guess I need some more settings for debug SWD interface. Can you help me on that? Originally my projects run on STlink with following properties:

SWO clock 2000 kHz, Coreclock 180mhz

How should ini code look like? thanks once more

Is the board not flashable? What’s the output of the project task “Advanced → Verbose Upload”?

Board has SWD interface out which both in development and in production is connected to STLink

Output for Verbose Upload :

Processing erica_black_dsp (platform: ststm32; board: erica_black_dsp; framework: stm32cube)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CONFIGURATION: https://docs.platformio.org/page/boards/ststm32/erica_black_dsp.html
PLATFORM: ST STM32 (14.2.0) > BDSP
HARDWARE: STM32F429ZGT6 180MHz, 256KB RAM, 1MB Flash
DEBUG: Current (stlink) External (blackmagic, cmsis-dap, jlink, stlink)
PACKAGES: 
 - framework-stm32cubef4 1.26.2 
 - tool-dfuutil 1.9.200310 
 - tool-ldscripts-ststm32 0.1.0 
 - tool-openocd 2.1100.0 (11.0) 
 - tool-stm32duino 1.0.1 
 - toolchain-gccarmnoneeabi 1.70201.0 (7.2.1)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 52 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
MethodWrapper(["checkprogsize"], [".pio/build/erica_black_dsp/firmware.elf"])
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   2.5% (used 6440 bytes from 262144 bytes)
Flash: [=         ]  14.7% (used 154148 bytes from 1048576 bytes)
.pio/build/erica_black_dsp/firmware.elf  :
section               size        addr
.isr_vector            428   134217728
.text               138084   134218160
.rodata              15364   134356248
.ARM.extab               0   134371612
.ARM                     8   134371612
.preinit_array           0   134371620
.init_array             24   134371620
.fini_array              4   134371644
.data                  700   536870912
.bss                  5740   536871612
._user_heap_stack     1536   536877352
.ARM.attributes         42           0
.comment               126           0
.debug_frame         83264           0
.stab                  204           0
.stabstr               493           0
Total               246017
<lambda>(["upload"], [".pio/build/erica_black_dsp/firmware.elf"])
AVAILABLE: blackmagic, cmsis-dap, jlink, mbed, stlink
CURRENT: upload_protocol = stlink
openocd -d2 -s /Users/t/.platformio/packages/tool-openocd/scripts -f interface/stlink.cfg -c "transport select hla_swd" -f target/stm32f4x.cfg -c "program {.pio/build/erica_black_dsp/firmware.elf}  verify reset; shutdown;"
xPack OpenOCD, x86_64 Open On-Chip Debugger 0.11.0-00155-ge392e485e (2021-03-15-18:44)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
debug_level: 2

hla_swd
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 2000 kHz
Error: open failed
in procedure 'program'
** OpenOCD init failed **
shutdown command invoked

The OpenOCD invocation looks good, but OpenOCD can’t find your STLink adapter.

It seems like you’re using Mac. Do you have libusb installed? Can you connect to the chip using other tools, e.g., STM32CubeProgrammer?

You are right, this most probably is a test stand issue, will get back here once I have new wire to test this.

I’m on Mac, previously stuff was working under Eclipse/STM32IDE. I Found PlatrofmIO when I started thinking to move project in to VScode.

Today I’ve tried with new wires. Could upload successfully with default ini:

[env:erica_black_dsp]

platform = ststm32

board = erica_black_dsp

framework = stm32cube

When I tried to use build flags that I copied from old eclipse build setup I got errors:

/Users/t/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld: error: .pio/build/erica_black_dsp/FrameworkHALDriver/Src/stm32f4xx_hal.o uses VFP register arguments, .pio/build/erica_black_dsp/firmware.elf does not

Problem seems to be in
-mfloat-abi=hard
Seems to be toolchain or linkage? How can I solve this? Thanks!

It seems object files are compiled with -mfloat-abi=hard but this build flag isn’t used in the final ELF linking stage.

Try adding a small extra script to append to the linker flags.

extra_scripts = link_hardfloat.py

with link_hardfloat.py in the project’s root directory

Import("env")
env.Append(LINKFLAGS=["-mfloat-abi=hard"])

This seems to solve the issue. Thanks!

Now I could get hello world to run in debug mode! great!

Next questions I have are more regarding libraries and includes setup:

  • If adding #include <stm32l4xx_hal.h> to main.cpp to VScode it does not see the framework file, what is correct way to set include path for such?

  • Usually in STM32 HAL projects I would have config file provided by STM32 HAL library template
    included with defines to set up library includes. Is this file defined somewhere in project settings or I have to add it to project /src dir ?

  • I have my own library, which is located in parent directory of platformio project. Tree looks like this:

└─ .
   ├─ app2
   │  ├─ app.cpp
   │  ├─ app.h
   │  └─ targets
   │     ├─ desktop_target_dir
   │     └─ platrofmio_dir
   ├─ app1
   │  ├─ app.cpp
   │  ├─ app.h
   │  └─ targets
   │     ├─ desktop_target_dir
   │     └─ platrofmio_dir
   └─ custom_library
      ├─ blocks
      │  └─ some_block.h
      ├─ dsp
      │  └─ some_dsp.h
      └─ utils
         └─ some_util.h

How should I include my custom library correctly to the project, considering that I might need to debug and make library code changes while working in the environment?

I don’t understand the question. It does not “see” the framework file? There is a compile error when writing that include?

PlatformIO by default automatically uses a config file that enables all submodules. If you don’t want that, you can tell the stm32cube.py builder script to not use that default file by adding

board_build.stm32cube.custom_config_header = yes

and additionally adding a e.g. -Iinclude flag so that if your HAL config file is in include/ it will be found by the framework during the build process. An example is in e.g. GitHub - maxgerhardt/pio-stm32h7-stm32cube-freertos.

Adding libraries is per LDF doc and library options.

Your libraries should be organized in a PlatformIO compatible folder structure for this to work.

Since I don’t see where in the directory tree structure above the project root with the platformio.ini is, I can’t say specifically what path you need. One option is to use lib_extra_dirs with with a relative path, e.g. lib_extra_dirs = ../custom_library, then all folders within custom_library/ are seen as potentially includable libraries (blocks, dsp, utils modelled as separate libraries).

If you have more complex libraries and need to add include files, give a library a library.json file.

Lint gives this error:

#include errors detected. Please update your includePath. Squiggles are disabled for this translation unit() .C/C++(1696)

cannot open source file "stm32l4xx_hal.h"C/C++(1696)

I had wrong include file name copied from example files,

#include “stm32f4xx_hal.h”

works like charm!

Regarding rest:

Will read carefully library include docs and get back here with my progress!

@maxgerhardt before I jump in lib stuff deep in:

Program with simple hello world runs, but it does not print in to VScode terminal. Could you suggest how I can redirect stdout there. In original eclipse project I was debugging trough SWO.

Is it really via SWO or SWD semihosting? What’s a minimal piece of code to use SWO?

Out-of-the-box, PlatformIO doesn’t have the capability to read the SWO stream (or tell OpenOCD to read it), per Viewing SWO output within PIO?. But the linked topic also contains workarounds. The “Monitior” task starts miniterm.py, which can connect to serial ports (UART) and network sockets.

Seeing semihosting output is possible by expanding the GDB initialization commands and running the application in debug mode (gd32-pio-projects/gd32-spl-semihosting-printf at main · CommunityGD32Cores/gd32-pio-projects · GitHub).

Actually per Viewing SWO output within PIO? - #13 by maxgerhardt I was able to get a SWO demo running within PlatformIO. This is now also tracked in Support viewing SWO data · Issue #4069 · platformio/platformio-core · GitHub.

I think debugging via semihosting is OK for now, later on I might want to get SWO running and its good to know that there is work towards this direction.

I tried to add .ini lines

board_debug.semihosting = yes
debug_extra_cmds =
    monitor arm semihosting enable
    monitor arm semihosting_fileio enable

However linker fails to find initialise_monitor_handles()
What I am missing?

This doesn’t work outside the GigaDevice project I mentioned – it triggers something specific in platform-gd32. You need to remove that line and append your existing extra script with the lines

so that initialise_monitor_handles() becomes available.

; board_debug.semihosting = yes

removed ^^^ line and updated

update_link_flags.py

with:

Import("env")


env.Append(
    LINKFLAGS=[
        "-mthumb",
        "-mfloat-abi=hard",
        "-mfpu=fpv4-sp-d16",
        "--specs=rdimon.specs",
    ],
    LIBS=["rdimon"],
)

Still have same link error

changed that py code to

Import("env")


env.Append(
LINKFLAGS=[
    "-mthumb",
    "-mfloat-abi=hard",
    "-mfpu=fpv4-sp-d16",
    "--specs=rdimon.specs",
    "--specs=nano.specs",
]
)
env.Append(LIBS=["rdimon"])

now error changed to

arm-none-eabi-g++: fatal error: /Users/t/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/nano.specs: attempt to rename spec 'link' to already defined spec 'nano_link'
compilation terminated.
*** [.pio/build/erica_black_dsp/firmware.elf] Error 1

for

Import("env")


env.Append(LINKFLAGS=["-mthumb", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16"])

env.Append(LINKFLAGS=["--specs=rdimon.specs"], LIBS=["rdimon"])

also link error undefined reference to `initialise_monitor_handles()’

Try adding those too

or try SWO with the referenced demo.

SWD semihosting is extremely slow – you will see for yourself.