FreeRTOS + libopecm3. The very simple task hardfault.

I have stucked with integrating FreeRTOS into my libopencm3 project for stm32f205. Finally I reduced the code to the minimal and it still goes to a hardfault. Here is my main code. Just a task and UART. No interrupts, no queues. Just send and wait. However crash appears. It looks like that crash appears when performing context switch and the symptoms are similar to that of stack overflow. Nevetheless task is provided tish 4k bytes of stack which should be enough for such a simple task. Also I have checked NVIC IPR registers for enabled interrupts – there are no. On top of that I have tried two different FreeRTOS version: one from the official sourceforge repo and one generate by ST’s Cube. ~~~

include <string.h>

include <libopencm3/cm3/scb.h>

include <libopencm3/stm32/usart.h>

include <libopencm3/stm32/gpio.h>

include <libopencm3/stm32/rcc.h>

include “FreeRTOS.h”

include “task.h”

void init(void); static void simpletask(void *pparam) { (void)p_param;
const char *str = "Hello from dummy taskrn";
for(;;)
{
    for(uint32_t i=0; i<strlen(str); i++)
    {
        usart_wait_send_ready(UART5);
        usart_send(UART5, str[i]);
    }

    vTaskDelay(100);
}
} int main(void) { TaskHandlet hndl; init(); if(xTaskCreate(simpletask, “SimpleTask”, 1024, NULL, 1, &hndl) != pdPASS) { for(;;); }
vTaskStartScheduler();

for(;;);

return 0;
} void init(void) { // setup clock struct rccclockscale clock = rcchse8mhz3v3[RCCCLOCK3V3120MHZ]; rccclocksetuphse3v3(&clock);
scb_set_priority_grouping(SCB_AIRCR_PRIGROUP_GROUP16_NOSUB);

rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);

/* Configure UART */
gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12);
gpio_set_output_options(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO12);
gpio_set_af(GPIOC, GPIO_AF8, GPIO12);

rcc_periph_clock_enable(RCC_UART5);

usart_set_baudrate(UART5, 921600);
usart_set_databits(UART5, 8);
usart_set_parity(UART5, USART_PARITY_NONE);
usart_set_stopbits(UART5, USART_CR2_STOPBITS_1);
usart_set_mode(UART5, USART_MODE_TX);
usart_set_flow_control(UART5, USART_FLOWCONTROL_NONE);
usart_enable(UART5);
} ~~~ FreeRTOS config: ~~~

ifndef FREERTOSCONFIGH

define FREERTOSCONFIGH

/* Ensure stdint is only used by the compiler, and not the assembler. */

if defined(ICCARM) || defined(CC_ARM) || defined(GNUC__)

#include <stdint.h>

endif

define configUSE_PREEMPTION 1

define configSUPPORTSTATICALLOCATION 0

define configSUPPORTDYNAMICALLOCATION 1

define configUSEIDLEHOOK 1

define configUSETICKHOOK 1

define configCPUCLOCKHZ ( 120000000 )

define configTICKRATEHZ ((TickType_t)1000)

define configMAX_PRIORITIES ( 7 )

define configMINIMALSTACKSIZE ((uint16_t)256)

define configTOTALHEAPSIZE ((size_t)48*1024)

define configMAXTASKNAME_LEN ( 16 )

define configUSETRACEFACILITY 1

define configUSE16BIT_TICKS 0

define configUSE_MUTEXES 1

define configQUEUEREGISTRYSIZE 8

define configCHECKFORSTACK_OVERFLOW 2

define configUSEMALLOCFAILED_HOOK 1

define configUSEPORTOPTIMISEDTASKSELECTION 1

define configUSEHEAPSCHEME 4

/* Co-routine definitions. */

define configUSECOROUTINES 0

define configMAXCOROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */

define INCLUDE_vTaskPrioritySet 1

define INCLUDE_uxTaskPriorityGet 1

define INCLUDE_vTaskDelete 1

define INCLUDE_vTaskCleanUpResources 0

define INCLUDE_vTaskSuspend 1

define INCLUDE_vTaskDelayUntil 0

define INCLUDE_vTaskDelay 1

define INCLUDE_xTaskGetSchedulerState 1

/* Cortex-M specific definitions. */

ifdef __NVICPRIOBITS

/* __BVICPRIOBITS will be specified when CMSIS is being used. */ #define configPRIO_BITS __NVIC_PRIO_BITS

else

#define configPRIO_BITS 4

endif

/* The lowest interrupt priority that can be used in a call to a “set priority” function. */

define configLIBRARYLOWESTINTERRUPT_PRIORITY 15

/* The highest interrupt priority that can be used by any interrupt service routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values. */

define configLIBRARYMAXSYSCALLINTERRUPTPRIORITY 5

/* Interrupt priorities used by the kernel port layer itself. These are generic to all Cortex-M ports, and do not rely on any particular library functions. */

define configKERNELINTERRUPTPRIORITY ( configLIBRARYLOWESTINTERRUPTPRIORITY << (8 – configPRIOBITS) )

/* !!!! configMAXSYSCALLINTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */

define configMAXSYSCALLINTERRUPTPRIORITY ( configLIBRARYMAXSYSCALLINTERRUPTPRIORITY << (8 – configPRIOBITS) )

