From f3580f38e44bc9d6a201f04d8aa9b74e50b69e87 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Tue, 20 Oct 2026 21:11:29 +0800 Subject: [PATCH] =?UTF-8?q?docs(review):=20=E4=B8=93=E5=AE=B6=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=202026-10-19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/review/Motor_v2_专家评审_2026-10-19.html | 64 +++++++++++++++++++ .../STATIC_ANALYSIS_NOTES_复核_2026-10-19.md | 34 ++++++++++ 2 files changed, 98 insertions(+) create mode 100644 docs/review/Motor_v2_专家评审_2026-10-19.html create mode 100644 docs/review/STATIC_ANALYSIS_NOTES_复核_2026-10-19.md diff --git a/docs/review/Motor_v2_专家评审_2026-10-19.html b/docs/review/Motor_v2_专家评审_2026-10-19.html new file mode 100644 index 0000000..35711af --- /dev/null +++ b/docs/review/Motor_v2_专家评审_2026-10-19.html @@ -0,0 +1,64 @@ + +Motor_v2 专家评审 2026-10-19
+

Motor_v2 电机固件专家评审

+
仓库 cbb/Motor_v2 · 分支 master · 评审基线提交 86ca766(2026-10-13 “feat(motor): 引入运行禁止机制重构电机控制安全系统”)· 评审日期 2026-10-19 · 静态评审,未实编/未上机
+
2致命
15严重
22一般
11建议
5.6综合评分/10
+ +

1. 项目概述与架构

+
GD32C103CB(Cortex-M4F,120 MHz)上的无刷电机 FOC 驱动固件,配 DRV8313 门驱动、KTH7823 磁编码器,CAN-FD(仲裁 1 Mbps / 数据 5 Mbps)与上位机通信;CMSIS-Toolbox csolution + AC6(microlib) 构建;应用位于 0x08012000,配合独立 BOOT 实现 OTA。最新提交引入了 RunInhibit 位图式“运行禁止”闸门,作为功率级唯一执行者。
+
┌──────────────── GD32C103CB (Cortex-M4F @120MHz, APP @0x08012000) ────────────────┐
+│ 中断层                                                                            │
+│  ADC0 注入组(TIMER1 CH3 TRGO 触发) ─► 写三相电流 + 置 TASK_CURRENT_UPDATE  [prio 0,0] │
+│  TIMER2 50µs 节拍 ─► 置任务位(角度/速度/电机控制/1ms CAN …)              [prio 0,1] │
+│  TIMER1 中心对齐 PWM ≈20.0067kHz (ARR=2999)                              [prio 0,2] │
+│  SysTick 1ms(delay/CPU 统计)  [0]   CAN RX0/TX/DMA0-CH4  [prio 1]                  │
+├──────────────────────────────────────────────────────────────────────────────────┤
+│ 主循环 main.cpp:关中断取任务位快照 → do_task()                                       │
+│   ├ 高频:KTH7823 SPI 读角度 → α-β/卡尔曼 → run_inhibit.update() → FOC 模式分发        │
+│   │        Clarke/Park → PID(电流/速度/位置/MIT) → 逆Park → SVPWM → Set_3Pwm          │
+│   ├ 低频:health(热模型/欠压/nFAULT) · power_manage · 喂狗                            │
+│   └ CAN:CAN-FD(仲裁1M/数据5M) 命令解析 · 周期反馈帧 · 参数持久化(flash.cpp EEPROM)   │
+├──────────────────────────────────────────────────────────────────────────────────┤
+│ 存储:EEPROM 模拟 0x0801F800-0x08020000(2×1KB) · 节点ID 乒乓双备份+CRC · OTA/备份区   │
+└──────────────────────────────────────────────────────────────────────────────────┘
+
目录主要文件职责规模(行)
Algorithm/FOC.cpp/h、pid、Filter(α-β/卡尔曼)坐标变换、SVPWM、多模式控制环、零位校准~1.8k
device/Can、ADC、Timer、ang_sensor、motorCAN-FD 协议栈、注入采样、PWM、KTH7823 SPI、DRV8313 使能~3.6k
sys/flash、health、run_inhibit、initial、systick、config参数持久化/OTA、保护、运行禁止闸门、初始化、时基~3.0k
顶层main.cpp、tasks.cpp调度主循环、任务拆分~0.4k
RTE/GD32C10x 标准库、启动文件、链接脚本厂商库(含本地修改)—
+ +

2. 评审范围与方法

+
+ +

3. 问题清单(50 条)

