Files
STM32F4-Base/Src/stm32f4xx_it.c
T
wandering1 b1494eb10c feat(固件): 标定值语义 setter + 卷锁 fail-open 自检留痕 + 控制台编号写法整理
三批同笔的理由:它们是同一份权威构建(Linker run 04:5x,Code=233,900 / RW=1,536)里的内容,中间态从未
单独编译过,拆开提任何一段都没有对应的构建凭证。按道分述如下。

**① 算法层(ui-maint):写值与置脏成对,不留可单独调用的置脏口**。新增 run_par_cal_k_set() /
run_par_cal_b_set(),被拒时副本不动也不置脏(= 不承诺持久化);104 的 run_par_104_write() k/b 两支
同批改调 setter,函数内自己碰 s_dirty 的两处删净——**消除两份置脏逻辑才是本段的目的**。刻意**没有**新增
公开 run_par_mark_dirty():作者的理由我采纳并原文保留——「一旦存在就一定有人只调它」,与今天删掉的零消费
者接口是同一失效机理。另新增合法域唯一出口 run_par_db_range()、粗守上限 RUN_PAR_K_MAX_UV、毫→工程换算
单点 s_milli_to_eng(),并改正了头文件里「除以 1000 唯一在此」那条在加 db_range 后会变假陈述的说法。
**顺带满足 task-43 第①项**:adc_cal 落盘口的缺口由本段 setter 解决(写值必置脏),task-43 剩余项 = 可诊断
性与文档。

**② 日志层(log-maint):卷锁 fail-open 的 defaultTask 侧边沿留痕**。syslog_drain() 尾部紧跟既有
s_quiet_
drop 差值块之后读 vol_lock_get_stats(),水位新增才算一个 episode、每上电一条,投 SYSLOG_SELFTEST,文本
vollock failopen=%lu。三条硬约束都落了且**有牙**:失败调用点零改动(wdev.log 自己也要这把非递归卷锁);
不打错级、**不打 [ERR]**(断言里 g_sys_err_count == 0 就是机器判据,把「改成 DBG_ERROR」注入后四条用例
全红);锁层只自增、唯一写者消费。作者一度按我的要求准备造 obs_first_ms/obs_last_ms 字段,我撤了那条
要求——记录自带 ts 就是被观测时刻,**再造一个时间戳字段等于造第二个「看起来像发生时刻」的东西**。
成本 .bss +48 B、**零栈增量**(缓冲全静态),已由本笔权威构建的 after 表证实:9 条链全 PASS,
iec104Task 1,464 / margin 1,096、defaultTask 3,040 与提交态逐项一致。

**③ 控制台与中断(log-maint,纯注释/文档)**:b623a406 之后的编号写法整理,把裸形态号改为可校验形式,
零代码行为改动。

实测:@build 0 错误 0 警告;run_par 67/67、sys_log_mcu 141/141、console_log 套件零回归
覆盖率只增不减
(sys_log_mcu.c 410/413 = 99.3%、函数 22/22);cppcheck / coding-standard /
doc-links / bom / mojibake /
nested-comment 全 0;编号五项式错误差值 0、不可判定绝对数 **1,156**(上限 1,166 未动,本笔没吃余量)。
台账随本笔回填:ram_baseline --write 与 mem-numbers --write 同批(RW_IRAM1 80,920 B 61.7%
/
RW_CCM 57,376 B 87.9% / ER_IROM1 260,004 B 24.8%)。
2026-10-27 05:10:11 +08:00

