Hardfault in Task Scheduling [STM32f107]

skikepok wrote on Thursday, November 15, 2012:


First, thank you for the FreeRTOS project.

My code is based on the “CORTEX_STM32F107_GCC_Rowley” DEMO.

I tried to create a FreeRTOS project launching a simple task. but after almost
5 seconds, the application crash unexpectedly.
I looked for the crashing part but I could not identify it.

I tried to remove my simple task but the application still crash; that is why
I think there is a problem in my configuration of the task scheduler.

This is my main:

int main( void )

So there is only the Idle task running.

With only this task, my application still crash and I don’t understand either why or where.

I didn’t modify a lot of file and certainly not task.c or task.h

This is my STM32F10x_Startup.S file.
This is my thumb_crt0.S file.

There is my compilation flags (using arm-none-eabi-gcc):

-DPACK_STRUCT_END="__attribute((packed))" -DALIGN_STRUCT_END="__attribute((aligned(4)))" -DNULL="(void *)0" -DSTARTUP_FROM_RESET -c -fno-common -O0 -g -mcpu=cortex-m3 -mthumb -ggdb -std=c99

Does someone have an idea of what could be wrong ?



rtel wrote on Thursday, November 15, 2012:

You say you are starting from CORTEX_STM32F107_GCC_Rowley, and that you are using an STM32F107, so if you are starting from a project that targets the processor you want to use, but not using the project unmodified, is it a fair assumption that you are not actually using the Rowley tools?

If that is the case, which tools are you using, and do they come with a project for the STM32F107 that you could pinch the start up files from?

If you do change start up files, make sure to read FAQ 1 on the following page for info on setting up the vector table:


skikepok wrote on Friday, November 16, 2012:

I am using arm-none-eabi-gcc with a Makefile, editing files with emacs.
(My Makefile)

I am not using the Rowley tools but I think it should work without it. I am right ?
I just read the configuration files of the Rowley tools and gather all needed files in my project directory.

I have followed the FAQ when I started my tasks, there is my vector table after preprocessing:

  .word __stack_end__
  .word reset_handler
  .word NMIException
  .word HardFaultException
  .word MemManageException
  .word BusFaultException
  .word UsageFaultException
  .word 0
  .word 0
  .word 0
  .word 0
  .word vPortSVCHandler
  .word DebugMonitor
  .word 0
  .word xPortPendSVHandler
  .word xPortSysTickHandler
  .word WWDG_IRQHandler
  .word PVD_IRQHandler
  .word TAMPER_IRQHandler
  .word RTC_IRQHandler
  .word FLASH_IRQHandler
  .word RCC_IRQHandler
  .word EXTI0_IRQHandler
  .word EXTI1_IRQHandler
  .word EXTI2_IRQHandler
  .word EXTI3_IRQHandler
  .word EXTI4_IRQHandler
  .word DMAChannel1_IRQHandler
  .word DMAChannel2_IRQHandler
  .word DMAChannel3_IRQHandler
  .word DMAChannel4_IRQHandler
  .word DMAChannel5_IRQHandler
  .word DMAChannel6_IRQHandler
  .word DMAChannel7_IRQHandler
  .word ADC_IRQHandler
  .word USB_HP_CAN_TX_IRQHandler
  .word USB_LP_CAN_RX0_IRQHandler
  .word CAN_RX1_IRQHandler
  .word CAN_SCE_IRQHandler
  .word EXTI9_5_IRQHandler
  .word TIM1_BRK_IRQHandler
  .word TIM1_UP_IRQHandler
  .word TIM1_TRG_COM_IRQHandler
  .word TIM1_CC_IRQHandler
  .word TIM2_IRQHandler
  .word TIM3_IRQHandler
  .word TIM4_IRQHandler
  .word I2C1_EV_IRQHandler
  .word I2C1_ER_IRQHandler
  .word I2C2_EV_IRQHandler
  .word I2C2_ER_IRQHandler
  .word SPI1_IRQHandler
  .word SPI2_IRQHandler
  .word USART1_IRQHandler
  .word USART2_IRQHandler
  .word USART3_IRQHandler
  .word EXTI15_10_IRQHandler
  .word RTCAlarm_IRQHandler
  .word USBWakeUp_IRQHandler
  .word TIM8_BRK_IRQHandler
  .word TIM8_UP_IRQHandler
  .word TIM8_TRG_COM_IRQHandler
  .word TIM8_CC_IRQHandler
  .word ADC3_IRQHandler
  .word FSMC_IRQHandler
  .word SDIO_IRQHandler
  .word TIM5_IRQHandler
  .word SPI3_IRQHandler
  .word UART4_IRQHandler
  .word UART5_IRQHandler
  .word TIM6_IRQHandler
  .word TIM7_IRQHandler
  .word DMA2_Channel1_IRQHandler
  .word DMA2_Channel2_IRQHandler
  .word DMA2_Channel3_IRQHandler
  .word DMA2_Channel4_5_IRQHandler
  .word vMAC_ISR
  .word vMAC_ISR

