*This content has been reposted with the approval of the original author.
Introduction:
When developing with the APM32F407 microcontroller, encountering Hardfault issues is a common challenge. Hardfault is a fatal fault that causes the program to halt. This blog post aims to analyze common Hardfault problems in APM32F407 and provide solutions to help developers quickly identify and resolve these issues.
Causes of Hardfault:
Before delving into Hardfault analysis, let’s understand some common causes:
Uninitialized or wild pointers: Using uninitialized pointers or pointing to invalid memory addresses in your code can lead to a Hard Fault. Make sure to properly initialize pointers before using them and ensure that they do not go out of bounds or point to invalid memory.
Stack overflow: Stack overflow occurs when the program uses more stack space than the allocated stack size. When this happens, critical data gets overwritten, resulting in a Hard Fault. Check for recursive function calls, large local variables, or excessive function call nesting in your code, to ensure sufficient stack space.
Errors in interrupt handlers: Hard Faults can occur if there are hardware errors or incorrect configurations in interrupt handlers (e.g., TMR, USART, etc.). Make sure to properly configure and implement interrupt handlers and handle any possible hardware errors.
Improperly configured peripherals: Incorrect initialization or configuration of peripherals, like not enabling clocks, setting incorrect pins or parameters, can cause Hard Faults. Make sure to properly initialize and configure any peripherals before using them.
Accessing illegal peripherals or memory regions: Accessing illegal peripherals or memory regions can lead to Hard Faults. Ensure that any access to peripherals or memory is within their valid address ranges and prevent any access conflicts.
Mathematical operation errors: Using unsupported mathematical operations or generating NaN (Not a Number) values can cause Hard Faults. Ensure that you use the correct data types and mathematical rules when performing mathematical operations and avoid dividing by zero or using invalid values.
FLASH or RAM errors: Errors in reading from or writing to FLASH or RAM can result in Hard Faults. Make sure to properly read from and write to FLASH or RAM and implement appropriate error handling.
Resolving Hardfault Issues:
Here are some common solutions to resolve Hardfault issues:
Debugging tools: Using debugging tools like JTAG/SWD debuggers during runtime can help catch Hardfault exceptions and inspect relevant register values to pinpoint the issue.
Exception handler function: Adding a Hardfault exception handler function in the program allows specific actions, such as logging or restarting, to be performed when a Hardfault occurs.
Stack size optimization: Addressing stack overflow issues may require adjusting the stack size.
Check pointers: Before using pointers, ensure they are properly initialized and that the memory they point to has not been released.
Memory checks: Employing memory inspection tools like the Memory Management Unit (MMU) helps detect illegal memory access.
Recommended Tools:
Keil MDK: A comprehensive embedded development toolset that provides an integrated development environment, including compilers, debuggers, and simulators.
SEGGER J-Link: A powerful JTAG/SWD debugger that supports various MCUs and offers extensive debugging capabilities.
Debug a HardFault:
If you can find out in Keil’s Peripherals > Core Peripherals > Fault Reports that a relevant register bit is set, you can backtrack to the error code based on the address. If you cannot see it here, you can check it by following the steps below about how to find the HardFault reason in Keil debug mode:
In Keil uVision, start a debug session by clicking Debug > Start/Stop Debug Session.
Once the debug session is started, the debugger will stop at the HardFault exception.
In the Registers window, locate the SP register. The value of the SP register will be the address of the top of the stack.
In the Memory window, click the Select button and enter the SP value. This will select the stack memory.
The 7th value of the stack is the address of the last instruction that was executed before the HardFault exception occurred.
In the Disassembly window, click the Goto button and enter the address of the last instruction. This will take you to the instruction that caused the HardFault exception.
Here is an example of how to find the HardFault reason in Keil debug mode:
Suppose the SP value is 0×200003E8. The 7th value of the stack is 0xE000ED08. This means that the last instruction that was executed before the HardFault exception occurred is located at address 0xE000ED08. In the Disassembly window, if you click the Goto button and enter 0xE000ED08, the debugger will take you to the instruction that caused the HardFault exception.
Note: It is dangerous to stay in hardfault or while(1) when your code references the product, you can add code (Trigger a system reset) to reset the chip to get out of this state.
void HardFault_Handler(void)
{
uint32_t cfsr = SCB->CFSR; // Read CFSR register
uint32_t hfsr = SCB->HFSR; // Read HFSR register
printf("@HardFault_Handler!\n\r");
printf("CFSR: 0x%08X\n\r", cfsr);
printf("HFSR: 0x%08X\n\r", hfsr);
// Print R0 to R7 registers
printf("R0 = 0x%08X\n\r", (unsigned int) __get_MSP());
printf("R1 = 0x%08X\n\r", (unsigned int) __get_PSP());
printf("R2 = 0x%08X\n\r", (unsigned int) __get_PRIMASK());
printf("R3 = 0x%08X\n\r", (unsigned int) __get_FAULTMASK());
printf("R4 = 0x%08X\n\r", (unsigned int) __get_BASEPRI());
printf("R5 = 0x%08X\n\r", (unsigned int) __get_CONTROL());
printf("R6 = 0x%08X\n\r", (unsigned int) __get_APSR() & 0xFFFFFFFCU);
printf("R7 = 0x%08X\n\r", (unsigned int) __get_xPSR());
printf("\n\r");
// Trigger a system reset
SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk;
while(1); // Program stops here
}
Conclusion: Hardfault issues pose common challenges during APM32F407 development, but with appropriate debugging tools and solutions, we can effectively identify and resolve these issues. It is advisable for developers to maintain good coding practices, promptly address Hardfault exceptions, and strive to improve development efficiency and code quality.
Example Code
int main(void)
{
char ch;
/* USART Initialization for printf */
USART_Init();
while(1)
{
printf("\n\r");
printf("+----------------------------------------------------+\n\r");
printf("| HardFault_Analysis Code |\n\r");
printf("+----------------------------------------------------+\n\r");
printf("Please enter a character to continue!\n\r");
scanf("%c", &ch);
printf("Input char is:%c !\n\r", ch);
printf("\n\r");
// Simulate a hardware fault
__disable_irq();
((void(*)(void))0xE000ED08)(); // Access an invalid memory address
__enable_irq();
}
}