How to Locate HardFault in FreeRTOS?

How to Locate HardFault in FreeRTOS?

Source: WeChat Official Account 【Osprey Talks Microcontrollers】

Author: Osprey

ID: emOsprey

Hello everyone, I am Osprey. Due to some circumstances, this update is a bit late. However, I still strive for everyone to learn some practical technology from the Osprey official account each time, enhancing their core competitiveness.

Thank you all for your continued support of OspreyHow to Locate HardFault in FreeRTOS?How to Locate HardFault in FreeRTOS?.

Today, let’s continue discussing the common issue of HardFault during development. This problem has been with us since we started learning STM32 development, and many people encounter this issue without knowing how to locate it.

If you are developing independently and encounter such a problem, you generally look at the code, modify the code, and other conventional methods, because you are most familiar with the code you wrote, and the changes are usually not too significant, making it easier to narrow down the scope and locate the issue.

However, products are becoming increasingly complex, and the current development model is collaborative, with each person responsible for their own module. Such projects have a large codebase and high complexity, making it even more difficult to locate problems.

Sometimes, when you just join a company and are unfamiliar with any code, encountering a HardFault can be particularly frustrating, making you feel like running away (as long as one of you can run away from the codeHow to Locate HardFault in FreeRTOS?).

At this point, having an expert who can solve such difficult problems can save a lot of time. I have also solved many similar issues in the company, so I have considerable experience and play this kind of role.

My method for locating HardFault generally relies on KEIL online debugging + C language + authoritative guides.

Currently, my bug-fixing process is roughly as follows:

1. For reproducible issues, if I am familiar with the code, I can resolve it within a few hours.

2. For sporadic issues, I determine the time to solve the problem based on the occurrence situation. Generally, after encountering it four or five times, I can basically locate it.

3. For hard-to-reproduce issues, I usually need to attach a logger to record the runtime situation in real-time.

After going through so much, there are very few HardFault issues that require me to spend several days to resolve (I still remember when I first came to Shenzhen, a HardFault caused by a bug written by someone else forced me to work several nights in a row; if it weren’t for a chance opportunity, I might not have been able to resolve it).

Here’s a small advertisement: if you have a difficult issue, you can hire me to solve your HardFault problem.

However, recently at work, due to using C++, I am not very familiar with the basics, and the speed of resolving HardFault has decreased. Additionally, the project compilation optimization level -O2 has increased the debugging difficulty, so mastering the following methods is very important:

Summary of several compilation optimization settings in MDK

Regarding HardFault, I have previously shared many notes; I wonder how many people have seriously read them.

HardFault INVSTAE error localization (Part 1)

What the heck, did the board just HardFault after returning from the New Year?

Today, I will continue to share methods for locating HardFault in FreeRTOS.

Here, we need a component written by an expert: CmBacktrace (in fact, if online debugging is possible, I wouldn’t need to rely on this component, but it is still quite useful in hard-to-reproduce situations).

Gitee repository: https://gitee.com/Armink/CmBacktrace

This component is probably known and used by many friends, but I want to say that some friends may be using an older version of the component that lacks the following tracking functionality, so I recommend everyone to update.

How to Locate HardFault in FreeRTOS?

As you can see, when an error occurs, the function call stack (sometimes it may be incorrect and needs actual analysis, only for reference).

_call_main ->  main -> fult_test_by_div0

Quite practical.

Moreover, this note is not only applicable for locating HardFault in FreeRTOS; in fact, it can also be modified for use in other RTOS like uCOS, rt-thread, etc. (bare metal is even easier).

The repository example supports platforms: bare metal, rt-thread, ucOS-ii, freertos.

The focus here is on how to port this component to freertos (in fact, the repository’s documentation is also very detailed and can be referenced). Since freertos is also continuously updated, the examples in this component may not fully apply to new versions, and I have just completed the porting, so I will record it here for everyone’s convenience.

1. Copy the entire folder of cm_backtrace (source files) from the repository to your project folder.

How to Locate HardFault in FreeRTOS?

2. Add these files to your project (we can open demos -> os -> freertos project to view).

How to Locate HardFault in FreeRTOS?

There are only two files, quite simple.

One is the core source code, and the other is the assembly code, which is the entry point for code execution.

Note that depending on the IDE, the selected assembly file may differ:

How to Locate HardFault in FreeRTOS?

In fact, it just relocates the default HardFault handler function from startup_stm32f10x_hd.s to cmb_fault.S.