The vector table seems to fit the FAQ and I succed to launch my task; only 5 seconds but I thought that mean the vector table was correct.

skikepok wrote on Monday, November 19, 2012:

Hi again,

I continued tracking the hard fault and I found the last assembly line executed before the hardfault.

Here the file i used to debug.

I used a lot of “wait_XXX” to debug because the debugger take a lot of time executing a loop.

So, the backtrack could look like:

wait_1000() // i = 8
wait_10000() // i = 0
wait_100000() // i = 0
wait() // The second in toggle

So, in wait_1000(), after 8 wait_100() successful execution, the hardfault happens

  0x08012870 <+0>:	push	{r7, lr}
   0x08012872 <+2>:	sub	sp, #8
   0x08012874 <+4>:	add	r7, sp, #0
   0x08012876 <+6>:	mov.w	r3, #0
   0x0801287a <+10>:	str	r3, [r7, #4]
   0x0801287c <+12>:	b.n	0x801288a <wait_1000+26>
=> 0x0801287e <+14>:	bl	0x8012848 <wait_100>
   0x08012882 <+18>:	ldr	r3, [r7, #4]
   0x08012884 <+20>:	add.w	r3, r3, #1
   0x08012888 <+24>:	str	r3, [r7, #4]
   0x0801288a <+26>:	ldr	r3, [r7, #4]
   0x0801288c <+28>:	cmp	r3, #9
   0x0801288e <+30>:	ble.n	0x801287e <wait_1000+14>
   0x08012890 <+32>:	add.w	r7, r7, #8
   0x08012894 <+36>:	mov	sp, r7
   0x08012896 <+38>:	pop	{r7, pc}

The jump on wait_100 fail and I fall in the HardFault_Handler loop without.

Do you have any idea of what could happens ?

rtel wrote on Monday, November 19, 2012:

There is nothing obviously wrong in the C code.


skikepok wrote on Monday, November 19, 2012:

I know the error do not come from the C code, I am looking for a reason freeRTOS raise an exception that could fail and fall in hard fault handler.

What exception could be raised in the middle of the code ?
Timer exception ?
Scheduler exception ?

Is it possible of an overflow ?

You know freeRTOS better that I do, what could happens at this stage of the code (from FreeRTOS kernel, not from my own code) ?

rtel wrote on Monday, November 19, 2012:

So it looks like you are creating just one task.  Your application will also create the idle task, so provided configUSE_TIMERS is set to 0, there will be two tasks running in your system.

Start by:

+ Having your application task the highest priority task, which in this case just means settings its priority above tskIDLE_PRIORITY.

+ Having a large task stack, say ( configMINIMAL_STACK_SIZE * 4 )

+ Using the co-operative scheduler.  Set configUSE_PREEMPTION to 0.  That means only your application task will ever run because it never blocks or yields.

+ Removing all code other than a NULL loop, so your task is just doing for( ;; ) __asm volatile ( “NOP” );  The NOP is useful for break points.

Does the code run then?  If not, how many times does the tick interrupt occur before it crashes (you can tell by inspecting the xTickCount variable in tasks.c)?


rtel wrote on Monday, November 19, 2012:

Additionally, ensure configUSE_TICK_HOOK is 0, and ideally configCHECK_FOR_STACK_OVERFLOW is 2 (which will require an overflow hook function to be defined, example below):

void vApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )
	( void ) pcTaskName;
	( void ) pxTask;
	/* Run time stack overflow checking is performed if
	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
	function is called if a stack overflow is detected. */
	for( ;; );


skikepok wrote on Tuesday, November 20, 2012:

Thank you a lot Richard for your help.

The problem was in the vApplicationTickHook function I had.

I found this when I disabled configUSE_TICK_HOOK as you advised me to.

In the version given by Rowley exemple, a message was pushed in the LCD queue.
Since I was not using the LCD anymore, the stack should fail somewhere.

Thanks again