/* Normal assert() semantics without relying on the provision of an assert.h header file. / / USER CODE BEGIN 1 */

define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}

/* USER CODE END 1 */ /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS standard names. */

define vPortSVCHandler svcallhandler

define xPortPendSVHandler pendsvhandler

/* IMPORTANT: This define MUST be commented when used with STM32Cube firmware, to prevent overwriting SysTick_Handler defined within STM32Cube HAL */

define xPortSysTickHandler systickhandler

/* USER CODE BEGIN Defines /
/
Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) / / USER CODE END Defines */

endif /* FREERTOSCONFIGH */

~~~ Startup( I don’t know actually where problem can be so I provide it too): ~~~ .syntax unified .text .global memsetreg .type memsetreg, STTFUNC memsetreg: // call with the following (note that the arguments are not validated prior to use): // r0 – address of first word to write (inclusive) // r1 – address of first word following the address in r0 to NOT write (exclusive) // r2 – word value to be written // both addresses in r0 and r1 needs to be divisible by 4! .Lloopbegin: str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed cmp r0, r1 bne .Lloopbegin bx lr .global resethandler .type resethandler, STTFUNC resethandler: ldr r0, =ramstart // r0 – point to beginning of SRAM ldr r1, =ramend // r1 – point to byte after the end of SRAM ldr r2, =0 // r2 – the byte-sized value to be written bl memset_reg // copy .data section from flash to SRAM ldr r0, =data // dst addr ldr r1, =dataloadaddr // src addr ldr r2, =data_size // length in bytes bl memcpy // enter the application code bl main // shutdown if the application code returns b shutdown .global shutdown .type shutdown, STTFUNC shutdown: cpsid f ldr r0, =0 mov r1, r0 mov r2, r0 mov r3, r0 mov r4, r0 mov r5, r0 mov r6, r0 mov r7, r0 mov r8, r0 mov r9, r0 mov r10, r0 mov r11, r0 mov r12, r0 ldr lr, =0xffffffff ldr r0, =ramstart ldr r1, =ramend // set to value in r2 bl memsetreg b . // loop forever .ltorg // dump literal pool (for the ldr …,=… commands above) ~~~ Linker script: ~~~ /* STM32F205RG – 1024K Flash, 128K RAM */ MEMORY { rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } /* SECTIONS { .confidential (NOLOAD) : { (confidential) ASSERT ((SIZEOF(.confidential) <= 33K), “Error: Confidential section too big!”); } >ram }/ INCLUDE libopencm3_stm32f2.ld ramstart = ORIGIN(ram); ramend = ORIGIN(ram) + LENGTH(ram); stack = _ramend – 8; stacklimit = _stack – end; __stack_chk_guard = _ram_end – 8; system_millis = _ram_end – 4; datasize = SIZEOF(.data); ~~~ libopencm3_stm32f2.ld: ~~~ /* Generic linker script for STM32 targets using libopencm3. */ /* Memory regions must be defined in the ld script which includes this one. */ /* Enforce emmition of the vector table. */ EXTERN (vector_table) /* Define the entry point of the output file. */ ENTRY(reset_handler) /* Define sections. / SECTIONS { .text : { *(.vectors) / Vector table / *(.text) /* Program code / . = ALIGN(4); *(.rodata) /* Read-only data */ . = ALIGN(4); } >rom
/* C++ Static constructors/destructors, also used for __attribute__
 * ((constructor)) and the likes */
.preinit_array : {
    . = ALIGN(4);
    __preinit_array_start = .;
    KEEP (*(.preinit_array))
    __preinit_array_end = .;
} >rom
.init_array : {
    . = ALIGN(4);
    __init_array_start = .;
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array))
    __init_array_end = .;
} >rom
.fini_array : {
    . = ALIGN(4);
    __fini_array_start = .;
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    __fini_array_end = .;
} >rom

/*
 * Another section used by C++ stuff, appears when using newlib with
 * 64bit (long long) printf support
 */
.ARM.extab : {
    *(.ARM.extab*)
} >rom
.ARM.exidx : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
} >rom

. = ALIGN(4);
_etext = .;

.data : {
    _data = .;
    *(.data*)   /* Read-write initialized data */
    . = ALIGN(4);
    _edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);

.bss : {
    *(.bss*)    /* Read-write zero initialized data */
    *(COMMON)
    . = ALIGN(4);
    _ebss = .;
} >ram

/*
 * The .eh_frame section appears to be used for C++ exception handling.
 * You may need to fix this if you're using C++.
 */
/DISCARD/ : { *(.eh_frame) }

. = ALIGN(4);
end = .;
} PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); ~~~

FreeRTOS + libopecm3. The very simple task hardfault.

As this is not using interrupts, and will therefore run sequentially, have you tried stepping through the code to see where the hardfault occurs? Do any characters get sent? Does the tick interrupt increase (set a break point on the vTaskIncrementTick() function in FreeRTOS/Source/tasks.c). You can also use the code on this page to determine where the hardfault occurs https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

FreeRTOS + libopecm3. The very simple task hardfault.

Thanks for the answer! I have just a minute ago found a problem. The issue is that of enabled stack smashing protector which is enabled by GCC option -fstack-protector-all. It places word on a stack when entering a function and check the value on function return. I don’t know how exactly it caused the fault but disabling it solved all the problems.