Pio remote test using a custom board results in a faulty binary

Hi everyone,

I have encountered a problem while trying to set up remote unit testing on my custom board.

I started the project using a nucleo_f446re board and successfully set up pio run, pio test, and pio remote test using mbed framework.

As a next step, I have added my custom board based on stm32f446re using the following tutorials: Custom Embedded Boards — PlatformIO v6.1 documentation
Mbed OS — PlatformIO latest documentation

For this custom board, I use ST-LINK/V2 for programming/debugging and have a separate serial line where test results are reported.

I was able to make pio run, and pio test work, however, with pio remote test(and pio remote run), I have run into a problem. The code is being compiled however the resulting .bin and .elf files are a fraction of the size of what they are supposed to be.

For pio test the size of firmware.bin is 56kb while with pio remote test the size of firmware.bin is only 1 kb. The faulty firmware is programmed on the custom board through the remote agent, but of course, there is no response, and no unit tests are being run.

When building with pio remote test I get the following warning: arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol Reset_Handler; defaulting to 0000000008000000

A few config files for context:
custom_targets.json

{
“DMCB_60033”:{
“inherits”: [“MCU_STM32F4”],
“extra_labels_add”: [
“DMCB_60033”,
“REV_A”
],
“device_has_add”: [
“CAN”
],
“components_add”: [“FLASHIAP”],
“macros_add”: [
“STM32F446xx”,
“USB_STM_HAL”,
“USBHOST_OTHER”,
“LED1=MBED_CONF_APP_HEARTBEAT_LED”,
“HSE_VALUE=25000000ul”
],
“device_has_remove”: [
“ANALOGIN”,
“I2CSLAVE”,
“I2C_ASYNCH”
],
“detect_code”: [“0796”],
“release_versions”: [“5”,“6”],
“device_name”: “STM32F446RETx”,
“bootloader_supported”: true
}
}

DMCB_60033.json

{
“build”: {
“core”: “stm32”,
“cpu”: “cortex-m4”,
“extra_flags”: “-DSTM32F446xx -DSTM32F4xx”,
“f_cpu”: “180000000L”,
“mcu”: “stm32f446ret6”,
“variant”: “STM32F446RE”
},
“connectivity”: [
“can”
],
“debug”: {
“default_tools”: [
“stlink”
],
“jlink_device”: “STM32F446RE”,
“onboard_tools”: [
“stlink”
],
“openocd_board”: “st_nucleo_f4”,
“openocd_target”: “stm32f4x”,
“svd_path”: “STM32F446x.svd”
},
“frameworks”: [
“mbed”,
“arduino”,
“stm32cube”
],
“name”: “STM32F446RE (128k RAM. 512k Flash)”,
“upload”: {
“maximum_ram_size”: 131072,
“maximum_size”: 524288,
“protocol”: “stlink”,
“protocols”: [
“jlink”,
“stlink”,
“blackmagic”,
“mbed”
]
},
“url”: “NUCLEO-F446RE | Mbed”,
“vendor”: “ST”
}

Thank you for the answer in advance.

What happens with pio remote test --force-remote?

Hi @maxgerhardt,

Thanks for the quick response!

I’m getting the following error with --force-remote:

Failed to extract configuration for DMCB_60033.
It might not be supported in the this Mbed release.

Where is this file located?

DMCB_60033.json is located under:
$PROJECT_DIR/Boards/
This is the project structure:
ProjectStructure

Is the remote machine a Linux machine? boards/ is usually written lowercase. This makes a difference on Linux vs Windows. Same goes for lib/.

So I have changed the folder names to lowercase however when using --force-remote, I still receive the following error:
Failed to extract configuration for DMCB_60033. It might not be supported in the this Mbed release

However, Linux’s case sensitivity gave me an idea. Previously, for pio remote test I was using lib_extra_dirs instead of lib_deps for accessing my local libraries because for lib_deps I was always getting the following error:

Building & Uploading...
Library Manager: Installing file://Lib/Components/Hwal
[Errno 2] No such file or directory: 'Lib/Components/Hwal'

I ensured that “lib” is lowercase and the path ends with a / symbol, and that seems to fix lib_deps. Using lib_deps instead of lib_extra_dirs, pio remote test without the --force-remote option finally resulted in the proper size binary being programmed on the board through the remote agent from windows client.

Currently, I can start remote tests from a client running on my local windows, but when trying to start it from a CI pipeline running Linux I am getting the same error, even though the path is fixed:

Building & Uploading...
Library Manager: Installing file://lib/Components/Hwal/
[Errno 2] No such file or directory: 'lib/Components/Hwal/'

What is weird is that boards/TARGET_DMCB_60033/ is found.

