ST电机库学习记录——触发HardFault

发布时间:2026/8/8 8:00:54
ST电机库学习记录——触发HardFault 使用15V电压供电电机能正常启动电压提高到16V时就会进入HardFault_Handler开始怀疑可能是电压升高后启动瞬间的相电流/电流尖峰增大触发了硬件过流保护随后中断处理或嵌套调度导致真正的CPU HardFault。16 V启动 → 电流尖峰触发 COMP1/2/4 → TIM1_BRK_M1_IRQHandler → 在Break中断里再次调用 MC_RunMotorControlTasks() → ADC/FOC中断嵌套、栈压力或非法访问 → HardFault_Handler内存窗口中看到的0x0800566B位于工程映射文件中的R3_2_CurrentReadingPolarization()附近。因此目前最可疑的路径是电流偏置校准 / PWM电流采样 → R3_2_CurrentReadingPolarization() → 电流采样或COMP过流触发 → 内存/栈/中断上下文异常 → HardFault调试发现SCB-CFSR 0x00000100 SCB-HFSR 0x40000000CFSR bit 8 IBUSERR指令总线错误HFSR.FORCED 1BusFault升级成了HardFaultPRECISERR 0、BFARVALID 0不是一个可定位到具体数据地址的普通数据访问错误SCB-BFAR 0xE000EDF8目前无效因为BFARVALID没有置位不能把它当作真实故障地址。出现新方向按键干扰由于VECTPENDING 0x29根据该芯片的中断向量表0x29对应EXTI15_10_IRQn也就是PC13启动/停止按键中断当前处于Pending状态。16 V时如果功率级噪声耦合到PC13可能会产生按键误触发。改为程序自动触发可能性排除系统能够在16-18V稳定启动星期一13:54已处理 1m 52s目前16–18 V能够稳定启动主要得益于以下修改。移除Break中断中的重入调度文件[stm32g4xx_mc_it.c]删除了MC_RunMotorControlTasks();原来过流/过压Break中断中会再次调用完整电机状态机可能与ADC电流环、SysTick任务嵌套造成栈或异常现场破坏。缩小问题发生时间和范围通过已确认稳定的按键或串口启动。不再出现HardFault问题集中在“上电后立即启动”的时序而不是电机运行阶段。当前最可能的链路是MC_StartMotor1() → MCI_StartMotor() → 直接进入启动状态 → 中断/初始化时序冲突或异常栈损坏 → 非法PC 0xA7F708F4 → HardFault自动启动命令已经正确执行故障发生在START启动阶段而不是按键或MCI句柄初始化阶段。由于gHardFaultStackPC 0x07F6F734 gHardFaultStackLR 0x07F739CD这两个地址都不在Flash区0x080xxxxx说明CPU在进入START后发生了非法取指异常栈中的返回地址已经被破坏。怀疑栈空间不足Stack_Size EQU 0x1000即将栈从1 KB增加到4 KB。有一定效果。异常栈已经恢复正常gHardFaultCFSR 0x00000100 gHardFaultStackPC 0x08004450 gHardFaultStackLR 0x0800448B gHardFaultStackXPSR 0x41000000地址映射为0x08004450 → MCI_GetSTMState() 0x0800448B → MCI_StartMotor() 内部因此这次不是非法函数指针也不像栈溢出。当前是CFSR 0x100 → IBUSERR指令总线错误也就是CPU在Flash中执行MCI_GetSTMState()附近代码时发生了指令取指错误。BFARVALID没有置位所以不是数据访问地址错误。锁定问题CPU 取指令时发生总线错误开始查询发生原因还有一个线索宏定义#define M1_CHARGE_BOOT_CAP_DUTY_CYCLES ((uint32_t)0.000\是自举电容充电占空比初始值是0当调大他的数值时系统就不会进入HardFault_Handler而是稳定触发过流保护说明问题集中在“启动初期低侧导通/自举充电”阶段而不是正常运行阶段。FOC 已完整执行高频任务已返回ADC 中断主体已完成PWM 回调指针预检查正常ADC 注入转换状态没有及时清除TIM1 更新中断卡在while (ADCDataReg1[...]-JSQR ! 0) {}这会阻塞 TIM1 ISR造成后续中断时序异常最终出现 HardFault。FOC、高频任务和 Break ISR 都执行过但随后仍发生未定义指令。更重要的是刚才加入的 ADC 超时保护在超时后直接返回这会跳过后续。如果 ADC 等待确实超时PWM 更新中断就不会重新配置 ADC 触发电机自然没有启动意向。也就是说这次“更稳定但电机不启动”很可能是超时保护把启动链路截断了。重新测试发现故障不是 ADC 超时由于发生了未对齐访问。故障地址0x0800968E对应 OPAMP 初始化时的STRD指令该指令要求目标地址 8 字节对齐但诊断变量改变了全局变量布局使hopamp1/hopamp2只满足 4 字节对齐。后经过设置变量验证说明不是 OPAMP 句柄未对齐而是异常栈/返回现场再次损坏。观察到电机启动后的中断活动导致HAL_GetTick()访问地址异常按键启动后定时器中断确实继续运行了约0xD9E次FOC 已经完整执行到0x1E没有检测到回调指针错误ADC 等待没有超时栈只下降了 8 字节不像栈溢出故障每次都落在同一个位置具有确定性。故障现场仍然是gHardFaultStackPC 0x080023D2 - HAL_GetTick() gHardFaultStackLR 0x08002171 - HAL_Delay() gHardFaultStackR0 0xF8802201 BFAR 0xF8802201这里不能理解为“HAL_Delay()本身有问题”。真正异常是执行HAL_GetTick()时CPU试图访问0xF8802201查询官方 MCSDK 的启动路径MC_StartMotor1() → MCI_StartMotor() → SysTick 中的 MC_RunMotorControlTasks() → TSK_MediumFrequencyTaskM1() → IDLE → R3_2_TurnOnLowSides() → CHARGE_BOOT_CAP约10 ms → OFFSET_CALIB / START → PWMC_SwitchOnPWM() → TIM1_UP / ADC1_2 中断 → FOC_HighFrequencyTask()加入启动过程快照gStartTraceStage变量1收到按键启动请求之前的快照 2MC_StartMotor1() 返回之后 3进入 IDLE 启动分支准备低侧导通 4自举电容充电结束准备切换 5调用 PWMC_SwitchOnPWM() 之前 6PWMC_SwitchOnPWM() 返回之后停在stage 1启动请求没有被正常消费。停在stage 3低侧导通或状态机没有继续。停在stage 4自举充电、READY/NFAULT 或定时器状态异常。停在stage 5重点怀疑pFctSwitchOnPwm函数指针或 PWM 句柄。到达stage 6后卡住重点检查首次 TIM1/ADC 中断和电流采样。经过测试启动前 / 自举充电 / PWM首次打开等过程已排除范围缩小到START 状态进入后的 Rev-Up / FOC 高频中断阶段检查START 状态进入后问题发生位置加入变量后调试发现按键请求已正常进入状态机自举充电已完成PWMC_SwitchOnPWM()已返回READY/NFAULT 没有触发保护PWM 函数指针没有异常。FOC 环仍然在运行但给出的Iq转矩参考为零或接近零。此时电机可能只得到很小的电压矢量没有形成足够启动转矩。同时存在异常栈/返回地址破坏发现StackPC0x50519178不是有效代码地址XPSR也不像正常 Cortex-M 异常栈帧。这说明 HardFault 发生时异常栈或返回地址已经被破坏不能再把StackPC当作可靠的故障源码位置。怀疑硬件过流导致出现问题启动时的实际路径是分流电阻电压 ↓ COMP1/2/4 比较器 ↓ TIM1 BKIN ↓ TIM1 Break 中断 ↓ TIMx_BRK_M1_IRQHandler() ↓ PWMC_OCP_Handler() ↓ 关闭 PWM置位 OverCurrentFlag这一条路径中COMP 比较器是硬件异步工作的ADC 软件滤波无法阻止它触发。因此软件 ADC 滤波只能改善 FOC 电流采样不能阻止 COMP 硬件过流HAL_Delay()或等待也不能阻止硬件 Break真正要抑制误触发需要比较器迟滞、消隐、数字滤波、RC 滤波或改善功率级振铃。先区分“真实硬件过流”和“过流中断后软件崩溃”在 Break 中断入口、清除 TIM1 标志之前锁存TIM1SR/BDTR/AF1/AF2COMP1/2/4CSRDAC3DOR1/DOR2GPIOEIDR当时的 CFSR/HFSR增加 OCP 回调指针检查。如果pFctSwitchOffPwm地址异常则不再调用错误函数指针直接关闭 TIM1 主输出设置过流标志记录gBreakTraceGuardFlags避免在 Break 中断中再次 HardFault。加固 HardFault 诊断代码。现在会先验证 MSP、PSP、faultFrame 和 PWM 句柄地址再读取内容避免 HardFault 处理函数因读取坏指针造成二次故障。本次没有直接增加 ADC 软件滤波或大段延时因为 COMP 过流保护是硬件异步路径软件滤波无法阻止它而且可能掩盖真实的功率级振铃问题。测试发现不是过流保护触发而是 CPU 的未对齐访问故障。启动后某个指针、结构体地址或栈数据被破坏导致未对齐访问不是 ADC 数值本身直接触发 HardFault。判断是中频任务执行时出了问题还是电流ADC转换完成中断完成后的高频任务出的冲突变量当前值结论gDiagLastContext0x1F最后记录的是 ADC 转换完成中断正常结束gDiagFOCStage0x1EFOC 高频任务已执行到阶段 30主体已返回gDiagHFStage4高频任务已完成gHardFaultFrameValid0HardFault 堆栈帧已经损坏或无效gHardFaultStackPointer0x10880021不在 SRAM属于异常指针gBreakTraceCount启动前后均为1启动瞬间没有新的 Break/OCP 事件因此当前没有证据表明是中频任务直接触发。ADC 高频任务本体已经执行完成。更像是高频中断返回阶段、异常返回阶段或此前发生了栈/指针破坏。目前无法排除“中频任务进入前后”的边界问题因为原有gDiagLastContext不够细。加入变量gDiagMFStage1 进入中频调度 2 开始处理启动/停止命令 3 启动/停止命令处理完成 4 即将进入 TSK_MediumFrequencyTaskM1 5 中频任务及回调完成 6 即将进入安全任务 7 中频调度完成 0xE1 运行完整性检查失败 0xE2 MCboot 尚未完成不是中频任务出错而是中频任务已经完成随后 ADC 转换完成中断中的高频 FOC 已完成故障更可能发生在 ADC 高频中断退出、异常返回或此前已经发生的栈/指针破坏。屏蔽高频任务看看电机启动后中频任务是否有问题ADC 转换中断仍然运行但不会调用TSK_HighFrequencyTask();同时会清除TIM1-BDTR.MOE因此这次测试中电机不会真正输出 PWM 旋转只用于验证中频任务和状态机。重新启用时将gDiagDisableHFTask 0屏蔽高频任务后ADC 中断仍在运行。中频任务持续执行并正常返回。中频任务没有引起 HardFault。原来的 HardFault 需要高频 FOC 任务或其与 PWM/ADC 的交互才会出现。排除中频任务本身直接触发 HardFaultSysTick 中频调度栈溢出本次测试中的硬件 Break/OCP 触发。高频任务问题判断修改代码实现高频 FOC 继续执行ADC 电流采样继续执行FOC 运算继续执行跳过PWMC_SetPhaseVoltage()每次强制清除TIM1-BDTR.MOE禁止实际 PWM 输出。测试后发现高频任务确实在执行FOC 高频任务主体能够完成中频任务也能够完整执行最后进入FAULT_OVERPastFaults0x0010是MC_START_UP启动失败不是 HardFault因为 PWM 更新被屏蔽启动失败是预期结果。允许 PWM 更新重新测试执行真实 PWM 后出现了指令总线故障。从数据看gDiagPWMUpdateRunCount 0x25已实际执行 37 次PWMC_SetPhaseVoltage()。gDiagPWMUpdateLastError 0PWM 计算函数返回正常。gDiagPWMStateBefore 1PWM 当时已开启。gDiagPWMBDTRBefore/After 0x2333BC3BMOE 未被软件清除。gDiagValpha -10、gDiagVbeta 86初始电压指令很小没有明显越界。gHardFaultFrameValid 1、gHardFaultFrameSource 1HardFault 堆栈帧有效来自 MSP。得到结论电机启动、PWM 开始输出后CPU 在取指令时发生 BusFault。尝试软件上解决问题滤除窄毛刺、保留真实过流保护、降低 24 V 启动冲击COMP1/COMP2/COMP4 增加10 mV迟滞减少比较器阈值附近振荡。TIM1 实际使用的是Break1已把滤波编码从3调整为8。当前 170 MHz、CKDDIV2 下约要求故障持续0.56 µs才触发。小于此宽度的开关毛刺会被滤除。持续过流和 STSPIN32G4NFAULT仍会立即关闭 PWM。测试结果启动后gDiagPWMUpdateRunCount0x22真实 PWM 更新成功运行了 34 次。gDiagPWMUpdateStage3PWMC_SetPhaseVoltage()已正常返回。gDiagPWMUpdateLastError0占空比计算没有报告错误。gDiagFOCStage0x1E整个 FOC 高频任务已经走到出口。gDiagHFStage4高频任务完整返回。gDiagLastContext0x1FADC 中断已经执行到末尾。Valpha4、Vbeta11故障前并没有输出异常大的电压矢量。gBreakTraceCount、TIM1_SR、电机故障字均未变化。gOcpFilterCode8、COMP CSR0x00010040比较器迟滞和 Break 滤波已经生效。测试后发现不是比较器过流且无法通过配置COMP解决而是物理 PWM 开始输出后ADC 高频中断完整执行若干次随后在中断返回或紧邻位置发生非法取指。阶段性总结问题测试方式结果按键误触发初始化后直接调用MC_StartMotor1()仍可复现COMP/OPAMP重复初始化在HAL_COMP_Init()等位置断点只在上电初始化进入中频任务自身崩溃屏蔽高频任务只运行中频状态机无 HardFault只因无电流环进入预期故障状态ADC/FOC计算本身高频任务运行但禁止真实 PWM 更新可以持续运行PWMC_SetPhaseVoltage()同步崩溃观察 Stage 和返回值Stage3、Error0函数已经返回软件电压矢量溢出记录Valpha/Vbeta故障前数值很小硬件过流 Break比较 Break 计数、TIM1_SR、电机故障字启动前后均未变化比较器阈值振荡加 10 mV 迟滞和 BKF8配置已生效但故障仍存在普通栈溢出4 KB 栈、记录最小 MSP、栈保护标志未发现栈越界明显空指针/外设实例错误检查 PWM、OPAMP 指针和运行保护标志地址合理、保护标志为 0SysTick/HAL_GetTick根因屏蔽 PWM 时 SysTick长期运行正常不是独立根因确定性的 MCSDK算法错误低电压稳定同一程序随母线电压升高才出现不符合普通确定性算法错误特征尝试不修改硬件的情况下能通过调整配置解决目前现象PWM能够输出几次才发生HardFault。尝试一完整执行状态机、ADC、FOC 和 CCR 更新但禁止 TIM1.MOE功率管不动作结论24V 上电并启动。电机不转是正常现象。没有进入HardFault。允许真实 PWM 边沿但强制输出零电压矢量。尝试二允许真实 PWM 边沿但强制输出零电压矢量。结论锁定HardFault 需要“真实功率级开关边沿”才会出现与 FOC 输出电压大小、启动电流或按键无关。普通“降低FOC占空比”不能可靠解决因为零矢量虽然三相线电压接近零但三个桥臂仍以约50%占空比产生完整的24V开关边沿。降低调制量只降低电流不降低每个边沿的24V幅度。尝试三把 STSPIN32G4 栅极驱动 VCC 从当前12V降到8V保持20kHz和零矢量观察边沿减缓后是否稳定。8V测试结果无改善配置及回读均成功但仍在约0x22次FOC更新后HardFault与12V时的0x23基本一致。尝试四栅极驱动保持8V。PWM从20kHz降至10kHz。已确认这次三相零矢量测试仍会 HardFaultgHardFaultCFSR 0x1400非精确 BusFault 异常入栈失败。MSP 已损坏为非法地址。10 kHz 只是让故障从约 34 次延后到 40 次 PWM 更新不能解决问题。因此基本排除 FOC 电压矢量和电机电流本身故障需要真实开关沿才能产生。尝试五仅 U/V 相半桥开关8 V 栅极电源、10 kHz、零矢量、过流保护均保留。没有进入HardFault 结论单桥臂稳定运行0x40AD次而三桥臂约0x28次就 HardFault故障与多桥臂同步开关瞬态高度相关不是过流保护或 FOC 运算错误。尝试六改为 UV 双桥臂测试直接进入HardFault 双桥臂正常运行时故障尝试七双桥臂错沿测试U/V 两桥臂开启。两相比较沿相差128个定时器计数。8 V 栅极电源、10 kHz、零矢量不变。错沿有效但尚未完全消除问题原双桥臂同步换相通常约0x23次就故障。加入 64 tick 错沿后多次可运行到0x37F、0x40AD说明故障概率已经显著下降。偶发 HardFault 的CFSR0x00020000是INVSTATE异常帧中的 PC、LR、xPSR 同时损坏仍是开关瞬态破坏 CPU 执行状态不是程序主动跳到某个错误函数。PastFaults0x0010是双桥臂/零矢量测试无法建立转速后的预期启动失败不是过流Break 计数仍为 0。尝试八双桥臂错沿从 64 tick 加大到 128 tick预期的启动超时当前零矢量测试不会产生旋转状态机随后停止 PWM。任然可能触发HardFaultIBUSERR而且异常帧被破坏把错沿从 64 增至 128 没有消除故障因此暂时不再继续盲目增大占空比差。尝试九恢复栅极驱动 VCC到12VPWM到20kHz问题依旧……

相关新闻