+
编号严重度领域文件:行号标题 / 现象风险修改建议
M01致命CAN/FOCdevice/Can.cpp:1128-1132;Algorithm/pid.cpp:50,126控制帧目标电流/速度直接作为 PID 限幅,未校验符号与有限性
目标电流 target_current、目标速度 target_velocity 被原样传入 set_limit();pid.cpp:50 _constrain(x,-limit,limit) 在 limit<0 时上下界颠倒;NaN/Inf 未过滤。
mode3/4/5 下发负值时 PID 输出被钉在 +|limit|,与误差方向无关,可导致反向满压、电机失控;电流环限幅(电压量纲)被设为电流值,单位错配。协议层对所有浮点字段做 isfinite() 与范围夹紧;set_limit 内取 fabsf 并拒绝非正值;电流环输出限幅改用 limit_voltage/v_safe,与目标电流分离。
M02致命Flash/安全sys/flash.cpp:304-321,393-404,887-899(format 后 save_system_config);sys/flash.cpp:77-84EEPROM 页满重建时丢失电角度零位校准角
任一写入触发页满 → format() 擦除两页 → save_system_config(false) 只重写 6 个控制参数、CRC 与两个刷新周期,不重写 ADDR_CALIBRATION_ANGLE(0x07);若正是写校准角触发的页满,新校准角同样不会写入。上电回退默认 83°。
换向角错误 → 力矩方向/大小错误,速度环可能正反馈失控,且无任何告警(init 认为读取失败属正常首启)。save_system_config 重建路径同时重写校准角(及将来所有独立记录);或改为双页轮转搬运最新有效记录;无有效校准角时置 INHIBIT 位禁止闭环并上报。
M03严重CAN/安全sys/run_inhibit.h:19-29;device/Can.cpp(无命令超时逻辑)无通信超时/心跳丢失停机
禁止来源仅 nFAULT/欠压/过热/采样失效/未使能,无 CAN 超时来源;收到最后一条控制帧后电机持续执行。
上位机死机、线缆脱落、总线 Bus-Off 时电机按最后目标一直运行(速度模式下持续转动)。新增 INHIBIT_COMM_TIMEOUT:控制帧到达刷新时间戳,超时(可配置,如 100 ms)request(),收到新控制帧再 release;超时阈值可经 CAN 配置并持久化。
M04严重FOC/安全Algorithm/FOC.cpp:59-63;sys/systick.cpp:164-168零位校准在主循环阻塞约 1 s 且持续喂狗
calibrate_zero_position() 直接 motor_resume() + Set_3Pwm(ALIGN_PWM_DUTY) + delay_1ms(1000);delay_1ms 循环内 fwdgt_counter_reload()。
1 s 内欠压快检、nFAULT 轮询、热模型、CAN 处理全部停摆,看门狗也被持续喂而失去意义;对齐电流无限流、对齐后未判转子静止。改为非阻塞状态机(每 50 µs 推进),期间 run_inhibit/保护任务照常运行;对齐时做电流闭环或占空比按 Vbus 归一;delay_1ms 内不得喂狗。
M05严重安全/FOCAlgorithm/FOC.cpp:426-431;sys/config.h(MAX_VCC 仅作读数有效判定)无过压保护,Vbus>36 V 时 SVPWM 按旧电压归一
update_power 仅接受 8–36 V,超出时保留旧 Vdc;固件无过压禁止位,回馈泵升无处理。
制动/回馈时母线抬升,实际相电压被放大,叠加功率器件超压,存在击穿 MOSFET/驱动风险。增加 INHIBIT_OVERVOLTAGE(带回差与防抖);超限时继续用实测 Vbus 归一;必要时短路制动或限制回馈电流。
M06严重实时性/安全RTE/Device/GD32C103CB/startup_gd32c10x.s:178-181;gd32c10x_it.c 未编入工程HardFault 等异常直接死循环,PWM 保持最后占空比
实际生效的是启动文件弱定义 `B .`,不关 PWM、不睡眠驱动,依赖约 50 ms 看门狗复位。gd32c10x_it.c 不在 cproject 编译列表且重复定义 SysTick_Handler。
异常期间三相按最后占空比输出最长约 50 ms(IRC40K 偏差下更不确定),可能过流/冲击。实现强定义 HardFault/MemManage/BusFault/UsageFault/NMI:首先关 TIMER1 输出(CHxEN/POEN)并拉低 nSLEEP,再保存故障现场到 BKP/保留 RAM,最后复位。
M07严重安全device/Can.cpp:1167-1168;device/motor.cpp:243-249;sys/run_inhibit.cpp:32-45motReset 直接唤醒驱动,绕过运行禁止闸门的睡眠状态
RESET bit0 先 release(NFAULT) 再 motor_reset()(sleep→resume)。若其他禁止位仍在,闸门 stopped 已为 true,不会再次 motor_sleep(),驱动保持唤醒。
欠压/过热/未使能期间驱动被唤醒(PWM 虽被置 0,但违背单一执行者设计,DRV8313 故障锁存也被清除)。motReset 仅 release(NFAULT),驱动睡眠/唤醒全部交给 RunInhibit::update();或在闸门中把 stopped 置 false 强制重新施加睡眠。
M08严重CAN/Flashdevice/Can.cpp:940,1048,1175;sys/flash.cpp(writeNodeId/save_system_config/format)运行中 Flash 擦写使控制环停摆
节点 ID、刷新周期、RESET bit2 存参等命令在主循环中直接擦写 Flash,不检查电机是否静止;FOC 控制环也在主循环(tasks.cpp:96-118)。
单 bank 擦页期间 CPU 取指停顿数十 ms,PWM 保持最后占空比,控制失效;可能触发看门狗复位。仅在 control_mode==0 且被禁止/静止时允许持久化;否则延迟到停机或回 NACK;擦写前先 request(INHIBIT_FLASH_BUSY)。
M09严重CANdevice/Can.cpp:950,967-981旧格式 SET_NODE_ID 未拦截广播
DLC 1/2 的旧格式允许 target_node==BROADCAST;扩展格式(约 1010 行)已拦截,旧格式没有。
一条广播帧可把总线上所有节点改为同一 ID,造成 ID 冲突、命令错发至多个电机。旧格式同样拒绝广播目标,并要求魔数/二次确认;考虑废弃旧格式。
M10严重Flashsys/flash.cpp:444,906;sys/health.cpp:195一次欠压保存后本次上电所有存参被跳过
欠压路径 save_system_config(true) 将 system_config_saved 置 true 且永不清零,此后 444 行直接返回 OK。
欠压恢复后的参数修改、进 BOOT 前保存、format 后的重建全部被静默跳过 → 与问题 2 叠加,页满时整页参数丢失。save 标志只用于“本次欠压已保存”,在欠压解除时清零;format 重建路径应强制保存(忽略该标志)。
M11严重Flashsys/flash.cpp:413-430,161-181;main.cpp:107EEPROM 无掉电原子性,CRC 错误时参数全部归零
format() 同时擦除两页,无备份页;format 可能在欠压保存路径中被触发;CRC 错误时全部参数回 0(含多圈角度 angle_set);main 不检查 flashEEP.init() 返回值,也不进 init_error_flags。
掉电/欠压期间擦写失败即全部配置丢失,上电以 0 参数运行;多圈位置丢失。采用双页交替(有效页标记 + 搬运后再擦旧页);欠压时禁止 format;init 失败置初始化错误位并禁止运行。
M12严重安全sys/health.cpp:98-103,212-213过热/欠压解除后自动恢复运行
保护解除后不需上位机确认,电机直接按原模式、原目标继续动作;过热还会在 PROTECT_TIME 到期后按时间解除。
无人值守下电机突然重新转动,存在机械伤人/撞击风险。故障解除后保留 INHIBIT_NOT_ENABLED(需上位机重新下发使能);过热解除改为温度回差而非定时。
M13严重实时性device/Timer.cpp:75-107,139-141;sys/config.h:376,384控制节拍与 PWM/采样不同步,频率不一致
TIMER2 产生 50 µs(20 kHz) 任务节拍;TIMER1 中心对齐 ARR=2999 → 周期 5998 clk ≈ 20.0067 kHz。两者约 150 ms 拍频一次。
采样到控制的延时在 0~50 µs 漂移,每秒约 6.7 帧被重复/丢弃,产生约 6.7 Hz 转矩纹波与噪声。由 ADC 注入完成中断(或 TIMER1 更新事件)驱动 FOC 计算;修正 ARR 使周期整数匹配;去掉独立的 TIMER2 控制节拍。
M14严重实时性device/Timer.cpp:329-342PWM 比较值写入未开影子寄存器预装载
Set_3Pwm 直接写 CHxCV,全仓无 timer_channel_output_shadow_config 调用。
周期中途更新产生窄脉冲/不对称脉冲,扰动低边电流采样窗口并增加开关损耗。对 CH0~CH2 开启 TIMER_OC_SHADOW_ENABLE,并开启 ARR 预装载。
M15严重实时性main.cpp:67-80;device/Timer.cpp:139无任务超时/丢拍检测
主循环一轮超过 50 µs 时任务位被静默合并,控制直接丢拍,无计数无上报。
高负载(CAN 突发、Flash 擦写)时控制周期失真不可见,调试困难,严重时失稳。在 TIMER2 ISR 中检测上次置位未被取走则累加 overrun 计数,通过 CAN 状态帧上报;超阈值请求禁止。
M16严重FOCAlgorithm/pid.cpp:64-68;device/ang_sensor.h:103-111;Algorithm/FOC.cpp:509-510NaN/Inf 目标值导致积分污染与死循环
NaN 进 PID 后斜坡 fminf/fmaxf 使输出按最大速率爬升且积分永久为 NaN;Inf 进 normalizeAngle360 的 while 循环永不结束(mode6 开环角度累加路径)。
控制输出失控或主循环卡死(之后仅靠看门狗复位,期间 PWM 保持)。协议层过滤非有限值;normalizeAngle360 改用 fmodf 并对非有限输入返回 0;PID 入口检测 isfinite 并复位。
M17严重FOC/安全device/ang_sensor.cpp:78,160-176角度传感器读失败/断线未升级为禁止运行
读失败返回 FAULT_RECEIVE 并保留旧角度,无错误计数、不请求 inhibit;读回 0xFFFF(MISO 浮空)被当作有效;TRANS 标志等待无超时。
编码器断线时以陈旧/错误角度换向,力矩方向错误,可能飞车。连续 N 次读失败或校验失败 → request(INHIBIT_ENCODER_FAULT);识别 0x0000/0xFFFF 等非法值;TRANS 等待加超时。
M18一般CANdevice/Can.cpp:1117控制帧不校验长度与模式范围
短帧缺失字段按 0 处理(P 增益等被清零);P_config、control_mode 无范围检查,tasks.cpp:113 对非法模式仅不执行。
错误/截断帧改变控制参数,行为不可预期。按命令定义校验 DLC 与字段范围,不合法回 NACK 且不修改任何状态。
M19一般CANdevice/Can.cpp:1187RESET 深睡眠位判断运算符优先级错误
`eigth_byte & 0x80 >> 7` 等价于 `eigth_byte & 1`,实际判断 bit0 而非 bit7。
上位机置 bit0 时意外进入深睡眠,bit7 反而无效。改为 `(eigth_byte >> 7) & 0x01` 或 `eigth_byte & 0x80`。
M20一般CAN/FOCdevice/Can.cpp:1177-1181运行中可清零角度
RESET bit3 不检查状态即 angle_set(0) 并重置卡尔曼。
位置模式下目标与实际角度瞬间跳变,电机猛冲。仅在 mode0/禁止状态下允许,或同时把 target_angle 置为新零点。
M21一般CANdevice/Can.cpp:1395,744TX 路径主循环与 ISR 竞争邮箱、乱序
CANFD_AsyncSend 在主循环直接 can_message_transmit,同时 TX 中断从队列填邮箱。
选邮箱竞态、新帧绕过队列先发,反馈帧时序错乱。统一经 TX 队列发送,仅在临界区内检测空邮箱并启动。
M22一般CANdevice/Can.cpp:896-924BOOT 帧无魔数/校验
任何基础 ID 0x0000 的帧都可触发进 BOOT 或节点静默。
误触发导致电机离线。增加魔数 + 目标节点 + 停机状态校验。
M23一般CANdevice/Can.cpp:575,630远程帧未过滤
rx_ft 读出后未判断,远程帧被当作数据帧处理。
DLC 非 0 的远程帧携带随机数据进入命令解析。丢弃 RTR 帧或单独处理。
M24一般CANdevice/Can.cpp:359,413,1241-1251总线错误/Bus-Off 不可见,FIFO 溢出分支不可达
未开错误中断,Bus-Off 不上报也不纳入保护;只开 RFNE,FIFO 满/溢出处理永远进不去。
总线故障时静默失联(与无通信超时叠加)。开启 EWIE/BOIE/ERRNIE,记录 TEC/REC,Bus-Off 时请求禁止并按策略恢复。
M25一般CANdevice/Can.cpp:394-407;sys/config.h:341硬件过滤器全收,默认 STATUS 1 kHz×48 B
所有帧靠软件过滤。
多节点组网时总线与中断负载偏高。按节点 ID 配置硬件过滤器;默认刷新率下调。
M26一般CAN/Flashdevice/Can.cpp:1034反馈刷新周期无下限且每次设置都写 Flash
可配置为极小周期;频繁设置磨损 Flash。
总线饱和、Flash 寿命下降。设定下限(如 1 ms);值未变不写(write 已跳过同值,但应在命令层限频)。
M27一般Flashsys/flash.cpp:230-257readFloat 无保留字节防护,可能误读 CRC 字
read() 在 206 行用保留字节排除 CRC 字,readFloat 没有同类防护,扫描至头部 CRC 区。
记录不存在时可能把低字节为 0x07 的 CRC 字当作校准角返回,calib==0 判定拦不住。float 记录格式加入类型标记/校验位,或扫描时跳过 CRC 区。
M28一般Flash/BOOTsys/flash.cpp:929-1016,1077-1098OTA 标志与备份区搬运缺乏原子性
OTA_SET 擦页后未写回目标值;前序写失败后 FMC 已锁,后续擦除失败;move_app_data 擦除备份区前未先作废 BACKUP_AVAL,48 页擦除期间关中断且不喂狗;新 APP 首启即覆盖备份区,A/B 回滚失效;地址注释过时。
升级中途掉电变砖或回滚失效。先作废标志再擦写、分段喂狗、确认新 APP 正常运行后再覆盖备份;更新注释。
M29一般安全Algorithm/FOC.cpp:466-468;sys/config.h:407-408欠压快检基准只升不降,阈值注释不一致
vbus_reference 峰值保持无衰减;回馈短时抬高后恢复正常即被判跌幅>5 V;高母线时恢复阈值(×0.9)低于触发阈值(−5 V)会抖动;注释默认 8 V,实际 12 V。
误跳闸、保护抖动。基准改为慢速低通跟踪;触发/恢复阈值统一并带回差;更正注释。
M30一般FOCAlgorithm/FOC.h:47;Algorithm/FOC.cpp:429,413;device/Timer.cpp:329-342v_safe 初值与运行值不一致,占空比无统一限幅
初值 Vdc/1.05,运行值 Vdc×1.1;首次 update_power 前 T0 可能<0 → 负占空比;Set_3Pwm 不限幅,负浮点转 u32 为未定义行为。
上电首拍产生异常占空比。Set_3Pwm 内统一夹紧 [0, Dmax];v_safe 初值与运行公式一致。
M31一般FOC/实时性sys/config.h:395-397;Algorithm/FOC.cpp:95-98最高占空比约 95.5% 超出采样窗口要求(约 90%)
高调制时 W 相低边导通时间不足,电流读数趋零,经共模去除把误差分摊到 Iq;注释“每周期匹配两次”与实际单沿触发不符。
高速/高负载时转矩估计失真。限制最大占空比或做两相动态选相采样;修正注释。
M32一般FOCAlgorithm/FOC.cpp:526,546,636-640,751多模式积分饱和与热路径改写用户限幅
526 行在热路径直接改写 limit_voltage;mode1/4/5 由 SVPWM 或外部钳位限压,但 PID 内部 limit 仍为 Vdc,积分 windup。
大扰动后超调、恢复慢。各环 PID 的 limit 与实际执行限幅一致;不在控制路径改写用户参数。
M33一般实时性device/ADC.cpp:62-63,467-481电流三相读取与清 ready 无原子保护(撕裂)
ISR 可能在读取三相中途写入新帧,三相来自不同帧,或丢失一帧 ready。
偶发电流尖峰/误判采样失效。读取侧用 LDREX/STREX 或序号双读校验(seq 前后相同才接受),无需长临界区。
M34一般实时性main.cpp:53-65;sys/initial.cpp:255看门狗启用晚,复位原因未读取
看门狗在 OTA 初始化与磁检之后才开启,初始化失败循环中既无看门狗也不喂狗;未读 RCU_RSTSCK。
上电阶段卡死不自动复位;现场无法区分看门狗/软件/欠压复位。尽早启用看门狗;启动时读取并上报复位原因后清除。
M35一般构建startup_gd32c10x.s:42,53;regions_GD32C103CB.h:102-103栈/堆大小两处定义不一致
启动文件 Stack 0x800/Heap 0x800;regions 头文件 0x200/0xC00。缺少最坏栈深分析。
实际生效值不明,存在栈溢出隐患。以 map 确认生效值并统一一处;用 armlink --info=stack/--callgraph 核算最坏栈深;栈底放哨兵。
M36一般FOCdevice/ang_sensor.cpp(SPI 初始化 prescale)SPI 分频与注释不符
prescale=24 实际映射为 /16,约 7.5 MHz,注释写 5 MHz。
超出传感器/走线裕量时误码。按手册确认 KTH7823 最高时钟并使用正确枚举。
M37一般安全sys/health.cpp:150-153,252-256;Algorithm/FOC.cpp:89-91若干故障只上报不禁止
温度传感器失效(255)被置 0,温度保护静默失效;编码器 MagStatus 只上报;单相电流失效时用陈旧 Kalman 值继续闭环;无软件瞬时过流与堵转保护。
保护覆盖不全。传感器失效 → 禁止运行;增加软件过流(相电流阈值+计数)与堵转(Iq 大且速度≈0 持续 T)保护。
M38一般构建Robot_V2/Robot_V2.cproject.yml:misc;Robot_V2.csolution.yml:build-types编译选项与 build-types 冲突,链接诊断大面积抑制
cproject 对所有构建强制 -O3,覆盖 Debug optimize:none / Release balanced;Link 抑制约 70 个 L62xx/L63xx 诊断(含 L6329 重复)。
Debug 不可调;真实链接问题被掩盖。移除 cproject 中 -O3,由 build-types 控制;只保留确认无害的个别抑制。
M39一般构建Robot_V2/RTE/Device/GD32C103CB/*.c 与 *.base@1.0.0厂商库文件被本地修改(与 .base 差异)
25 个 RTE 设备文件与 base 不同(如 system_gd32c10x.c 改了 VECT_TAB_OFFSET=APP_BASE 0x08012000 并加注释,timer/can/adc 库也有改动)。
pack 更新时修改被覆盖或合并困难,应用基址隐藏在厂商文件中。将应用基址等改动移到用户代码(如 SystemInit 后设置 SCB->VTOR)或文档化;尽量恢复厂商库原样。
M40建议构建仓库根目录缺少 README / 协议文档 / 构建说明 / CI
无 README,CAN 命令集只存在于代码注释。
新人与上位机开发者难以对接,回归无保障。补 README(硬件、构建、烧录、地址布局)与 CAN 协议表;增加 cbuild CI 与主机端 PID/SVPWM 单元测试。
M41建议代码质量Robot_V2/Algorithm/thermal.cpp,.h空壳文件未加入工程
thermal.cpp 仅有文件头注释,未在 cproject 中。
死代码干扰阅读。删除或实现后加入工程(热模型目前在 sys/health.cpp)。
M42建议代码质量RTE/Device/GD32C103CB/gd32c10x_it.c死文件且重复定义 SysTick_Handler
不在编译列表。
误加入工程会产生重复定义。删除,或改为强定义异常处理的唯一来源。
M43建议构建.continue/、.vscode/c_cpp_properties.jsonIDE 配置入库
Continue MCP 模板(无敏感信息)与 windows-gcc-x86 IntelliSense 配置(与 AC6 目标不符)。
噪声、误导。加入 .gitignore 或改为 arm 交叉配置。
M44建议代码质量sys/initial.h:10-176,42;sys/initial.cpp:7,15头文件与 C/C++ 混用问题
头文件中定义 static 变量;C++ 类包在 extern "C" 中;initial.h 被重复包含;fputc 使用 throw()。
每个编译单元各有副本、链接语义混乱。static 变量移入 .cpp;extern "C" 只包 C 接口;去掉 throw()。
M45建议代码质量sys/flash.h:59 等魔数与命名不一致
ADDR_VEL_LIMIT 实际存 target_current;多处魔数。
维护误用。重命名、集中常量。
M46建议FOCAlgorithm/FOC.cpp(Ud 恒 0);Algorithm/Filter.cpp(CurrentKalman Q=10,R=5e-5)Id 未闭环;电流卡尔曼增益≈1 等于不滤波
Ud 恒为 0;Kalman 参数使滤波失效。
高速/弱磁场景能力受限;无效计算消耗 CPU。增加 Id 电流环(目标 0);重新整定或移除该滤波器。
M47建议FOCAlgorithm/FOC.cpp(SVPWM)SVPWM 量纲约定未注明
Uq 量纲为相幅值的 √3 倍(数值验证扇区与角度误差约 1e-13,变换正确)。
参数整定易误解。在注释中写明电压归一化约定。
M48建议CANdevice/Can.cpp:366-390CAN-FD 位时序裕量待确认
数据段 5 Mbps 仅 6 tq、SJW=1,TDCO=4 单位需对照手册。
长线/多节点时误码。按手册核算采样点(70–80%),示波验证 TDC。
M49建议实时性system_gd32c10x.c:857未开启时钟监控 CKM
晶振起振失败卡在 while(1)。
板级故障时无安全输出。开启 CKM,NMI 中安全停机。
M50建议CANdevice/Can.cpp:331,1292;Can.h:226-228CAN RX DMA 收益有限、残留死代码
M2M 按帧启动 DMA;通道 5 中断为空;旧 rx_message_buffer 队列无人调用。
额外中断与维护负担。评估直接读邮箱;删除死代码。
+ +

4. 既有评审(STATIC_ANALYSIS_NOTES.md)结论跟踪

+
条目原结论当前状态证据 / 说明
SUP-GLB-001 编译期常量(ADC/health/config constexpr)误报/偏离仍成立ADC.cpp:22-47;health.cpp:107;config.h 全部为 constexpr
硬件单例 FOC / sampler / CAN0_transmiter / KTH7823 / thermalController / Version接受单例仍成立FOC.cpp:28;ADC.cpp:60;Can.cpp:86;ang_sensor.cpp:39;health.cpp:104;initial.cpp:218
TaskScheduler scheduler 短临界区已保护,接受仍成立main.cpp:68-72 关中断取快照并清位;taskFlags volatile(initial.h:75);两写入方同抢占级
CAN RX/TX 队列临界区与 PRIMASK 恢复已保护,接受基本成立,但有遗漏Can.cpp:644-731、480;遗漏:主循环 CANFD_AsyncSend 直接写邮箱与 TX ISR 竞争(Can.cpp:1395/744,见M21)
ADC injected 电流缓存不加临界区保留现状风险仍在ADC.cpp:62-63、467-481 存在三相撕裂/丢 ready(M33);建议序号双读而非 PRIMASK
“加 PRIMASK 后实机连续重启”归因于时序归因时序归因不成立10 周期级临界区不足以致复位;更可能是 update_current 提前返回分支(ADC.cpp:468)未恢复中断 + 与 systick 改动捆绑未隔离 + 50 ms 看门狗(IRC40K)余量小;无复位原因记录无法定位
systick DWT CPU 占用统计允许小误差仍成立systick.cpp:75-79、193-206;仅诊断值
ang_sensor SPI DMA 完成标志接受 volatile 标志已过时已改为寄存器轮询 spi_rw_half_word_polling(ang_sensor.cpp:57-82),标志不存在;新问题:TRANS 等待无超时(:78)
Timer total_us100_counter仅 ISR 使用,接受仍成立Timer.cpp:19、149-153;可改为 ISR 内 static
health voltage_state / last_vbus_slow模块私有,接受仍成立(有残留)health.cpp:112-113 文件内 static;last_vbus_slow 只写不读
SUP-CMP-001 normalizeAngle360 浮点比较无需容差比较结论成立,但有新缺陷ang_sensor.h:103-111 输入 Inf/NaN 时死循环(M16)
printf:FOC 齿槽校准打印位于 FOC_DEBUG正式版不编译已过时9fbd9c3 已移除齿槽补偿;FOC_DEBUG 仅剩 motor.cpp:245 一处
versionToString 去 snprintf已改仍成立initial.cpp:302-346
AUTO-MET-001 calibrate_cogging_tick 拆分已拆分已过时函数随齿槽功能删除;Can.cpp:1186 bit4 改为保留位
AUTO-MET-001 communication_check 拆分已拆分已落实Can.cpp:841-1115
AUTO-MET-001 do_task 拆分已拆分已落实tasks.cpp:296-399
“实编仍需在 Keil/CMSIS/cbuild 环境验证”待验证仍未验证本次评审为静态评审,未实编;cproject -O3 覆盖 build-types(M38)需一并处理
+ +

5. 亮点

+
+ +

6. 优先级修复路线图

    +
  1. P0(上电机前必须修,1–2 天):M01 控制帧输入校验与 PID 限幅取正;M02/M10 EEPROM 重建重写校准角并修正 system_config_saved;M03 通信超时禁止;M06 HardFault 先关 PWM;M07 motReset 交给闸门;M16 NaN/Inf 过滤。
  2. +
  3. P1(一周内):M04 零位校准非阻塞化、delay 不喂狗;M05 过压保护;M08 运行中禁止 Flash 擦写;M09 广播改 ID 防护;M12 故障解除需重新使能;M17 编码器故障禁止;M19 深睡眠位优先级 bug。
  4. +
  5. P2(迭代内):M13/M14/M15 由 ADC 中断驱动 FOC、影子寄存器、丢拍计数;M11 EEPROM 双页原子化;M33 电流序号双读;Bus-Off/错误中断;看门狗前移与复位原因上报;补软件过流/堵转。
  6. +
  7. P3(持续改进):构建选项清理(-O3、诊断抑制)、厂商库还原、README/协议文档/CI/主机单元测试、死代码清理、Id 闭环。
+ +

7. 总结评分

+
维度评分说明
功能安全与故障保护5.0 / 10有统一运行禁止闸门与上电默认禁止,但缺通信超时/过压/过流/编码器故障禁止,故障后自动恢复
电机控制算法6.5 / 10变换与离散化正确;限幅符号、NaN、windup、采样窗口问题
实时性与中断6.0 / 10执行模型清晰、临界区合理;节拍与 PWM 不同步、无丢拍检测、异常不关 PWM
CAN 通信协议5.5 / 10DLC 合法化、ACK 回写较好;输入校验、Bus-Off、广播防护不足
参数存储/Flash4.5 / 10节点 ID 存储设计好;EEPROM 重建丢校准角、无原子性、标志位逻辑缺陷
代码质量与可维护性6.5 / 10注释充分(Doxygen)、函数已拆分;头文件/死代码/魔数
构建与仓库卫生5.0 / 10csolution 规范;-O3 覆盖、诊断抑制、厂商库改动、无 README/CI
综合5.6 / 10架构方向正确、近期在安全闸门上投入明显;但输入校验、通信超时、参数存储一致性三处缺陷可直接导致失控,修完 P0 前不建议无人值守或带负载运行。
+

本报告由专家评审生成,仅新增 docs/ 文件,未改动任何源码。

+
\ No newline at end of file diff --git a/docs/review/STATIC_ANALYSIS_NOTES_复核_2026-10-19.md b/docs/review/STATIC_ANALYSIS_NOTES_复核_2026-10-19.md new file mode 100644 index 0000000..0d77d82 --- /dev/null +++ b/docs/review/STATIC_ANALYSIS_NOTES_复核_2026-10-19.md @@ -0,0 +1,34 @@ +# STATIC_ANALYSIS_NOTES 复核修订版(2026-10-19) + +> 原文件:仓库根目录 `STATIC_ANALYSIS_NOTES.md`(最后修改于 7c4aaa5,2026-09-01),本次保留未改。 +> 复核基线:master `86ca766`(2026-10-13)。完整评审见 [Motor_v2_专家评审_2026-10-19.html](Motor_v2_专家评审_2026-10-19.html)。 + +| 条目 | 原结论 | 当前状态 | 证据 / 说明 | +|---|---|---|---| +| SUP-GLB-001 编译期常量(ADC/health/config constexpr) | 误报/偏离 | **仍成立** | ADC.cpp:22-47;health.cpp:107;config.h 全部为 constexpr | +| 硬件单例 FOC / sampler / CAN0_transmiter / KTH7823 / thermalController / Version | 接受单例 | **仍成立** | FOC.cpp:28;ADC.cpp:60;Can.cpp:86;ang_sensor.cpp:39;health.cpp:104;initial.cpp:218 | +| TaskScheduler scheduler 短临界区 | 已保护,接受 | **仍成立** | main.cpp:68-72 关中断取快照并清位;taskFlags volatile(initial.h:75);两写入方同抢占级 | +| CAN RX/TX 队列临界区与 PRIMASK 恢复 | 已保护,接受 | **基本成立,但有遗漏** | Can.cpp:644-731、480;遗漏:主循环 CANFD_AsyncSend 直接写邮箱与 TX ISR 竞争(Can.cpp:1395/744,见M21) | +| ADC injected 电流缓存不加临界区 | 保留现状 | **风险仍在** | ADC.cpp:62-63、467-481 存在三相撕裂/丢 ready(M33);建议序号双读而非 PRIMASK | +| “加 PRIMASK 后实机连续重启”归因于时序 | 归因时序 | **归因不成立** | 10 周期级临界区不足以致复位;更可能是 update_current 提前返回分支(ADC.cpp:468)未恢复中断 + 与 systick 改动捆绑未隔离 + 50 ms 看门狗(IRC40K)余量小;无复位原因记录无法定位 | +| systick DWT CPU 占用统计 | 允许小误差 | **仍成立** | systick.cpp:75-79、193-206;仅诊断值 | +| ang_sensor SPI DMA 完成标志 | 接受 volatile 标志 | **已过时** | 已改为寄存器轮询 spi_rw_half_word_polling(ang_sensor.cpp:57-82),标志不存在;新问题:TRANS 等待无超时(:78) | +| Timer total_us100_counter | 仅 ISR 使用,接受 | **仍成立** | Timer.cpp:19、149-153;可改为 ISR 内 static | +| health voltage_state / last_vbus_slow | 模块私有,接受 | **仍成立(有残留)** | health.cpp:112-113 文件内 static;last_vbus_slow 只写不读 | +| SUP-CMP-001 normalizeAngle360 浮点比较 | 无需容差 | **比较结论成立,但有新缺陷** | ang_sensor.h:103-111 输入 Inf/NaN 时死循环(M16) | +| printf:FOC 齿槽校准打印位于 FOC_DEBUG | 正式版不编译 | **已过时** | 9fbd9c3 已移除齿槽补偿;FOC_DEBUG 仅剩 motor.cpp:245 一处 | +| versionToString 去 snprintf | 已改 | **仍成立** | initial.cpp:302-346 | +| AUTO-MET-001 calibrate_cogging_tick 拆分 | 已拆分 | **已过时** | 函数随齿槽功能删除;Can.cpp:1186 bit4 改为保留位 | +| AUTO-MET-001 communication_check 拆分 | 已拆分 | **已落实** | Can.cpp:841-1115 | +| AUTO-MET-001 do_task 拆分 | 已拆分 | **已落实** | tasks.cpp:296-399 | +| “实编仍需在 Keil/CMSIS/cbuild 环境验证” | 待验证 | **仍未验证** | 本次评审为静态评审,未实编;cproject -O3 覆盖 build-types(M38)需一并处理 | + +## 需要写回原记录的修订要点 + +1. 删除/标注过时:齿槽校准相关两条(FOC_DEBUG 打印、calibrate_cogging_tick 拆分),9fbd9c3 已移除齿槽补偿。 +2. ang_sensor 已改为寄存器轮询,“SPI DMA 完成标志”条目应替换为“轮询超时”条目,并补 TRANS 等待超时。 +3. ADC 电流缓存:保留“不加长临界区”的原则,但撕裂风险真实存在,建议改用序号双读;“加 PRIMASK 导致重启”的归因应改为“未定位”,并在启动时记录复位原因后在独立分支复现。 +4. CAN 队列:补充“主循环 CANFD_AsyncSend 直接写邮箱与 TX ISR 竞争”的偏离说明或修复。 +5. normalizeAngle360:比较结论成立,但需补充非有限输入保护。 +6. health:`last_vbus_slow` 只写不读,可删除。 +7. 实编验证仍未完成;同时修正 cproject 中强制 -O3 覆盖 build-types 的问题。