PlatformIO Community

How to use independently loaded and installed ARM compiler in PlatformIO?

Hi, I am confused with a mix of different toolchains and libraries that do no work together with several examples i tried. For STM32F103, I wanted to use original ARM compiler ( [gcc-arm-none-eabi-10-2020-q4-major-win32.exe]) and original most recent libopencm3. I downloaded both and used included makefile to build the library which completed flawlessly. I used to develop in Eclipse where mapping IDE to these was trivial. I was advised to try Platformio and here it is tricky.
Now I am wondering is there an easy way to switch the compiler/linker and map the precompiled/built libraries into Platformio project. Specifically, I want to have compiler installed on C:/ARM/Toolchain, and libopencm3 in C:/Platformio/libopemcm folders.
So far I was not able to find where I can change the path to toolchain and library. Platformio insists on the toolchain installed from somewhere in /packages folder, and there are no easy instructions how to remove and repoint it.
Does anyone has same problem and is there an easy solution? Thanks!

What exact error are you running into? Have you tried running our libopencm3 blinky example first? I highly doubt that that is due to the framework version or compiler version. Above example works just fine.

C:\Users\Max\.platformio\platforms\ststm32\examples\libopencm3-blink>pio run -e nucleo_f103rb
Processing nucleo_f103rb (platform: ststm32; framework: libopencm3; board: nucleo_f103rb)
------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/ststm32/nucleo_f103rb.html
PLATFORM: ST STM32 (13.0.0) > ST Nucleo F103RB
HARDWARE: STM32F103RBT6 72MHz, 20KB RAM, 128KB Flash
DEBUG: Current (stlink) On-board (stlink) External (blackmagic, cmsis-dap, jlink)
PACKAGES:
 - framework-libopencm3 1.10000.200730 (1.0.0)
 - 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 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio\build\nucleo_f103rb\src\main.o
Generating linker script .pio\build\nucleo_f103rb\generated.stm32f103rb.ld
Compiling .pio\build\nucleo_f103rb\FrameworkLibOpenCM3\lib\stm32\f1\adc.o
[...]
Indexing .pio\build\nucleo_f103rb\libFrameworkLibOpenCM3.a
Linking .pio\build\nucleo_f103rb\firmware.elf
Checking size .pio\build\nucleo_f103rb\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   0.0% (used 0 bytes from 20480 bytes)
Flash: [          ]   0.5% (used 688 bytes from 131072 bytes)
Building .pio\build\nucleo_f103rb\firmware.bin
=============== [SUCCESS] Took 3.34 seconds ===============

platform_packages for framework-libopencm3 and toolchain-gccarmnoneeabi.

The trivial examples for “blinky” do work. The problem comes later when I try to do something serious from open source fragments. For instance, software using USB CDC device class, I2C drivers and FreeRTOS. It does not work in the combination of generic board and F1xx series processor.

For instance, there is gpio_set_mode() and gpio_mode_setup() which do same things in libopencm3 for STM32F103 and STM32F407. It is unclear which version of libopencm3 platformio installs and from where - from the sources it looks that it is no the mainstream version but rather something that was modified by Platformio community.
The same about compiler - I’d prefer to use the one which is warrantied by ARM directly; it is unclear where platformio takes them because versioning is different.
As the result, platformio nicely compiles only the minimum examples of entire projects created and maintained in it (like maple 3D printer), but fails to reliably work out of the box for new projects involving more.
In the attempt to have reliable versions, I tried to rebuild libopencm3 - it is a make project, and platformio build system does not do it out of the box. So I used the recommended process with ARM compiler and now I have *.a versions which I am trusting. I also replaced (copied) the ARM compiler into the packages folder which platformio used to store its compiler. It did not change a lot, I still cannot link (include in the link command line) the *.a library (in my additional question).

So my question here is not about “why don’t you use platformio-supplied compiler”, but rather "how to configure platformio to use ARM-supplied and maintained compiler located at a default or any other installation locations. I.e. how to repoint the toolchain path?
Thanks!

No it’s not. Per package info the latest version is framework-libopencm3-1.10000.200730 meaning LibOpenCM3 as of 2020 July 30th, which maps to the state at commit 24bef9c4. If you pull that commit and execute maketo generate the nvic.h header files, you will see that, e.g. with Meld as a comparison tool, it is exactly the same as the what PlatformIO packages currently.

Code that interfaces with libopencm3 must then also be compatible withthat version – or libopencm3 must be updated, as per above.

Indeed libopencm3 is not a PlatformIO project. It has no platformio.ini or anything and isn’t intended to be one. However, you can use it as a package source for framework-libopencm3.

Per above

Per package info the latest attainable version is toolchain-gccarmnoneeabi-windows_amd64-1.90301.200702 so that’s 9.3.1. Since you seem to be wanting gcc-arm-none-eabi-10-2020-q4-major-win32.exe from a local installation, you’ll need to point the package source to a local path. As documented here, the general file:// protocol works. Mind that for PlatformIO to recognize something as a valid package source, the root folder of the package will need to have package.json akin to what you see in C:\Users\<user>\.platformio\packages\toolchain-gccarmnoneeabi\package.json with update version information. (Equivalent if you want to change the libopencm3 source).

