Affordable and flexible platform to ease prototyping using a STM32F401RET6 microcontroller.

CoIDE mbed offline compile F401RE

15 Apr 2014

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

15 Apr 2014

Hi Jörg, thank you for writing this up. Is there any way you can share your mbed library CoIDE project and the blink CoIDE project somewhere/somehow? Your instructions are pretty good, but I am sure I would miss a step somewhere ...

Thanks, Michael

24 Apr 2014

/media/uploads/tham/gpio.rar I'm follow you with CoIDE, Jorg. Thank you for your information. It's work and can be debuged correctly but I'm not sure the clock (that I set) is set correctly. Please check....

25 Apr 2014

/media/uploads/tham/bmp085.rar With CoIDE, I try to connect with bmp085(i2c) and display on glcd5110, it's work. (library : use base C library, FPU : FPU hard)

08 May 2014

I have just read this today. I was not certain if CoIDE supports new nucleo boards. If it does, it should not be a problem to add exporters for mbed.

I might find time to do that.

Regards,
0xc0170

17 Aug 2014

Oh , wonderful information.. mbed twicked the startup function to resetHandler() , most case main() is userlevel startup function. So, on embedded works, we needs to check LD scripts. what's startup.s has bootup and linking the main() function.

19 Aug 2014

On CoIDE, program has bootup in startup_stm32f4xx.c file and linking to main() function. If you would not comment out "extern void SystemInit(void); in startup_stm32f4xx.c", it wil link to system_stm32f4xx.c to startup system clock before go to main() then you must comment out SystemInit(); in the main() function.

27 Oct 2014

I have just stumbled upon this: "mbed for CoIDE (nucleo platforms stm32f401re and stm32l152re)":

http://www.coocox.org/forum/topic.php?id=4418

These are sample projects for coocox.

27 Oct 2014

Thanks for sharing.

Coide should be in the mbed enabled for these targets (some are only available offline in mbed SDK):

        'KL25Z',
        'KL05Z',
        'LPC1768',
        'ARCH_PRO',
        'DISCO_F407VG',
        'NUCLEO_F334R8',
        'NUCLEO_F401RE',
        'NUCLEO_F411RE',
        'DISCO_F429ZI'
27 Oct 2014

I own NUCLEO_F401RE and when I export a project from mbed to coocox I get "ld.exe cannot open linker script" error when builing it... I checked and there is no .ld file anywhere in the zip being exported. I am quite new to this (nucleo & coocoox) so maybe I'm not grasping it right yet... Anyway help would be appreciated.

27 Oct 2014

Ok. I now know I need to download SDK for my platform from: https://developer.mbed.org/users/mbed_official/code/mbed/ But when click, "Export to desktop IDE", and select my platform (ST Nucleo F401RE) and toolchain (either GccArm or CoIde) I get the "Page error". The same goes for mbed-src (GccArm & CoIde). The only way to get the SDK was to import the mbed-src to mbed web IDE and then to export it from there.

13 Nov 2014

Hello,

thanks a lot for this post. It was very useful to me. I was able to create a coocox (version 1.7.7) project for my Nucleo-F401 board.

But there are some more things that need to be modified in system_stm32f4xx.c concerning the clock setup. Coocox SetSysClock function is configured for a 168MHz device, so there is the need to correct also the APB1 (low speed) and APB2 (high-speed) prescallers. Default values result in AHB clock/2 for APB2 and AHB clock/4 for APB1. These numbers are 42MHz for APB2 and 21MHz for APB1. The F401 device can handle 84MHz for APB2 and 42MHz for APB1. To obtain the maximum frequencies you have to change the prescallers in SetSysClock function:

    /* PCLK2 = HCLK / 1 - APB2 clock */ 
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK / 2 - APB1 clock */
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;

I also modified that function to use the external 8MHz clock from STLink that is connected by default in my version of the nucleo board. I only added the line

RCC->CR |= ((uint32_t)RCC_CR_HSEBYP);

before RCC->CR |= ((uint32_t)RCC_CR_HSEON); in the beginning of the SetSysClock function and changed HSE_VALUE to 8000000 in stm32f4xx.h I also optimized the flash read latency, reducing the wait states from 5 (default) to 2, according to table 6 in the reference manual, and enabling the Instruction Prefetch. The corresponding line in SetSysClock function is:

FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;

Best regards,

Miguel Florianopolis, Brazil.