How to Locate HardFault in FreeRTOS?

Note that there is a weak here, so during linking, it will not link this but rather cmb_fault.S :

How to Locate HardFault in FreeRTOS?

To facilitate problem localization, we will also need to modify this code later.

If the HardFault code in your startup file has been modified and you do not understand assembly, it is recommended to restore it to the above form; otherwise, it may not run correctly.

3. Initialization code in the main function.

How to Locate HardFault in FreeRTOS?

The string here needs to be the same (modify according to your project name):

How to Locate HardFault in FreeRTOS?

Therefore, it is recommended to create the project in English. This will be useful when outputting error messages; otherwise, you will need to modify it each time you check the call stack, which is quite troublesome.

If the internal watchdog is enabled, it is recommended to disable it:

// HAL 库__HAL_DBGMCU_FREEZE_IWDG1();// 标准库DBGMCU_Config(DBGMCU_IWDG_STOP, ENABLE);

At the location of the assertion failure, add the function cm_backtrace_assert:

How to Locate HardFault in FreeRTOS?

This way, even if the assertion fails, you can still see the call stack.

4. Modify FreeRTOS kernel files (kernel version V10.2.1)

To analyze the erroneous code, it is necessary to know the stack information of each task, and FreeRTOS may not have this information, so we need to add it.

task.c

How to Locate HardFault in FreeRTOS?

FreeRTOS.h

How to Locate HardFault in FreeRTOS?

Note that in older versions of FreeRTOS, only one modification was needed, but in the new version, two modifications are required; otherwise, it will assert failure and cannot run.

It is recommended to add comments as well.

UBaseType_t     uxSizeOfStack;      /*< Support For CmBacktrace >*/

Related function modification task.c prvInitialiseNewTask():

How to Locate HardFault in FreeRTOS?

At the end of task.c, add the following code to obtain the stack address, size, and name:

How to Locate HardFault in FreeRTOS?

For convenience, I will paste the code here:

/*-----------------------------------------------------------*//*< Support For CmBacktrace >*/uint32_t * vTaskStackAddr(){    return pxCurrentTCB->pxStack;}uint32_t vTaskStackSize(){    #if ( portSTACK_GROWTH > 0 )        return (pxNewTCB->pxEndOfStack - pxNewTCB->pxStack + 1);        #else /* ( portSTACK_GROWTH > 0 )*/        return pxCurrentTCB->uxSizeOfStack;        #endif /* ( portSTACK_GROWTH > 0 )*/}char * vTaskName(){    return pxCurrentTCB->pcTaskName;}/*-----------------------------------------------------------*/

5. Modify component configuration information according to the RTOS platform and chip core

cmb_cfg.h

How to Locate HardFault in FreeRTOS?

1) You need to define the print output function, generally using printf for printing, or you can use some custom print functions that are similar to printf.

#define cmb_println(...)               printf(__VA_ARGS__);printf("\r\n")

2) Enable RTOS support

#define CMB_USING_OS_PLATFORM

3) Specify the RTOS as FreeRTOS

#define CMB_OS_PLATFORM_TYPE           CMB_OS_PLATFORM_FREERTOS

4) Select the chip core based on actual choice; currently supports M0, M3, M4, M7.

#define CMB_CPU_PLATFORM_TYPE          CMB_CPU_ARM_CORTEX_M3

5) Print virtual stack; you can print the original stack information when an error occurs, which may help with analysis.

#define CMB_USING_DUMP_STACK_INFO

6) Language support: English. It actually also supports Chinese, but it is recommended to use English (if not configured, it defaults to English).

#define CMB_PRINT_LANGUAGE             CMB_PRINT_LANGUAGE_ENGLISH

7) If compiled with C++, there may be errors; you can define this at the beginning:

#define __CLANG_ARM

7. Modify the component as needed for easier use (let’s see if we can have a chance to merge these into the expert’s branch).

1) Since the functionality involves a small scope, the related header file inclusion form can be changed to this, so you don’t need to modify the header file path, making porting easier:

#include <cm_backtrace.h>-->>#include "./cm_backtrace.h"#include <cmb_cfg.h>-->>#include "./cmb_cfg.h"#include "cmb_def.h"-->>#include "./cmb_def.h"

In main, you also do not need to include header files, but rather declare this function directly where needed, as external code only needs to call this function:

#include <cm_backtrace.h-->void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver);

This way, you do not need to add the header file path.

