Files
DCU_APP/GD32E508_DCU_APP/sys/hardfault.cpp
T
cbb 76da7a3dd6 Refactor and clean up codebase
- Removed unused constants and type aliases in app_spi_command_defs.h and temp_sensor.h.
- Simplified ISpiCommandHandler destructor to default.
- Eliminated redundant methods and comments in temp_sensor and usart0 files.
- Consolidated writeU32Le function to app_spi_command_defs.h for reuse.
- Updated comments for clarity and accuracy in task_manager.h and task_runner.cpp.
- Removed hardfault.h as it contained no declarations.
- Cleaned up CANFD and watchdog implementations by removing dead code and unnecessary comments.
- Updated version numbers in config.h to reflect recent changes.
- Enhanced error handling and diagnostics in hardfault handling.
2026-07-15 02:49:37 +08:00

152 lines
4.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file hardfault.cpp
* @brief HardFault 诊断处理——通过 USART0 输出故障寄存器信息。
*
* 当 APP 在 BOOT 跳转后立即死机时,标准 printf 不可用,
* 所以使用直接寄存器操作输出。
*/
#include "gd32e50x.h"
#include <stdint.h>
/**
* @brief 通过 USART0 直接发送一个字节(纯寄存器操作,不依赖库函数/宏)。
*/
static void rawPutc(char ch) {
volatile uint32_t *stat0 = (volatile uint32_t *)0x40013800U;
volatile uint32_t *data = (volatile uint32_t *)0x40013804U;
while ((*stat0 & (1U << 7)) == 0U) {} /* 等待 TBE */
*data = (uint32_t)ch;
}
/**
* @brief 通过 USART0 直接发送字符串。
*/
static void rawPuts(const char *s) {
while (*s) { rawPutc(*s++); }
}
/**
* @brief 输出 32 位十六进制值。
*/
static void rawHex32(uint32_t val) {
const char hex[] = "0123456789ABCDEF";
rawPuts("0x");
for (int i = 28; i >= 0; i -= 4) {
rawPutc(hex[(val >> i) & 0xF]);
}
}
/**
* @brief 检测当前实际 APB2 时钟频率(Hz)。
*
* 通过读取 RCU_CFG0 的 SCSS / AHBPSC / APB2PSC 字段,
* 实时计算 USART0 所在的 APB2 总线时钟频率,
* 而不依赖可能已过时的 SystemCoreClock 全局变量。
*
* @param stack_frame 指向异常栈帧的指针(由汇编桩压入)。
* 包含: R0, R1, R2, R3, R12, LR, PC, xPSR
* @param lr_value EXC_RETURN 值,用于判断使用 MSP 还是 PSP。
*/
static uint32_t detectApb2Clock(void) {
volatile uint32_t *rcu_cfg0 = (volatile uint32_t *)0x40021000U;
uint32_t cfg0 = *rcu_cfg0;
/* 1. 确定 SYSCLK 频率 */
uint32_t scss = (cfg0 >> 2) & 0x3U;
uint32_t sysclk;
if (scss == 0x2U) {
sysclk = 180000000U; /* PLL = 180MHz(当前 PLL 目标频率) */
} else {
sysclk = 8000000U; /* IRC8M = 8MHz 或 HXTAL(未倍频时视为 8MHz) */
}
/* 2. AHB 预分频 */
uint32_t ahbpsc = (cfg0 >> 4) & 0xFU;
uint32_t ahb_div;
switch (ahbpsc) {
case 0x8: ahb_div = 2; break;
case 0x9: ahb_div = 4; break;
case 0xA: ahb_div = 8; break;
case 0xB: ahb_div = 16; break;
case 0xC: ahb_div = 64; break;
case 0xD: ahb_div = 128; break;
case 0xE: ahb_div = 256; break;
case 0xF: ahb_div = 512; break;
default: ahb_div = 1; break;
}
uint32_t ahb_clk = sysclk / ahb_div;
/* 3. APB2 预分频 */
uint32_t apb2psc = (cfg0 >> 11) & 0x7U;
uint32_t apb2_div;
switch (apb2psc) {
case 0x4: apb2_div = 2; break;
case 0x5: apb2_div = 4; break;
case 0x6: apb2_div = 8; break;
case 0x7: apb2_div = 16; break;
default: apb2_div = 1; break;
}
return ahb_clk / apb2_div;
}
extern "C" void HardFault_Handler_C(uint32_t *stack_frame, uint32_t lr_value) {
/* 确保 USART0 时钟可用 */
volatile uint32_t *rcu_apb2en = (volatile uint32_t *)0x40021018U;
*rcu_apb2en |= (1U << 2) | (1U << 14); /* RCU_GPIOA | RCU_USART0 */
/* 确保 PA9 处于 AF_PP 50MHz 模式(可能被其他代码覆盖) */
volatile uint32_t *gpioa_ctl1 = (volatile uint32_t *)0x40010804U;
uint32_t ctl = *gpioa_ctl1;
ctl &= ~(0xFU << 4);
ctl |= (0xBU << 4); /* PA9: AF_PP 50MHz */
*gpioa_ctl1 = ctl;
/* 根据实际 APB2 时钟计算波特率分频值 */
uint32_t apb2_clk = detectApb2Clock();
uint32_t baud_div = apb2_clk / 115200U;
if (baud_div == 0U) baud_div = 1U;
volatile uint32_t *usart_baud = (volatile uint32_t *)0x40013808U;
volatile uint32_t *usart_ctl0 = (volatile uint32_t *)0x40013800U;
*usart_baud = baud_div;
*usart_ctl0 = (1U << 3) | (1U << 13); /* TE | USARTEN */
rawPuts("\r\n!!! HardFault !!!\r\n");
rawPuts("EXC_RETURN="); rawHex32(lr_value); rawPuts("\r\n");
/* EXC_RETURN 解析:bit3=0(MSP)/1(PSP), bit2=0(handler mode)/1(thread mode) */
if (stack_frame) {
uint32_t pc = stack_frame[6];
uint32_t lr = stack_frame[5];
uint32_t psr = stack_frame[7];
rawPuts("PC="); rawHex32(pc); rawPuts("\r\n");
rawPuts("LR="); rawHex32(lr); rawPuts("\r\n");
rawPuts("PSR="); rawHex32(psr); rawPuts("\r\n");
}
rawPuts("CFSR="); rawHex32(SCB->CFSR); rawPuts("\r\n");
rawPuts("HFSR="); rawHex32(SCB->HFSR); rawPuts("\r\n");
rawPuts("MMFAR="); rawHex32(SCB->MMFAR); rawPuts("\r\n");
rawPuts("BFAR="); rawHex32(SCB->BFAR); rawPuts("\r\n");
/* 死循环 */
while (1) {}
}
/**
* @brief HardFault_Handler 汇编桩——保存栈帧后调用 C 诊断函数。
*/
__attribute__((naked)) void HardFault_Handler(void) {
__asm volatile(
"tst lr, #4 \n" /* 检查 EXC_RETURN 位 2 */
"ite eq \n"
"mrseq r0, msp \n" /* 位 2 = 0: 使用 MSP */
"mrsne r0, psp \n" /* 位 2 = 1: 使用 PSP */
"mov r1, lr \n" /* 保存 EXC_RETURN */
"b HardFault_Handler_C \n"
);
}