I’ve tried to run it on a local Linux docker to simulate the same scenario as in the pipeline and there the project runs without a problem.

For now, I was able to solve this issue by accessing my local libraries through lib_extra_dirs when running in the CI pipeline.

Here is my platformio.ini file:

; 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

################################################################################
# Custom section for value interpolation
################################################################################


; ## Windows Port ##############################################################
[windows_port]
    test_port           = COM4


; ## Linux Port ################################################################
[linux_port]
    test_port           = /dev/ttyUSB0


; ## Off Target ################################################################
; Linux/Windows host specific configuration values(when running unit tests on the
; host/off-target)
[off_target]
    ; .. Device Config .........................................................
    platform                  = native

    ; .. Build Config ..........................................................
    build_flags               = -pthread
                                -std=c++17
                                -Werror
    ; .. Library Dependencies...................................................
    lib_deps                  = symlink://boards/TARGET_DMCB_60033/PINOUT_DMCB_60033/

; ## On Target #################################################################
; target specific configuration values(when running unit tests on-target)
[on_target]
    ; .. Device Config .........................................................
    platform                  = ststm32@17.0.0
    board                     = DMCB_60033
    board_build.mbed.ldscript = $PROJECT_DIR/boards/TARGET_DMCB_60033/TOOLCHAIN_GCC_ARM/stm32f446xe.ld
    framework                 = mbed
    ; .. Build Config ..........................................................
    build_flags               = -DPIO_FRAMEWORK_MBED_RTOS_PRESENT
                                -std=gnu++11                                                    
                                -Iboards/TARGET_DMCB_60033/PINOUT_DMCB_60033/
                                -Iboards/TARGET_DMCB_60033/
    build_unflags             = -std=gnu++98
    ; .. Library Dependencies...................................................
    lib_deps                  = symlink://boards/TARGET_DMCB_60033/

    ; .. Test Config ...........................................................
    test_framework            = custom
    test_speed                = 1200000

    ; .. Additional scripts.....................................................
    extra_scripts             = pre:utilities/build_env_extra_scripts/mbedignore.py

; ## Common ####################################################################
; Common configuration values between both targets
[common]
    ; .. Build Config ..........................................................
    build_flags               = -Wall -Wextra -Wpedantic

    ; .. Library Dependencies...................................................
    lib_deps                  = symlink://lib/Components/Hwal/
                                symlink://lib/Components/Osal/
                                symlink://lib/Components/PwmSwitch/
                                symlink://lib/Compositions/Actors/Hid/
                                fmtlib/fmt@^8.1.1
    ; .. Static Analysis .......................................................
    check_tool                = clangtidy
    check_flags               = clangtidy: --checks=*,-llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,-bugprone-easily-swappable-parameters,-readability-redundant-access-specifiers,-modernize-use-trailing-return-type,-llvm-header-guard,-altera-id-dependent-backward-branch,-altera-unroll-loops,-llvmlibc-restrict-system-libc-headers,-llvm-include-order,-cppcoreguidelines-init-variables,-cppcoreguidelines-pro-type-member-init,-hicpp-member-init,-cppcoreguidelines-avoid-non-const-global-variables,-misc-const-correctness,-google-readability-namespace-comments,-llvm-namespace-comment


; ## Test ######################################################################
; Exclude main.cpp for testing purposes but first include everything
[test]
    ; .. Build Config ..........................................................
    build_src_filter          = +<**/*>
                                -<**/main.cpp>
    build_flags               = -lgcov
                                --coverage
                                -fprofile-abs-path
                                -fprofile-arcs
    ; .. Library Dependencies...................................................
    lib_deps                  = throwtheswitch/Unity@^2.5.2
                                https://github.com/eranpeer/FakeIt.git#2.4.0
    ; .. Test Config ...........................................................
    test_build_src            = true
    ; .. Additional scripts.....................................................
    extra_scripts             = pre:utilities/build_env_extra_scripts/copy_unity_config.py
                                pre:utilities/build_env_extra_scripts/generate_test_runners/generate_test_runners.py

################################################################################
#   Override default configuration
################################################################################
[platformio]
    src_dir                   = apps/
    build_cache_dir           = .pio/cache # among others enables caching of mbed-os,
                                           # which accelerates the build process 
                                           # significantly

################################################################################
#   Configuration Environments 
################################################################################

; ## Common ####################################################################
; Common configurations for all environments
[env]
    ; .. Library Dependencies...................................................    
    lib_ldf_mode              = chain
    ; .. Static Analysis .......................................................
    check_tool                = ${common.check_tool}
    check_flags               = ${common.check_flags}

