Using STM32CubeMX and PlatformIO

Thanks for the tip @ivankravets. It works great.
Now only the linking of the library’s (FreeRTOS and LwIP) sources is left. Tried the -l and -L flags under build_dirs option with no success. What would you recommend?

Do you have archives (*.a) of these libraries?

No, their static-library files aren’t available. Would like to have those libraries shipped with their source-code. Does PlatformIO provide any option to build them first and link them while compiling user application?

Honestly, I don’t understand what are you going to do but you can move 3-rd party libraries/source code to project/lib folder and include them in main project. PIO will find them and build automatically.

Please read project/lib/readme.txt.

Thanks for your response. Have cleaned up the way sources and headers of 3rd party libraries are included by placing them in lib/ and changing _#include_s accordingly. The linking problem that I am facing now has come down to this issue reported here.
How to pass flags to final firmware.elf linkage?.
Fails to pick up hard floating-point flags while linking.

Could you provide full output of pio run -v on https://hastebin.com ?

Sure. Here’s the link : https://hastebin.com/osotijexah.sql
Thanks!

Could you try lib_archive = false?

Hey… gave it a try to see whether I could (force) link the object files. Same error persists.

Copying every *.c and *.h files inside the Middlewares directory into lib/your_preferred_name will solve the problem.
I wrote small scripts and specify it to extra_scripts in platformio.ini, then it worked for me.

import os
import os.path
import shutil

lib_path = os.path.join('lib', 'CubeMX_Middlewares')

shutil.rmtree(lib_path, ignore_errors=True)
os.mkdir(lib_path)

for root, dirs, files in os.walk('Middlewares'):
    for file in files:
        if file.endswith('.c') or file.endswith('.h'):
            shutil.copy2(os.path.join(root, file), lib_path)
2 Likes

Hi,

I have related question.

I have a project that was created for makefile with STM32CubeMX but I don’t have the STM32CubeMX project *.ioc file. I ported it to platform io using just the source and header and the linker script generated and it compiled.

The project comes with a startup script “startup_stm32f103xe.s” that is included in the original makefile, and is generated whenever STM32CubeMX generates a makefile configuration files.

My question is, does pio + stm32 framework generate this startup script automatically, or do I have to copy it over. If so, how can I include it in platformio.ini?

— EDIT
Found the answer by looking at the platform builder file here, the builder takes care of adding the startup file for specific stm32 boards. I’ll keep this here for reference.

1 Like

Incidentally, you don’t have to copy the files manually for the cubemx and platformio.

You can generate a cubemx project and initialise a project using Pio in the same directory. they share similar folder structure. the only difference IIRC is to add the ‘Inc’ and ‘Driver’ folders to the include folders and you should be good to go… That way you can regenerate the cube project and compile with platformio without redoing the whole project all over.

You must select the “retain user code” or some such option in the cubemx software and ensure that your code only exists within specific marked blocks (USER CODE BEGIN and END comments) in the generated files…
:slight_smile:

Custom LD script could be set via Redirecting...

I am trying to do exactly this but am having some trouble getting it to work. Did you set up your MX Cube project as outlined in the first post? Would you mind posting your platformio.ini file? Did you get this to work with any middlewares such as FreeRTOS?

Not as in the first post as it was too cumbersome but in the reply a couple of posts above.
Basically these are the steps…

  1. Create a new project in CubeMX

  2. Change to the appropriate settings in the settings section.
    These are mine.

  3. Then setup the device as you choose to in the cubemx software and generate code.

  4. The initialise a pio project in the same folder as that of the cubemx project and add a main.cpp to the src folder.

  5. this is what my directory structure looks like after new pio project and adding the main.cpp file.

    .
    ├── Core
    │ └── Inc
    │ ├── gpio.h
    │ ├── main.h
    │ ├── stm32f0xx_hal_conf.h
    │ └── stm32f0xx_it.h
    ├── Drivers
    │ ├── CMSIS
    │ │ ├── DSP_Lib
    │ │ ├── Device
    │ │ ├── Include
    │ │ ├── Lib
    │ │ └── RTOS
    │ └── STM32F0xx_HAL_Driver
    │ ├── Inc
    │ └── Src
    ├── disco_030_test.gpdsc
    ├── disco_030_test.ioc
    ├── lib
    │ └── readme.txt
    ├── platformio.ini
    ├── platformio.sublime-project
    └── src
    └── main.cpp

And this is what my platformio.ini file looks like.

; 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
; http://docs.platformio.org/page/projectconf.html

 [env:disco_f030r8]
 platform = ststm32
board = disco_f030r8
framework = stm32cube
build_flags = -ICore/Inc

I had to add the build_flags section for the main.cpp to “see” the generated headers…

This is my barebones main.cpp

#include "main.h"
#include "gpio.h"

int main()
{

	return 0;

}

And thats it… I was able to compile the project just fine…

this is my build output.

[ Deviot 2.3.0.dev3 ] Starting…
[Tue Jun 19 20:10:50 2018] Processing disco_f030r8 (platform: ststm32; board: disco_f030r8; framework: stm32cube)

