Files
STM32F4-Base/Src/stm32f4xx_it.c
T
wandering1 970e574433 feat(adc): 1 kHz 采样节拍改由 TIM6 硬件定时器触发
- CubeMX 加 TIM6(PSC=83 / ARR=999 / ARR 预装载 / NVIC 抢占优先级 6)
- Src/main.c 回调加 TIM6 分支触发 CONVST(USER CODE 区)
- app_main.c 用 HAL_TIM_Base_Start_IT(&htim6) 替换单次触发
- adc_task.c 退化为纯消费者(1 ms 轮询仅作消费节奏)
- @build 0 错 0 警;台架 @test 验收待做
- 同步 ADC采样节拍设计说明 / 继电保护复现规划 / AGENTS / TPAFE README
2026-10-10 15:24:02 +08:00

608 lines
17 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"
/* 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、不遍历指针,只用 HAL_UART_Transmit 轮询 + SCB 寄存器读取,
* 因此在内核状态已不可信时仍可用。输出后 HAL_Delay(200) 排空 UART 再复位。
*/
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;
}
HAL_UART_Transmit(&huart1, (const uint8_t *)s, len, 0xFFFFu);
}
/* 字面量输出宏:长度由 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 函数里做。
*/
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);
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_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 htim6;
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 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 TIM6 global interrupt, DAC1 and DAC2 underrun error interrupts.
*/
void TIM6_DAC_IRQHandler(void)
{
/* USER CODE BEGIN TIM6_DAC_IRQn 0 */
/* USER CODE END TIM6_DAC_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_DAC_IRQn 1 */
/* USER CODE END TIM6_DAC_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 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 */