The long road to get mbed compile offline in CoIDE using gcc-arm
...I've made it. As a hobbyist I hesitated long to switch from AVR to ARM because I was afraid about exploding code sizes, lots of configuration stuff to take care about, various clocks, etc. But recently I had a memory size problem on which I chose to think about switching to ARM. Especially when I had a look on the example code of mbed which was in the shape of what I had in mind of how I hoped code would look like. So I dared the change... and it turned out to be as hard and painful as I originally expected. Apparently there is no way around pain, but maybe sharing my experiences can help others.
As board to start with I chose STM32 Nucleo F401RE. The IDE of choice became CoIDE because of some recommendations of a friend and the net. The toolchain was actually no choice: GCC - because as hobbyist I hate depending on proprietary tool chains.
CoIDE
I really like the wizard for creating a project by which I can select the chip. Also, adding CMSIS files on the fly by clicking "GPIO" in the Repository tab was just delighting.
The first downside was that the F401RE device is not yet supported - as workaround I chose STM32F401RC which has less flash and RAM but I assume besides that they are just alike. In the CoIDE project linker configuration I adjusted IROM1 size from 0x00040000 to 0x00080000, IRAM1 from 0x00010000 to 0x00018000.
mbed
For my first mbed blink-led project I created an mbed library project (configuration - output tab) with the source from the mbed-src development branch - there I found code for the Nucleo F401RE board. To the project I added the api, common, hal and F401 specific target code in the mbed-src subdirectories. I turned on LTO and c++ support in the project configuration. After some attempts I got a fresh baked libmbed-f401.a
as result.
The mbed blink-led project consisted of the Nucleo_blink_led main.cpp
:
Nucleo_blink_led main.cpp
#include "mbed.h"
DigitalOut myled(LED1);
int main() {
while(1) {
myled = 1; // LED is ON
wait(0.2); // 200 ms
myled = 0; // LED is OFF
wait(1.0); // 1 sec
}
}
As additional library I added the created libmbed-f401re.a output of the library project. Additionally I had to add the C-Library because of unresolved externals. And, of course, a group mbed in which I stored the required mbed header files of the api and hal directories, as well as cmsis.h
, cmsis_nvic.h
and device.h
from the TARGET_NUCLEO_F401RE directors. Also, I turned on LTO support in hope to get smaller binaries.
Finally it compiled + linked with the code size of about 27KB. The online-compiler managed the same source with 7KB... Anyway, the F401 has 512KB flash. Build succeeded, but the code did not run. The LED stayed dark and the debugger identified that the PC (program counter register) was somewhere in Nirvana.
not mbed
Ok - then I thought I probably should not start with mbed, but with plain CMSIS code. Allright - it took me a while (!) to get the sources right for the actual CMSIS release CoIDE was offering: Here the code:
Light user LED for Nucleo F401
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
int main()
{
GPIO_InitTypeDef GPIO_InitStructure;
SystemInit();
// activate PORT A
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// config PortPin
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
while(1);
}
It took me a long time to figure out that I used RCC_APB1PeriphClockCmd()
instead of RCC_AHB1PeriphClockCmd()
which compiled fine but made the LED not shine. But even with this bug identified the LED was dark.
clocks and startup
There is finally no way around of going into the mud and making hands dirty by investigating stuff which is supposed to be hidden by libraries, etc. In short: in case of CMSIS only (non-mbed) the standard system_stm32f4xx.c
is configured using the external clock, but the Nucleo F401 unfortunately has no external oscillator. I had to modify the clock config in function SetSysClock()
in file system_stm32f4xx.c
by copying parameters from the mbed-version of this file: i.e. use HSI instead of HSE clock (use RCC_CR_HSION
, RCC_CR_HSIRDY
, RCC_PLLCFGR_PLLSRC_HSI
), adjust PLL values:
#define PLL_M 16
#define PLL_N 336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 4
/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
#define PLL_Q 7
Then, finally.... the LED shone using the non-mbed project.
mbed again
After having these experiences with non-mbed: mbed was still mmmbad - the mbed clock setup code configures the clocks correctly for the Nucleo board. It turned out that the next and actually finally obstacle was the startup code. Before getting too frustrated I found a suspicious parameter in the Link Configuration: --entry=main
. After some attempts with new projects I found out that when enabling LTO in CoIDE this option will be added automatically. Apparently it configures the linker to use main()
as entry function which is just wrong. I digged in the startup assembly and identified as entry function to try Reset_Handler()
. With changing the entry function parameter to --entry=Reset_Handler
it finally worked. As I already mentioned the code size is 27KB. Maybe there is a way to shrink that down further.
So finally CoIDE + mbed work with the Nucleo F401RE board. Hopefully these lines save you some pain.
Jörg
The long road to get mbed compile offline in CoIDE using gcc-arm
...I've made it. As a hobbyist I hesitated long to switch from AVR to ARM because I was afraid about exploding code sizes, lots of configuration stuff to take care about, various clocks, etc. But recently I had a memory size problem on which I chose to think about switching to ARM. Especially when I had a look on the example code of mbed which was in the shape of what I had in mind of how I hoped code would look like. So I dared the change... and it turned out to be as hard and painful as I originally expected. Apparently there is no way around pain, but maybe sharing my experiences can help others.
As board to start with I chose STM32 Nucleo F401RE. The IDE of choice became CoIDE because of some recommendations of a friend and the net. The toolchain was actually no choice: GCC - because as hobbyist I hate depending on proprietary tool chains.
CoIDE
I really like the wizard for creating a project by which I can select the chip. Also, adding CMSIS files on the fly by clicking "GPIO" in the Repository tab was just delighting. The first downside was that the F401RE device is not yet supported - as workaround I chose STM32F401RC which has less flash and RAM but I assume besides that they are just alike. In the CoIDE project linker configuration I adjusted IROM1 size from 0x00040000 to 0x00080000, IRAM1 from 0x00010000 to 0x00018000.
mbed
For my first mbed blink-led project I created an mbed library project (configuration - output tab) with the source from the mbed-src development branch - there I found code for the Nucleo F401RE board. To the project I added the api, common, hal and F401 specific target code in the mbed-src subdirectories. I turned on LTO and c++ support in the project configuration. After some attempts I got a fresh baked
libmbed-f401.a
as result.The mbed blink-led project consisted of the Nucleo_blink_led
main.cpp
:Nucleo_blink_led main.cpp
As additional library I added the created libmbed-f401re.a output of the library project. Additionally I had to add the C-Library because of unresolved externals. And, of course, a group mbed in which I stored the required mbed header files of the api and hal directories, as well as
cmsis.h
,cmsis_nvic.h
anddevice.h
from the TARGET_NUCLEO_F401RE directors. Also, I turned on LTO support in hope to get smaller binaries.Finally it compiled + linked with the code size of about 27KB. The online-compiler managed the same source with 7KB... Anyway, the F401 has 512KB flash. Build succeeded, but the code did not run. The LED stayed dark and the debugger identified that the PC (program counter register) was somewhere in Nirvana.
not mbed
Ok - then I thought I probably should not start with mbed, but with plain CMSIS code. Allright - it took me a while (!) to get the sources right for the actual CMSIS release CoIDE was offering: Here the code:
Light user LED for Nucleo F401
It took me a long time to figure out that I used
RCC_APB1PeriphClockCmd()
instead ofRCC_AHB1PeriphClockCmd()
which compiled fine but made the LED not shine. But even with this bug identified the LED was dark.clocks and startup
There is finally no way around of going into the mud and making hands dirty by investigating stuff which is supposed to be hidden by libraries, etc. In short: in case of CMSIS only (non-mbed) the standard
system_stm32f4xx.c
is configured using the external clock, but the Nucleo F401 unfortunately has no external oscillator. I had to modify the clock config in functionSetSysClock()
in filesystem_stm32f4xx.c
by copying parameters from the mbed-version of this file: i.e. use HSI instead of HSE clock (useRCC_CR_HSION
,RCC_CR_HSIRDY
,RCC_PLLCFGR_PLLSRC_HSI
), adjust PLL values:Then, finally.... the LED shone using the non-mbed project.
mbed again
After having these experiences with non-mbed: mbed was still mmmbad - the mbed clock setup code configures the clocks correctly for the Nucleo board. It turned out that the next and actually finally obstacle was the startup code. Before getting too frustrated I found a suspicious parameter in the Link Configuration: -
-entry=main
. After some attempts with new projects I found out that when enabling LTO in CoIDE this option will be added automatically. Apparently it configures the linker to usemain()
as entry function which is just wrong. I digged in the startup assembly and identified as entry function to tryReset_Handler()
. With changing the entry function parameter to --entry=Reset_Handler
it finally worked. As I already mentioned the code size is 27KB. Maybe there is a way to shrink that down further.So finally CoIDE + mbed work with the Nucleo F401RE board. Hopefully these lines save you some pain.
Jörg