Unable to run pure C program on STM32F030

jbeik wrote on Thursday, November 13, 2014:

Hello,

I’m trying to run a test program on a Cortex M0. Without any real success.

I can flash internal memory but my program does not run as expected. In a first time, I only try to switch on and of PB12 line (GPIO).

My configuration:

  • FreeRTOSV8.1.2
  • gcc 4.9.1 (bare metal)
  • STM32F030

I have written a pure C test program. Thus I have used the following ldscript:

OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
          "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(Reset_Handler)
SEARCH_DIR(".");

MEMORY
{
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
    RAM  (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}

SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        KEEP(*(.isr_vector))
        *(.text)
        *(.text*)
        *(.rodata)
        *(.rodata*)
        . = ALIGN(4);
    } > FLASH

    _data_flash = .;

    .data : AT ( _data_flash )
    {
        . = ALIGN(4);
        _data_begin = .;
        *(.data)
        *(.data*)
        . = ALIGN(4);
        _data_end = .;
    } > RAM

    .bss :
    {
        . = ALIGN(4);
        _bss_begin = .;
        __bss_start__ = _bss_begin;
        *(.bss)
        *(.bss*)
        *(COMMON)
        . = ALIGN(4);
        _bss_end = .;
        __bss_end__ = _bss_end;
    } > RAM

    _stack_size = 1024;
    _stack_end = ORIGIN(RAM)+LENGTH(RAM);
    _stack_begin = _stack_end - _stack_size;
    . = _stack_begin;
    ._stack :
    {
        . = . + _stack_size;
    } > RAM
}

Loader is:

extern unsigned long _data_flash;
extern unsigned long _data_begin;
extern unsigned long _data_end;
extern unsigned long _bss_begin;
extern unsigned long _bss_end;
extern unsigned long _stack_end;

extern void startup(void);

void
Reset_Handler(void)
{
    unsigned long *source;
    unsigned long *destination;

    // Copying data from Flash to RAM
    source = &_data_flash;
    for(destination = &_data_begin; destination < &_data_end;)
    {
        *(destination++) = *(source++);
    }

    // default zero to undefined variables
    for(destination = &_bss_begin; destination < &_bss_end;)
    {
        *(destination++) = 0;
    }

    // starting main program
    startup();
    for(;;);
}

void
Default_Handler(void)
{
    for(;;);
}

__attribute__ ((section(".isr_vector")))
void (* const table_interrupt_vector[])(void) =
{
    (void *) &_stack_end,   // 0  - initial stack pointer
    Reset_Handler,          // 1  - initial PC
    Default_Handler,        // 2  - NMI
    Default_Handler,        // 3  - hard fault
...
    Default_Handler,        // 45 - Irq 29
    Default_Handler,        // 46 - Irq 30
    Default_Handler,        // 47 - Irq 31
};

My test program is only :

#include "FreeRTOS.h"
#include "task.h"
#include "stm32f0xx_conf.h"

void
startup(void)
{
    GPIO_InitTypeDef    gpio_init;

    RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOB, ENABLE);

    RCC_RTCResetCmd(ENABLE);
    RCC_RTCResetCmd(DISABLE);

    RCC_HSEConfig(RCC_HSE_Bypass);
    RCC_LSEConfig(RCC_LSE_ON);
    while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);

    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

    gpio_init.GPIO_Pin = GPIO_Pin_12;
    gpio_init.GPIO_Mode  = GPIO_Mode_OUT;
    gpio_init.GPIO_Speed = GPIO_Speed_Level_1;
    gpio_init.GPIO_OType = GPIO_OType_PP;
    gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOB, &gpio_init);

    for(;;)
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        vTaskDelay(100);
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
        vTaskDelay(100);
    }
}

I can build this test program without any trouble. I have checked with objdump that assembly output is correct:

image.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <table_interrupt_vector>:
        ...

080000c0 <Reset_Handler>:
 80000c0:       b580            push    {r7, lr}
 80000c2:       b082            sub     sp, #8
 80000c4:       af00            add     r7, sp, #0
 80000c6:       f240 0300       movw    r3, #0
 80000ca:       f2c0 0300       movt    r3, #0
 80000ce:       607b            str     r3, [r7, #4]
 80000d0:       f240 0300       movw    r3, #0
 80000d4:       f2c0 0300       movt    r3, #0
 80000d8:       603b            str     r3, [r7, #0]
 80000da:       e007            b.n     80000ec <Reset_Handler+0x2c>
...

I suppose I have done a mistake. But where ? Any ideas ?

Thanks a lot in advance,

JB

rtel wrote on Thursday, November 13, 2014:

It is always recommended to create a new project by editing the official demo for the port you are using - that way everything is pre-configured for you and in a known working state. If there is not an exact match for your port then chose the closest match. You should not need to create the low level stuff yourself unless you are the device manufacturer doing the first board bring up.

http://www.freertos.org/FreeRTOS-quick-start-guide.html
http://www.freertos.org/Creating-a-new-FreeRTOS-project.html
http://www.freertos.org/porting-a-freertos-demo-to-different-hardware.html

In this case it looks simply like you are trying to use FreeRTOS API functions that will place the calling task in the Blocked state without first creating a task or starting the scheduler. There are literally hundreds of demos you can use as a template for how to create tasks and start the scheduler, so your vTaskDelay() calls are called from within a task. This is perhaps a good generic start:

http://www.freertos.org/Hardware-independent-RTOS-example.html

There is also lots of information on the FreeRTOS website showing how to do this, the tutorial books, etc.

Regards.