Please have a look at GitHub - maxgerhardt/pio-example-latest-libopencm3. I’m having no problems at all using the bleeding-edge libopencm3 version with the newest 9.3.1 GCC from PlatformIO’s repos. The example coded per here just works, I’ve personally tested it on my Bluepill.

Maximilian, thanks a lot for the attention and care. It would be nice to explain what you did here in mainstream documentation - so it could be easily found. What happens in the community development is that bits and pieces are modified independently, and there may be some incompatibility. I tried to eliminate it by using examples from the book about freeRTOS with the files here:
git clone https://github.com/ve3wwg/stm32f103c8t6.git

As a sanity check, I compiled blinky and blinky2 and usbcdcdemo examples with the make file and independently loaded arm compiler: 10_2020-q4-major. The created binary files work.

Then I tried to compile the same with the platformio/libopencm3 combo. I was able to compile with “Success” status and generate binary, and upload it to the target. But it does not work. A deeper investigation shows that it experiences exception and ends in a blocking handler, somehow apparently related to UART3 interrupt (not touched with the program). In order to double check, I copied the same libopencm3 which was used for independent compilation to the the /packages, ovewriting platformio version. The result is the same - it does not work and ends in exception immediately.
There may be something very simple that I may be missing…

I will try once more, but it would be great (not sure I am not asking too much) if you try the same independently on your side and confirm if it works or not. Thanks again!

I cannot reproduce your problems. When I take the sourcefiles of rtos/blinky and add a standard platformio.ini to it, and remove/rename all the extra heap_x.c implementations in there, and upload it, my bluepill does the blinky, no problems. See GitHub - maxgerhardt/pio-libopencm3-rtos-blinky.

The same is true when I test the blinky2 example code. That is, exchange the contents of this with this. I get a perfect 1 on-and-off per second with it provided by vTaskDelay(pdMS_TO_TICKS(500));, so the scheduler is all-functional…

Maximilian, the magic happened. I am not sure what is different, but this time it works. I did not use -Isrc and -I src/rtos before, I expected that it will find them when placed in the /include directory and it did not complain…

Anyway, thanks a lot for your help, and I think that the problem was in the absence of a good step-by-step manual which tells how to configure and build a simple application with accompanying sources and platformio.ini files. Then you can point at it and say RTFM. But without it there are too many options to play with.

I also think that it is not a great idea to creatively modify the names of the libraries by the tool (eg. removing “lib” from the name). If it is done under the hood and different from other tools, it is misleading despite the beauty of the concept…

I hope that it could be a shorter path if a document like “step-by-step” guide with explanation what each step was doing, the first-time user could be better…

Thanks again!

1 Like

And finally, how could I know that heap_c.c is a problem?

One more question: I discovered the difference! I had /rtos placed in /lib folder, not in the /src/rtos as you did. The documentation says that /lib is for included libraries, and the will be automatically linked. So I placed it there, and compilation completes successfully. But when loaded, the application does not work.

I tried with your git image: it behaves the same way. Create a /lib in the project, and place /rtos there. Use exactly same configuration file. You will see the difference: the LED does not blink anymore, and if debugged, one can see the exception. The binary files are different.

I am now confused what happens? I am assuming that while I can make library from /rtos, the end result of building the program will be identical, because the same elements will be linked to final binary. Maybe platformio does some mistake in linking switches or ldscript.
Here is the structure of .pio when /rtos is placed in /src:
image

And Here is the structure found in .pio when /rtos is placed in /lib folder:
image

If I compare these two file sets, I find different binaries, identical Framework and ldscript and main.o.
So it may mean that the librtos.a is created incorrectly? Or, maybe there is a problem with “weak” attributes?

image

What do you think?

Ok, found the difference, it is also described here:

With lib_archive = false both linkages result in working program. IMHO, since the interrupt handlers are very frequently defined with weak substitutes, the default archiving of the /lib folder resulted in two weeks of frustration with platformio for me. It is not same for other conventional tools. I think the default decision is wrong, and the tool should default to false always. If the developer knows what they are doing, they may explicitly alter the default. And it should be spelled in bold in “Beware” section.

Now the library generation appears to have no *.a generation.
image

Exactly – that’s a subtetly when linking with archive files created from library files. The default is that PlatformIO will link libraries as archives, not with direct object files, and thus stuff like overwriting _weak functions, especially the interrupt handlers, won’t work.

This setting is also part of pretty much all other existing FreeRTOS library, see e.g.

or as discussed in

I want to compile for the STM32 Blue Pill module but have not been able to get the right configuration. Also, I have been using MySensors for over 5 years: this is a great It could be because I used the ZIP file to install the Arduino IDE part of the STM32 core and does not need to be loaded separately.
NavyArmyCCU Login

I don’t see how this has anything to do with changing the compiler version discussed in this topic. Please open a new one with the exact project informatin (platformio.ini and code), and error messages.