I’ve written a hard fault handler for a cortex M7 with the help of my friend Deepseek and would like to record the name of the freeRTOS task that was running at the time the hard fault occurred.
I would do this at the end of the task handler so cpu/fpu registers are recorded before executing this code which will probably change the cpu register values.
This code is performed in the hard fault handler interrupt routine and as the proposed commands aren’t ISR friendly I thought I had better ask.
I can give it a try, but I was wondering if there were any gotchas that I need to be aware of.
If the method I propose is a dud is there another way?
I know doing a stack analysis will often point to the naughty task, however this is magnum tedious and error prone in my case.
This is certainly not what the API was designed for as you rightly pointed out too. Looking at the function definition, I see that it has some critical section which would enable and disable interrupts and may cause some problems. I cannot confirm because we have not tried this.
You cannot trust the state of the system once a hard fault happens. For example, what if the reason of the hard fault was a corrupted pxCurrentTCB. In this case you will get some garbage task name or even worse try to read some non-readable memory. The best approach usually is to dump all the state (which may include pxCurrentTCB) and then do the analysis.
You can not use non-FromISR functions inside your fault handler. I will tend to just grab the current task handle from the global variable. Yes, that isn’t advised for normal task code, but this isn’t normal task code. You can even get the details of the TCB either by copying the structure definitions, or by putting your fault handling code inside the file freertos_task_c_additions.h and defining the define to enable that.
Another point is that, at least currently, pcTaskGetName(0) will get a pointer to the name of the current task, and while it doesn’t have FromISR, is currently safe to use to determine the task that was interrupted.
Note, the fault handler might have been triggered by an ISR, so you do need some stack tracing to find the guilty party. I find that for fault handlers, showing the registers, and especially the PC of the fault, is the first step to the answer, and then I look at the task that was running if I am in library code.
And it worked fine. I had a look at the code for the vTaskGetTaskInfo and in my version of freeRTOS Kernel V10.3.1 and there were some taskCritical functions in functions called by vTaskGetTaskInfo , (eg. eTaskGetState), however this did not appear to be a problem. The vTaskGetTaskInfo gave the correct answer for hard faults caused within the task itself or by a called function. I tried a few different typed of fault. Of course it won’t work if the task control blocks are corrupted, but it does seem to be of some utility.
I will do some more testing to see what breaks it.
The out put looked like:
==== [MemManage_Handler] ====
Hard Fault at Time: - UTC 2025-04-10 05:32:12
- Stack frame:
R0 = 0x00000000
R1 = 0xa5a5a5a5
R2 = 0xdeadbeef
R3 = 0x00000000
R12 = 0xa5a5a5a5
LR = 0x00000d2d
PC = 0x90043476
PSR = 0x41000000
- FSR/FAR:
CFSR = 0x00000082
HFSR = 0x00000000
DFSR = 0x00000009
AFSR = 0x00000000
Mem Mgt Fault Addr = 0x00000000
Mem Mgt Fault - DACCVIOL Data access violation\s
======= [End] =======
Task Name: ghControlTask
Task State: 0
Task Priority: 55
Task Stack High Water Mark: 238
Task Handle Addr: 200098d8
I call xTaskGetCurrentTaskHandle to get the task handle, check that it isn’t null, then call pcTaskGetName using that handle. It works for me. Yes I know I shouldn’t really call a function without _FROM_ISR in the name from an ISR but from examining the code I can see that it is safe at least for single-core systems.