680 lines
23 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.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f4xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
/* 道G task-26:崩溃现场上报改走控制台单写者的**有界**发送口(dbg_console_write_raw)。
* 原来这里直接调 HAL_UART_Transmit,于是崩溃路径成了绕过 console_log 行级独占的
* **第三个写者**,并且带两条本仓已实证的失效:① 超时判据是 HAL_GetTick()(TIM7 停摆
* 时永不成立,第 8a/8b 轮台架实证);② 僵尸通道(ORE 锁存)下 HAL 恒快速失败
* (docs/子系统设计/控制台单写者日志设计说明.md §12)—— 而 [ERR] 崩溃行正是台架
* 「出现即不通过」的判据来源,快速失败 = 关键证据整条蒸发。 */
#include "console_log.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* HardFault 现场报告实现(2026-09-29 迁移至此,**保护区**内):
* 原放在紧随 HardFault_Handler 之后的自造区 `HardFault_Report` 里——
* 实测 CubeMX 重生成不会保留"生成区之外的自造标记区"(它整段按新模板重写),
* 故迁入本文件本来就有的 `USER CODE BEGIN 0`(生成区内的标准保护位),
* 从此重生成不会丢失。
*
* 说明:本函数由 __asm void HardFault_Handler 用 B 直接跳入(见下方),
* 不经内核、不 printf、不遍历指针,只用寄存器级有界轮询(dbg_console_write_raw)+
* SCB 寄存器读取,因此在内核状态已不可信时仍可用。
* 2026-10-26(道G task-26)两处改动:
* ① 发送口由 HAL_UART_Transmit 换成 dbg_console_write_raw(理由见 hard_fault_write);
* ② 去掉输出后的 HAL_Delay(200):dbg_console_write_raw 自身等到 TC(移位寄存器排空)
* 才返回,延时本就冗余;去掉它是为了**少一条 tick 依赖**——HAL_Delay 也走
* TIM7 时基,tick 停摆时会卡死在复位之前(启动段 IWDG 尚未启动,没有兜底)。
* 同文件断言钩子早有同款理由的注释("无需 HAL_Delay:con_tx_bounded 已等到 TC")。
*/
static void hard_fault_write(const char *s, uint16_t len)
{
/* 显式长度 + 有界单次发送:上报路径自身不得再崩(2026-09-24 加固;
* 不做 '\0' 遍历,长度由调用方 sizeof 给出) */
if ((s == NULL) || (len == 0u)) {
return;
}
if (len > 64u) {
len = 64u;
}
/* 道G task-26:改走 dbg_console_write_raw(原来是 HAL_UART_Transmit(&huart1, …,
* 0xFFFF))。三条换它的理由,全部有仓内实证或既有判据背书:
* ① **不依赖 tick**:本口的上界是 DWT CYCCNT(CON_TX_TIMEOUT_CYC = 100ms 对应
* 周期数),DWT 使能不上时退回指令计数上界(CON_TX_GUARD_MAX)——两条都与
* TIM7/uwTick 无关。HAL 那条是 UART_WaitOnFlagUntilTimeout(HAL_GetTick(),
* Timeout=0xFFFF):正常上限约 65 秒,且 tick 一停摆就**永不超时**。
* ② **不受 HAL 状态机与 ORE 影响**:本口只轮询 TXE/DR/TC,不读 gState,僵尸通道
* 下不会"整条不发"(§12);也不再占用 huart1 的 HAL lock——崩溃现场不再可能
* 与被冻结的 defaultTask 所持 BUSY 互绊。USE_FULL_ASSERT 打开时也不再走
* assert_param(IS_UART_INSTANCE(NULL)) 那条二次进断言钩子的潜在递归。
* ③ **未初始化有短路**:huart1.Instance == NULL 时立即返回 HAL_ERROR,绝不解引用
* 地址 0(机器证据 = 主机单测 TC-CONLOG-100;极早期路径仍能走完全行不挂死
* = TC-CONLOG-102)。残余风险照实写在下方 hard_fault_report 函数头。
* 本口自身等到 TC 才返回,所以调用点不需要(也不该)再补 HAL_Delay。 */
dbg_console_write_raw(s, (unsigned)len);
}
/* 字面量输出宏:长度由 sizeof 定,编译期即可确定 */
#define HF_PUTS(lit) hard_fault_write((lit), (uint16_t)(sizeof(lit) - 1u))
static void hard_fault_puthex(uint32_t v)
{
static const char digits[] = "0123456789ABCDEF";
char out[9];
int i;
for (i = 0; i < 8; i++) {
out[i] = digits[(v >> (28 - i * 4)) & 0xFu];
}
out[8] = '\0';
hard_fault_write(out, 8u);
}
/* 崩溃现场报告核心(四个 Fault 共用)。
* 入口参数:tag - 故障名(ASCII 字面量,如 "HARDFAULT" / "MEMFAULT")
* frame - 异常栈帧 {R0,R1,R2,R3,R12,LR,PC,xPSR}
* 说明:CFSR 一次性打出,其子域已含 MMARVALID(bit7)/BFARVALID(bit15),
* 故 MMFAR/BFAR 的"是否有意义"由 CFSR 判定,四个 Fault 都能看全。
*
* ⚠ 本函数**不直接**被异常向量调用——异常入口是下方的 `__asm` 版 Handler,
* 它们只负责取异常帧指针,然后 `B` 到下面 4 个 per-fault 入口之一
* (每个入口自带 tag 字面量后再调本函数)。
* 这样做的原因:ARMCC 的 `__asm` 块**取不到 C 的 static 数据符号**
* (实测:`ADR r1, xxx_tag` 报 `A1516E: Bad symbol`,去掉 static 也无效),
* 而 `__asm` 里也无法给 C 函数传结构体/字符串参数。故把"带 tag"这一步
* 放在普通 C 函数里做。
*
* 关于"14 段裸发要不要包成一次整行独占"(道G task-26 定案,2026-10-26:**不包**):
* 本函数确实是 14 段裸发(tag / PC / LR / xPSR / R0~R3 / CFSR / HFSR / 可选 BFAR /
* 可选 MMFAR),段与段之间也确实可插字节;但 dbg_console_tx_begin()/tx_end() 在这里
* **空转**:异常上下文 IPSR != 0 时 begin 放行且**不持有**凭证("绝不等待"的必然结果),
* end 又只对持有者有效。而包上的代价是 ×9 条任务链的栈记账(本函数经断言/内核钩子
* 挂在 configASSERT 子树上;实测 default/net/iec104 三条链各 +80 B,把 iec104Task 的
* margin 顶到 1,016 < 1,024 ISR 底线)。真正救这条崩溃行的是另外两件事:**发送口归一**
* (hard_fault_write 改走 dbg_console_write_raw,三条理由见其函数头)与**去掉
* HAL_Delay**(少一条 tick 依赖)。整行性的真实依据与残余见
* docs/子系统设计/控制台单写者日志设计说明.md §4.4.1:
* 故障上下文 IPSR != 0,begin() 是**放行**(返回 1 但**不持有**凭证——异常上下文
* 绝不允许等待或失败),所以这里的原子性**不是**靠凭证,而是靠"Fault 优先级 -1、
* 外设中断 ≥5、任务全冻结 ⇒ 没有第二个写者能跑进来"。唯一残留:被抢占任务**已经
* 在移位寄存器里的那 ≤1 个字节**,它会出现在本行**之前**(不影响 [ERR] 前缀可 grep),
* 不是段间插入。已明确否决"发送循环逐字节检查让位标志"那种修法——那会把正在发的
* 启动日志行截断,换不来什么。
*
* 残余风险(照实登记,别当成已消除):
* - **极早期崩溃仍然静默**:若在 MX_USART1_UART_Init() 之前进 Fault,本口的
* `huart1.Instance == NULL` 短路会直接返回、一个字节都不发(换来的是"绝不解引用
* 地址 0",见 hard_fault_write ③;该短路有机器判据 TC-CONLOG-100 与 TC-CONLOG-102)。旧写法在
* 同样场景下也不发(gState==RESET 不等于 READY ⇒ HAL_BUSY),**并没有因为本次改动
* 变差**,但也别写成"早期崩溃现在能看到"。
* - **ORE/NE/FE 脏标志本身没被消除**:本笔只是不再经由 HAL 状态机,从而消除了
* "崩溃日志整条蒸发"这一类;"控制台输出可能被 RX 悬空噪声污染"那一条仍在
* §12 既有观察项名下(RX 配置是另一个风险面,本笔不动)。
*/
void hard_fault_report(const char *tag, uint32_t *frame)
{
/* 刻意不包整行独占:三条理由见上方"要不要包成一次整行独占"那一段。 */
HF_PUTS("\r\n[ERR] ");
hard_fault_write(tag, 16u);
HF_PUTS(" PC=");
hard_fault_puthex(frame[6]);
HF_PUTS(" LR=");
hard_fault_puthex(frame[5]);
HF_PUTS(" xPSR=");
hard_fault_puthex(frame[7]);
HF_PUTS(" R0=");
hard_fault_puthex(frame[0]);
HF_PUTS(" R1=");
hard_fault_puthex(frame[1]);
HF_PUTS(" R2=");
hard_fault_puthex(frame[2]);
HF_PUTS(" R3=");
hard_fault_puthex(frame[3]);
HF_PUTS(" CFSR=");
hard_fault_puthex(SCB->CFSR);
HF_PUTS(" HFSR=");
hard_fault_puthex(SCB->HFSR);
/* BFAR/MMFAR 仅在对应 valid 位为 1 时有意义 */
if ((SCB->CFSR & (1UL << 15)) != 0U) {
HF_PUTS(" BFAR=");
hard_fault_puthex(SCB->BFAR);
}
if ((SCB->CFSR & (1UL << 7)) != 0U) {
HF_PUTS(" MMFAR=");
hard_fault_puthex(SCB->MMFAR);
}
/* 此处无需归还所有权:本函数从未取过(见函数开头说明)。 */
/* HAL_Delay(200) 已删:最后一个 write_raw 内部等到 TC 才返回,串口已排空;
* 留着它反而多一条 TIM7 tick 依赖(tick 停摆 = 卡在复位之前)。 */
NVIC_SystemReset();
}
/* 四个 per-fault 入口:__asm Handler 取到帧指针后 `B` 到这里,由 C 补上故障名。
* 名字用 `fault_entry_*` 前缀,与向量符号(`*_Handler`)区分开。 */
void fault_entry_hard(uint32_t *frame)
{
hard_fault_report("HARDFAULT", frame);
}
void fault_entry_mem(uint32_t *frame)
{
hard_fault_report("MEMFAULT", frame);
}
void fault_entry_bus(uint32_t *frame)
{
hard_fault_report("BUSFAULT", frame);
}
void fault_entry_usage(uint32_t *frame)
{
hard_fault_report("USAGEFAULT", frame);
}
/* ==== 4 个异常入口:__asm 版 Handler(符号与向量表一致)====
* ⚠ **必须写在下面 4 个 `#define X X_Gen` 之前**——写在之后会被自己的宏改名。
* 2026-10-09 从生成区迁入本保护区:此前放在生成区内(L3),每次 CubeMX 重生成
* 都被抹掉、需 `git checkout HEAD -- Src/stm32f4xx_it.c` 复原;现在生成区保持
* CubeMX 原样,重生成零改动。
*
* 原理:EXC_RETURN bit2(`TST lr, #4`)判断异常帧在 MSP 还是 PSP,取帧指针后
* `B` 到上面的 per-fault C 入口。CubeMX 默认的空 `while(1)` 版会让死机在日志上
* **完全静默**(2026-09-20 实证)。
* ⚠ ARMCC 语法:内联汇编**只能**用整函数 `__asm void f(void) {...}` 形态。
* `__asm volatile("MRS %0, lr" : "=r"(x))`(GCC 语法)报 #18;
* `__asm { MRS x, lr }` 块内联会把寄存器名当 C 标识符报 #20(2026-09-29 实测)。
*/
__asm void HardFault_Handler(void)
{
extern fault_entry_hard
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_hard
}
/* MEMFAULT:访问 MPU 禁止区 / 非法特权级访问。须 SHCSR 的 MEMFAULTENA(bit16) 使能。
* 命中时 CFSR 的 MMARVALID(bit7) 置 1,MMFAR 记录出错地址(报告函数按此判定)。 */
__asm void MemManage_Handler(void)
{
extern fault_entry_mem
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_mem
}
/* BUSFAULT:非法总线访问 / 取指(外设时钟未开、错误指针、DMA 越界等)。
* 须 SHCSR 的 BUSFAULTENA(bit17) 使能。命中时 CFSR 的 BFARVALID(bit15) 置 1。 */
__asm void BusFault_Handler(void)
{
extern fault_entry_bus
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_bus
}
/* USAGEFAULT:未定义指令 / 非对齐访问 / 除零(须 DIV_0_TRP)/ 非法状态。
* 须 SHCSR 的 USGFAULTENA(bit18) 使能。
* ⚠ 本项目**刻意不使用硬件除零陷入**(C 代码里除零应自己判,避免把普通 bug 升级为死机)。 */
__asm void UsageFault_Handler(void)
{
extern fault_entry_usage
TST lr, #4
ITE EQ
MRSEQ r0, MSP
MRSNE r0, PSP
B fault_entry_usage
}
/* 为生成函数改名,避免与上面手工 `__asm` 实现符号冲突。
* 生成实体改名为 <原名>_Gen(永不执行,仅为占名字不冲突,
* 保持生成区代码零删除;未被引用 → 链接器自动移除)。
*
* 覆盖的 4 个 Cortex-M4 异常:HardFault / MemManage / BusFault / UsageFault。
* 后三者须在 SHCSR 中使能对应位才会真正触发(见 fault_handler_enable)。 */
#define HardFault_Handler HardFault_Handler_Gen
#define MemManage_Handler MemManage_Handler_Gen
#define BusFault_Handler BusFault_Handler_Gen
#define UsageFault_Handler UsageFault_Handler_Gen
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_adc1;
extern DMA_HandleTypeDef hdma_spi1_rx;
extern DMA_HandleTypeDef hdma_spi1_tx;
extern DMA_HandleTypeDef hdma_spi2_rx;
extern DMA_HandleTypeDef hdma_spi2_tx;
extern SPI_HandleTypeDef hspi1;
extern SPI_HandleTypeDef hspi2;
extern TIM_HandleTypeDef htim3;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern UART_HandleTypeDef huart4;
extern UART_HandleTypeDef huart5;
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart2;
extern UART_HandleTypeDef huart3;
extern TIM_HandleTypeDef htim7;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/******************************************************************************/
/* Cortex-M4 Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
/**
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void)
{
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
/* USER CODE END MemoryManagement_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
/* USER CODE END W1_MemoryManagement_IRQn 0 */
}
}
/**
* @brief This function handles Pre-fetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
/* USER CODE BEGIN BusFault_IRQn 0 */
/* USER CODE END BusFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
/* USER CODE END W1_BusFault_IRQn 0 */
}
}
/**
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void)
{
/* USER CODE BEGIN UsageFault_IRQn 0 */
/* USER CODE END UsageFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
/* USER CODE END W1_UsageFault_IRQn 0 */
}
}
/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void)
{
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
}
/******************************************************************************/
/* STM32F4xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f4xx.s). */
/******************************************************************************/
/**
* @brief This function handles DMA1 stream3 global interrupt.
*/
void DMA1_Stream3_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
/* USER CODE END DMA1_Stream3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi2_rx);
/* USER CODE BEGIN DMA1_Stream3_IRQn 1 */
/* USER CODE END DMA1_Stream3_IRQn 1 */
}
/**
* @brief This function handles DMA1 stream4 global interrupt.
*/
void DMA1_Stream4_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream4_IRQn 0 */
/* USER CODE END DMA1_Stream4_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi2_tx);
/* USER CODE BEGIN DMA1_Stream4_IRQn 1 */
/* USER CODE END DMA1_Stream4_IRQn 1 */
}
/**
* @brief This function handles EXTI line[9:5] interrupts.
*/
void EXTI9_5_IRQHandler(void)
{
/* USER CODE BEGIN EXTI9_5_IRQn 0 */
/* USER CODE END EXTI9_5_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(TP_BUSY_Pin);
/* USER CODE BEGIN EXTI9_5_IRQn 1 */
/* USER CODE END EXTI9_5_IRQn 1 */
}
/**
* @brief This function handles TIM3 global interrupt.
*/
void TIM3_IRQHandler(void)
{
/* USER CODE BEGIN TIM3_IRQn 0 */
/* USER CODE END TIM3_IRQn 0 */
HAL_TIM_IRQHandler(&htim3);
/* USER CODE BEGIN TIM3_IRQn 1 */
/* USER CODE END TIM3_IRQn 1 */
}
/**
* @brief This function handles SPI1 global interrupt.
*/
void SPI1_IRQHandler(void)
{
/* USER CODE BEGIN SPI1_IRQn 0 */
/* USER CODE END SPI1_IRQn 0 */
HAL_SPI_IRQHandler(&hspi1);
/* USER CODE BEGIN SPI1_IRQn 1 */
/* USER CODE END SPI1_IRQn 1 */
}
/**
* @brief This function handles SPI2 global interrupt.
*/
void SPI2_IRQHandler(void)
{
/* USER CODE BEGIN SPI2_IRQn 0 */
/* USER CODE END SPI2_IRQn 0 */
HAL_SPI_IRQHandler(&hspi2);
/* USER CODE BEGIN SPI2_IRQn 1 */
/* USER CODE END SPI2_IRQn 1 */
}
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
/**
* @brief This function handles USART3 global interrupt.
*/
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
/**
* @brief This function handles UART4 global interrupt.
*/
void UART4_IRQHandler(void)
{
/* USER CODE BEGIN UART4_IRQn 0 */
/* USER CODE END UART4_IRQn 0 */
HAL_UART_IRQHandler(&huart4);
/* USER CODE BEGIN UART4_IRQn 1 */
/* USER CODE END UART4_IRQn 1 */
}
/**
* @brief This function handles UART5 global interrupt.
*/
void UART5_IRQHandler(void)
{
/* USER CODE BEGIN UART5_IRQn 0 */
/* USER CODE END UART5_IRQn 0 */
HAL_UART_IRQHandler(&huart5);
/* USER CODE BEGIN UART5_IRQn 1 */
/* USER CODE END UART5_IRQn 1 */
}
/**
* @brief This function handles TIM7 global interrupt.
*/
void TIM7_IRQHandler(void)
{
/* USER CODE BEGIN TIM7_IRQn 0 */
/* USER CODE END TIM7_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* USER CODE BEGIN TIM7_IRQn 1 */
/* USER CODE END TIM7_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream0 global interrupt.
*/
void DMA2_Stream0_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream0_IRQn 0 */
/* USER CODE END DMA2_Stream0_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi1_rx);
/* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
/* USER CODE END DMA2_Stream0_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream2 global interrupt.
*/
void DMA2_Stream2_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream2_IRQn 0 */
/* USER CODE END DMA2_Stream2_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_rx);
/* USER CODE BEGIN DMA2_Stream2_IRQn 1 */
/* USER CODE END DMA2_Stream2_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream3 global interrupt.
*/
void DMA2_Stream3_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream3_IRQn 0 */
/* USER CODE END DMA2_Stream3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi1_tx);
/* USER CODE BEGIN DMA2_Stream3_IRQn 1 */
/* USER CODE END DMA2_Stream3_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream4 global interrupt.
*/
void DMA2_Stream4_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream4_IRQn 0 */
/* USER CODE END DMA2_Stream4_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc1);
/* USER CODE BEGIN DMA2_Stream4_IRQn 1 */
/* USER CODE END DMA2_Stream4_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream7 global interrupt.
*/
void DMA2_Stream7_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream7_IRQn 0 */
/* USER CODE END DMA2_Stream7_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx);
/* USER CODE BEGIN DMA2_Stream7_IRQn 1 */
/* USER CODE END DMA2_Stream7_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* 使能 MemManage / BusFault / UsageFault 三个异常。
*
* 为什么必须做:复位后 SCB->SHCSR 只开了 HardFault,后三者处于**禁用**状态——
* 它们触发时会被升级成 HardFault,`hard_fault_report` 打出来的是 "HARDFAULT"
* 且看不出根因。这里逐个置使能位,日志里才能直接看到 MEMFAULT / BUSFAULT /
* USAGEFAULT 字样。
*
* ⚠ 刻意**不**打开以下两项(都会把普通 bug 升级成死机,对本项目弊大于利):
* - CCR.UNALIGN_TRP :非对齐访问陷入。Cortex-M4 硬件本可处理非对齐访问,
* 打开后协议解析里常见的非对齐取字段会直接死机。
* - CCR.DIV_0_TRP :除零陷入。除零应由业务代码自己判,不要靠硬件兜。
* 打开它们只会让"本该只是算错个值"变成"整机复位"。
*
* 调用时机:app_main_init() 早期(日志可用前即可,越早越好)。
*/
void fault_handler_enable(void)
{
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk |
SCB_SHCSR_BUSFAULTENA_Msk |
SCB_SHCSR_USGFAULTENA_Msk;
}
/* USER CODE END 1 */