Alternatively, you can use relative paths to add header files:

#include "../../driver/cm_backtrace/cm_backtrace.h"

Additionally, we can make the program automatically stop before entering HardFault, allowing us to better utilize online debugging code, “What is the legendary software breakpoint?”.

HardFault_Handler    PROC    LDR     r0, =0xE000EDF0; DEMCR    LDR     r0,[r0,#0x00]    AND     r0,r0,#0x00000001    CBZ     r0,not_in_debug    BKPT    0not_in_debug    MOV     r0, lr                  ; get lr    MOV     r1, sp                  ; get stack pointer (current is MSP)    BL      cm_backtrace_fault

Because the information is most complete when just entering HardFault, and I don’t want to set a breakpoint every time, the above code effectively implements the function without affecting the normal operation of the program (it will automatically determine whether it is in debug mode).

8. Experiment.

Once everything above is done, you can verify the effect. Here we can simulate and see the situation (modify project configuration; I have shared this content before, so I won’t elaborate).

How to Locate HardFault in FreeRTOS?

After running the repository example, it should print the following information, indicating that a div 0 error occurred.

How to Locate HardFault in FreeRTOS?

Your ported project should also print similar information (add test code: fault_test_by_div0();). If it does not print, there are two possibilities:

1. The print function was not initialized properly before entering HardFault.

2. There is an issue with the print function.

How to Locate HardFault in FreeRTOS?

After that, we copy the last line and run the add2line tool in the repository to check the call stack information:

How to Locate HardFault in FreeRTOS?

In git bash, it may fail to execute; you can add the program path, or you can add the tool path to the Windows environment variable. If it prompts that the axf file cannot be found, just copy this file to the tool’s directory.

The correct approach is to place the tool in the C drive directory and add the environment variable, then you can open git bash or cmd in the axf directory to execute the command.

This is just for demonstration, so I won’t elaborate further.

Finally, let me briefly introduce the implementation principle of this component:

If a HardFault occurs, it first enters the HardFault_Handler in the assembly file, where it obtains the current stack pointer and LR, and determines which stack the error occurred on based on LR (here is the PSP stack).

Based on the error register information, it determines what kind of error occurred (here it is a division by zero error).

Then, it analyzes the stack information, LR, and PC in FLASH assembly code to find possible jump instructions. The two jump addresses found are 0x08001f96 and 0x08000368, thus obtaining the call stack.

Therefore, to accurately obtain the call stack, there are two important prerequisites (it is recommended to set the optimization level to -O0):

1. The stack has not been corrupted.

2. The chip’s running code and the axf file are consistent.

Even so, you cannot guarantee that the obtained call stack is correct. For example, if you use fault_test_by_unalign() for testing, the result is as follows:

How to Locate HardFault in FreeRTOS?

There is an extra fputc in the middle.

Therefore, this printed information can only be used as a reference.

However, online debugging is different; it is more professional and less likely to produce erroneous calling relationships.

How to Locate HardFault in FreeRTOS?

What I wanted to share ends here. See you next time!

Note

Due to recent changes in the WeChat official account’s push rules, to prevent missing articles, you can star and pin it, so that the articles pushed each time will appear in your subscription list.

You might also like:

Sharing an example of AP configuration for embedded devices

Embedded Linux single board connection to Feiyan IoT platform

Sharing a highly flexible protocol format (with code examples)

Embedded Miscellaneous Weekly | Issue 16

Embedded Miscellaneous Weekly | Issue 15

Why accessing illegal memory does not cause errors?

Embedded Miscellaneous Weekly | Issue 14

Sharing several practical code snippets (second edition)

Sharing a bug localization method you may not know

Sharing a method for modifying configuration files

Embedded Miscellaneous Weekly Issue 13: lz4

Understanding Embedded Parallel Multithreaded Processors!

Sharing a method for modifying configuration files

Sharing several practical code snippets (with code examples)

Reusing old boards: Setting up a wireless debugging environment!

Summary of three debugging methods for embedded segmentation faults!

Brief discussion on non-blocking reception in TCP communication (with code examples)

Encapsulation of commonly used interfaces in TCP communication

Common pitfalls of bus errors in embedded software? Let me take a step for everyone.

Sharing debugging methods for embedded software and several useful tools!

Sharing two suggestions to improve programming skills!

Reply with 1024 in the WeChat chat interface to obtain embedded resources; reply with m to view the article summary.

Leave a Comment