Verbose mode can be enabled via -v, --verbose option
PLATFORM: ST STM32 > ST STM32F0308DISCOVERY
SYSTEM: STM32F030R8T6 48MHz 8KB RAM (64KB Flash)
DEBUG: CURRENT(stlink) ON-BOARD(stlink) EXTERNAL(blackmagic, jlink)
Library Dependency Finder → Library Dependency Finder (LDF) — PlatformIO latest documentation
LDF MODES: FINDER(chain) COMPATIBILITY(soft)
Collected 0 compatible libraries
Scanning dependencies…
No dependencies
Compiling .pioenvs/disco_f030r8/src/main.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_can.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_cec.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_comp.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_cortex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_crc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_crc_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_dac.o
/Users/srikrishnachaitanyanarumanchi/.platformio/packages/framework-stm32cube/f0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_crc.c: In function ‘CRC_Handle_8’:
/Users/srikrishnachaitanyanarumanchi/.platformio/packages/framework-stm32cube/f0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_crc.c:475:8: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
(uint16_t volatile) (&hcrc->Instance->DR) = ((uint32_t)pBuffer[4i]<<8) | (uint32_t)pBuffer[4i+1];
^
/Users/srikrishnachaitanyanarumanchi/.platformio/packages/framework-stm32cube/f0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_crc.c:479:8: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
(uint16_t volatile) (&hcrc->Instance->DR) = ((uint32_t)pBuffer[4i]<<8) | (uint32_t)pBuffer[4i+1];
^
/Users/srikrishnachaitanyanarumanchi/.platformio/packages/framework-stm32cube/f0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_crc.c: In function ‘CRC_Handle_16’:
/Users/srikrishnachaitanyanarumanchi/.platformio/packages/framework-stm32cube/f0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_crc.c:511:8: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
(uint16_t volatile) (&hcrc->Instance->DR) = pBuffer[2*i];
^
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_dac_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_dma.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_flash.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_flash_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_gpio.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_i2c.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_i2c_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_i2s.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_irda.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_iwdg.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_pcd.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_pcd_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_pwr.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_pwr_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_rcc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_rcc_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_rtc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_rtc_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_smartcard.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_smartcard_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_smbus.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_spi.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_spi_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_tim.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_tim_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_tsc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_uart.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_uart_ex.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_usart.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_hal_wwdg.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_adc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_comp.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_crc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_crs.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_dac.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_dma.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_exti.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_gpio.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_i2c.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_pwr.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_rcc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_rtc.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_spi.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_tim.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_usart.o
Compiling .pioenvs/disco_f030r8/FrameworkHALDriver/Src/stm32f0xx_ll_utils.o
Compiling .pioenvs/disco_f030r8/FrameworkCMSISDevice/gcc/startup_stm32f030x8.o
Compiling .pioenvs/disco_f030r8/FrameworkCMSISDevice/system_stm32f0xx.o
Archiving .pioenvs/disco_f030r8/libFrameworkHALDriver.a
Archiving .pioenvs/disco_f030r8/libFrameworkCMSISDevice.a
Indexing .pioenvs/disco_f030r8/libFrameworkHALDriver.a
Indexing .pioenvs/disco_f030r8/libFrameworkCMSISDevice.a
Linking .pioenvs/disco_f030r8/firmware.elf
Checking size .pioenvs/disco_f030r8/firmware.elf
Building .pioenvs/disco_f030r8/firmware.bin
Memory Usage → Redirecting...
DATA: [ ] 0.3% (used 28 bytes from 8192 bytes)
PROGRAM: [ ] 0.5% (used 352 bytes from 65536 bytes)
========================= [SUCCESS] Took 5.13 seconds =========================

The advantage of doing the project this way is that you can make any changes to the cubemx settings again and again… and yet not redo the entire process of platformio. If you place your code in the

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

section in the headers… you won’t lose your code when you regenerate the cubemx code headers…

PS: I forgot to add, I did not test this with any middlewares. I have not worked on any project that needed them.

Hope this helps… :slight_smile:

3 Likes

Can you tell me what version of CubeMx you are using? Thanks very much.

I am using the latest version V4.26.0.

PlatformIO seems to be great if you are using a board that is made by someone else. It is not obvious to me how to proceed if I have my own custom designed board. Seems like you would get alot more adoption of your tools if you could accommodate those who design their own boards. Specifically I use STM32 series and I use FreeRtos. I have been reading documentation and threads all day and have still not succeeded in setting up the tools for my custom board. Is there a guide you can point me to? Maybe the folks at PlatformIO could make a Youtube video or a short write up. All documentation I am finding assumes you are using some board already in the eco system.

It is pretty straightforward to add you own custom board in platformio.
Please go through this link.

http://docs.platformio.org/en/latest/platforms/creating_board.html

Irrespective of the processor in question, the frameworks, upload_protocols are pretty much the same.
You can specify additional parameters like RAM/ROM, build flags and/or the VID/PID of the programmer/device.

I hope this helps you create you own custom board. :slight_smile:

OK this looks promising. Thanks for sharing and helping. I will give it another try. I think the major point I was missing that is explained in your link is how to tell platformio about your new board file.