vTaskDelay(250) causes a “Hard Fault&...

mikexxxx wrote on Monday, July 01, 2013:

I’m using the latest FreeRTOS version 7.4.2 and after a short while when vTaskDelay(250) is called I get a “Hard Fault” error.

Following the vTaskDelay function (where INCLUDE_vTaskDelay has been set to ‘1’), I see that portYIELD_WITHIN_API() calls vPortYield where portNVIC_INT_CTRL_REG  (Interrupt Control State Register at 0xe000ed04) PENDSVSET bit is set causing a PendSV interrupt.

The vPortSVCHandler calls the vTaskSwitchContex function .

So far all is well and this function returns to the vPortSVCHandler.

However at the end of vPortSVCHandler, the “lr” register is set to 0xfffffffd such that the last instruction “bx lr”, not surprisingly, causes a Hard Fault interrupt.  GDB gives me:

3 HardFaultHandler() main.c 0x8000210
2 <symbol is not available > 0xfffffffc
1 <symbol is not available > 0xfffffffc

This address is consistent with the “bx lr” instruction for Thumb code (LSB set to ‘1’)

Can anyone give me a clue to what’s going on?

rtel wrote on Monday, July 01, 2013:

The vPortSVCHandler calls the vTaskSwitchContex function .

Which port are you using?  I don’t think any of the official ports do that.  Do you mean PendSV handler, rather than the SVC handler?

However at the end of vPortSVCHandler, the “lr” register is set to 0xfffffffd such that the last instruction “bx lr”, not surprisingly, causes a Hard Fault interrupt.

That looks like a valid exec return code, so if the MCU is genuinely using that instruction to return from an interrupt then the return address should be popped off the stack, and the MCU should to be returning to 0xfffffffd.  If that is happening it looks like the MCU is in the wrong mode when it executes the instruction.

Regards.

mikexxxx wrote on Monday, July 01, 2013:

I am using a STM32F205.  I’m using the port.c and portmacro.h from portable\GCC\ARM_CM3

I have just two tasks, one to send a few characters to a UART, and another which currently sends some characters out to a SPI port and then waits.  As soon as the next vTaskDelay function comes along this error occurs.  In all other respects everything seems to be working!

Many thanks for your insight.  I am relatively knew to the processor.

Regards

Mike Perkins

davedoors wrote on Monday, July 01, 2013:

Have you set the interrupt priorities correctly?

http://www.freertos.org/RTOS-Cortex-M3-M4.html (note red text for STM32 users)
http://www.freertos.org/FAQHelp.html

If so, please post your UART and SPI interrupt configuration code and your interrupt handling code.

travfrog wrote on Monday, July 01, 2013:

Mike,

I’ve seen exactly this problem several times on the 205 and it was generally caused by the main ‘C’ stack being too small or corrupted.

davedoors wrote on Monday, July 01, 2013:

To elaborate, the main C stack gets reused as the interrupt stack, so is the stack used in PendSV and SVC handlers.

mikexxxx wrote on Monday, July 01, 2013:

First of thanks Dave for asking about interrupt priorities.  These were set to 6 and 7 after
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
was run.  Obviously subpriority is set to 0.

Travfrof, your supposition was correct.  I had increased the stack for the “main_task” from 128 to 256 and still had the same error.  Now after changing it to 1024 it now runs and I can fine tweak it according to my needs.

Dave, I thought the task in use at the time have to provide sufficient stack for the PendSV and SVC handlers, whether a task_delay or any other form of blocking?  I’m guessing there might be some confusion with main and  main_task?  Doesn’t Main should effectively end once
  vTaskStartScheduler();
is run?  Also won’t it will have the stack pointer associated with the linker file, and not be allocated a “size”?

Thanks again.

Mike Perkins

rtel wrote on Monday, July 01, 2013:

The stack in use when you call main() is recycled for use by all interrupt handlers.

The stack used by tasks is allocated when the task is created.

So when an interrupt occurs the stack pointer is switched from the stack used by the interrupted task, so the stack that was originally used by main().  If that was not done then each task would have to allocate enough  space on its stack for the maximum possible interrupt nesting depth, rather than having this space allocated just one. 

Note the run time stack overflow checking only checks the task stacks because the scheduler knows how big each task stack is.  It does not check the interrupt stack because it does not know (in a portable way) how big that is.

Regards.

travfrog wrote on Monday, July 01, 2013:

Richard, just to be clear, if I start main and immediately create a few auto variables - they will be put in the main ‘C’ stack.

Once the scheduler runs, those auto-variables still occupy the stack right so when the OS starts using it, the stack is actually that much shorter?

Mike, be aware that any initialization you are doing before starting the scheduler uses the main stack so it has to be large enough to handle deep calls to initialization routines - especially if those routines create temporary arrays.

rtel wrote on Monday, July 01, 2013:

No, when the scheduler starts the stack pointer is set back to the start of the stack, so interrupts have the whole stack available.   There is no way back to main() once the scheduler has started so there is no point in preserving any variables that were put on main’s stack before the scheduler was started.

Regards.

mikexxxx wrote on Monday, July 01, 2013:

Richard, I can see what you mean.

However, in my case I don’t believe it was “main” that had a stack limitation that caused the crash.  More likely my principle task, which I confusingly have called my “main_task” since when I increased the stack it then worked.

I am starting to presume that the stack size must also include variables declared in the task.

rtel wrote on Tuesday, July 02, 2013:

FreeRTOS does provide run time stack overflow protection, for task stacks at least, but it has to be turned on.

I am starting to presume that the stack size must also include variables declared in the task.

If you mean that when you declare an auto/stack variable inside a task, or in a function called by a task, then yes.  The compiler does that though, not the RTOS.  Tasks are just C function and completely unknown to the compiler.

Regards.