; ## Off-target on Linux/Windows host ##########################################
; Configuration environment for running production code off-target on a linux/
; windows host
[env:off_target]
    ; .. Device Config .........................................................
    platform                  = ${off_target.platform}
    ; .. Build Config ..........................................................
    build_flags               = ${common.build_flags}
                                ${off_target.build_flags}                          
    ; .. Library Dependencies...................................................
    lib_deps                  = ${common.lib_deps}
                                ${off_target.lib_deps}

; ## On-target #################################################################
; Configuration environment for running production code on-target from a
; windows/linux pio remote client
[env:on_target]
    ; .. Device Config .........................................................
    platform                  = ${on_target.platform}
    board                     = ${on_target.board}
    board_build.mbed.ldscript = ${on_target.board_build.mbed.ldscript}
    framework                 = ${on_target.framework}
    ; .. Build Config ..........................................................
    build_flags               = ${common.build_flags}
                                ${on_target.build_flags}
    build_unflags             = ${on_target.build_unflags}
    ; .. Library Dependencies...................................................    
    lib_deps                  = ${common.lib_deps}
                                ${on_target.lib_deps}
    ; .. Additional scripts.....................................................
    extra_scripts             = ${on_target.extra_scripts}                          

; ## Off-target test on Linux/Windows host #####################################
; Extended configuration environment for off-target unit tests on a linux/
; windows host
[env:off_target_test]
    extends                   = env:off_target
    ; .. Build Config ..........................................................
    build_flags               = ${common.build_flags}
                                ${off_target.build_flags}
                                ${test.build_flags}
    build_src_filter          = ${test.build_src_filter}
    ; .. Library Dependencies...................................................
    lib_deps                  = ${common.lib_deps}                        
                                ${test.lib_deps}
                                ${off_target.lib_deps}
    ; .. Test Config ...........................................................
    test_build_src            = ${test.test_build_src}
    ; .. Additional scripts ....................................................
    extra_scripts             = ${test.extra_scripts}
    
    ; .. Debug settings ........................................................
    ; when trying to debug a unit test we have to specify that specific unit test
    ; here 
    ; debug_test          = src/Hid/test_Hid

; ## Intermediate On-target test environment ###################################
; Do not use standalone, as it does not include pio remote client specific configurations.
; Should only be used through on_target_test_windows, on_target_test_linux or
; on_target_test_linux_ci environments.
[env:on_target_test]
    extends                   = env:on_target
    ; .. Build Config ..........................................................
    build_src_filter          = ${test.build_src_filter}
    ; the fakeit library uses exceptions and dynamic_cast, therefore only for
    ; on-target unit testing, we enable these features in the compiler
    build_flags               = -fexceptions
                                ${common.build_flags}
                                ${on_target.build_flags}
    build_unflags             = -fno-rtti
                                -fno-exceptions
    ; .. Library Dependencies...................................................
    lib_deps                  = ${common.lib_deps}
                                ${test.lib_deps}
                                ${on_target.lib_deps}
    ; .. Test Config ...........................................................
    test_framework            = ${on_target.test_framework}
    test_speed                = ${on_target.test_speed}    
    test_build_src            = ${test.test_build_src}
    ; .. Additional scripts.....................................................
    extra_scripts             = ${on_target.extra_scripts}
                                ${test.extra_scripts}
    ; .. Debug settings ........................................................
    ; when trying to debug a unit test we have to specify that specific unit test
    ; here 
    ; debug_test                = UnitTests/lib/Compositions/Actors/Hid/test_Hid

; ## On-target test environment for local windows pio remote client ############
[env:on_target_test_windows]    
    extends                   = env:on_target_test, windows_port
; ## On-target test environment for local linux pio remote client ##############
[env:on_target_test_linux]
    extends                   = env:on_target_test, linux_port
; ## On-target test environment for CI pipeline linux pio remote client ########
; using lib_extra_dirs instead of lib_deps for local libraries, because using lib_deps
; results in "[Errno 2] No such file or directory:" for all local libraries.
; (When run from linux docker container the tests execute properly using
; on_target_test_linux)
[env:on_target_test_linux_ci]
    extends                   = env:on_target_test, linux_port
    lib_deps                  = ${test.lib_deps}
                                fmtlib/fmt@^8.1.1
                                ${on_target.lib_deps}
    lib_extra_dirs            = lib/Components/
                                lib/Compositions/Actors/

For remote testing from local windows or local linux docker env:on_target_test_linux works however for the CI pipeline I have to use on_target_test_linux_ci. So it seems using Windows client lib_extra_dirs resulted in an error, but the CI pipeline running Linux only works using lib_extra_dirs.

I would prefer using lib_deps for all environments in the future, could you maybe give me a suggestion where I’m making the mistake?