Files
DCU_APP/GD32E508_DCU_APP/sys/hardfault.cpp
T
cbb 6aa21a1f9d feat(canfd): 添加CANFD自检功能和桥接模式支持
- 添加完整的CANFD初始化流程,包括硬复位机制解决CAN1卡死问题
- 实现CANFD自检功能,包含物理总线测试和内部回环测试
- 支持CAN0到CAN1/CAN2的透传桥接模式
- 添加详细的初始化诊断信息输出
- 修复CAN滤波器配置和GPIO映射问题
- 增强错误处理和状态监控功能

perf(system): 优化系统时钟配置提高性能

- 将AHB时钟从SYSCLK/4调整为SYSCLK/2 (60MHz)
- 优化PLL预分频配置参数
- 更新相关时序注释以反映实际频率变化

docs(esc): 更新EXMC总线时序配置注释

- 添加LAN9252 HBI时序要求详细说明
- 注明当前ESC未启用状态下的占位符说明
- 提供实际计算得出的HCLK延迟要求
2026-07-02 02:02:41 +08:00

151 lines
4.8 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) {
(void)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");
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"
);
}