Motor_v2 电机固件专家评审
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、motor | CAN-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. 评审范围与方法
- 范围:Robot_V2/ 下全部应用源码(Algorithm、device、sys、main、tasks,约 9.6k 行)、RTE 启动文件/时钟/链接区域/中断文件、csolution/cproject/cbuild-pack/vcpkg、.gitignore、IDE 配置;厂商标准库仅比对与 .base 的差异。
- 专家组:①电机控制算法/FOC ②实时性/中断/DMA/MCU 架构 ③CAN-FD 通信协议 ④功能安全与故障保护 + Flash 存储 ⑤代码质量、构建与仓库卫生。各视角独立通读后交叉核对,关键结论由主评审逐行复核(M01、M02、M04、M07、M10、M19 等)。
- 既有记录:全仓搜索 .md/.html,仅根目录
STATIC_ANALYSIS_NOTES.md。逐条核对见第 4 节,修订版见 STATIC_ANALYSIS_NOTES_复核_2026-10-19.md(原文件保留未改)。 - 严重度:致命=可能导致失控/烧毁/伤人;严重=保护失效、控制失效或数据丢失;一般=功能缺陷/可靠性隐患;建议=质量与可维护性。
- 局限:未编译、未上机、未示波;行号基于 86ca766。
3. 问题清单(50 条)
| 编号 | 严重度 | 领域 | 文件:行号 | 标题 / 现象 | 风险 | 修改建议 |
|---|---|---|---|---|---|---|
| M01 | 致命 | CAN/FOC | device/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-84 | EEPROM 页满重建时丢失电角度零位校准角 任一写入触发页满 → 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 | 严重 | 安全/FOC | Algorithm/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-45 | motReset 直接唤醒驱动,绕过运行禁止闸门的睡眠状态 RESET bit0 先 release(NFAULT) 再 motor_reset()(sleep→resume)。若其他禁止位仍在,闸门 stopped 已为 true,不会再次 motor_sleep(),驱动保持唤醒。 | 欠压/过热/未使能期间驱动被唤醒(PWM 虽被置 0,但违背单一执行者设计,DRV8313 故障锁存也被清除)。 | motReset 仅 release(NFAULT),驱动睡眠/唤醒全部交给 RunInhibit::update();或在闸门中把 stopped 置 false 强制重新施加睡眠。 |
| M08 | 严重 | CAN/Flash | device/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 | 严重 | CAN | device/Can.cpp:950,967-981 | 旧格式 SET_NODE_ID 未拦截广播 DLC 1/2 的旧格式允许 target_node==BROADCAST;扩展格式(约 1010 行)已拦截,旧格式没有。 | 一条广播帧可把总线上所有节点改为同一 ID,造成 ID 冲突、命令错发至多个电机。 | 旧格式同样拒绝广播目标,并要求魔数/二次确认;考虑废弃旧格式。 |
| M10 | 严重 | Flash | sys/flash.cpp:444,906;sys/health.cpp:195 | 一次欠压保存后本次上电所有存参被跳过 欠压路径 save_system_config(true) 将 system_config_saved 置 true 且永不清零,此后 444 行直接返回 OK。 | 欠压恢复后的参数修改、进 BOOT 前保存、format 后的重建全部被静默跳过 → 与问题 2 叠加,页满时整页参数丢失。 | save 标志只用于“本次欠压已保存”,在欠压解除时清零;format 重建路径应强制保存(忽略该标志)。 |
| M11 | 严重 | Flash | sys/flash.cpp:413-430,161-181;main.cpp:107 | EEPROM 无掉电原子性,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-342 | PWM 比较值写入未开影子寄存器预装载 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 | 严重 | FOC | Algorithm/pid.cpp:64-68;device/ang_sensor.h:103-111;Algorithm/FOC.cpp:509-510 | NaN/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 | 一般 | CAN | device/Can.cpp:1117 | 控制帧不校验长度与模式范围 短帧缺失字段按 0 处理(P 增益等被清零);P_config、control_mode 无范围检查,tasks.cpp:113 对非法模式仅不执行。 | 错误/截断帧改变控制参数,行为不可预期。 | 按命令定义校验 DLC 与字段范围,不合法回 NACK 且不修改任何状态。 |
| M19 | 一般 | CAN | device/Can.cpp:1187 | RESET 深睡眠位判断运算符优先级错误 `eigth_byte & 0x80 >> 7` 等价于 `eigth_byte & 1`,实际判断 bit0 而非 bit7。 | 上位机置 bit0 时意外进入深睡眠,bit7 反而无效。 | 改为 `(eigth_byte >> 7) & 0x01` 或 `eigth_byte & 0x80`。 |
| M20 | 一般 | CAN/FOC | device/Can.cpp:1177-1181 | 运行中可清零角度 RESET bit3 不检查状态即 angle_set(0) 并重置卡尔曼。 | 位置模式下目标与实际角度瞬间跳变,电机猛冲。 | 仅在 mode0/禁止状态下允许,或同时把 target_angle 置为新零点。 |
| M21 | 一般 | CAN | device/Can.cpp:1395,744 | TX 路径主循环与 ISR 竞争邮箱、乱序 CANFD_AsyncSend 在主循环直接 can_message_transmit,同时 TX 中断从队列填邮箱。 | 选邮箱竞态、新帧绕过队列先发,反馈帧时序错乱。 | 统一经 TX 队列发送,仅在临界区内检测空邮箱并启动。 |
| M22 | 一般 | CAN | device/Can.cpp:896-924 | BOOT 帧无魔数/校验 任何基础 ID 0x0000 的帧都可触发进 BOOT 或节点静默。 | 误触发导致电机离线。 | 增加魔数 + 目标节点 + 停机状态校验。 |
| M23 | 一般 | CAN | device/Can.cpp:575,630 | 远程帧未过滤 rx_ft 读出后未判断,远程帧被当作数据帧处理。 | DLC 非 0 的远程帧携带随机数据进入命令解析。 | 丢弃 RTR 帧或单独处理。 |
| M24 | 一般 | CAN | device/Can.cpp:359,413,1241-1251 | 总线错误/Bus-Off 不可见,FIFO 溢出分支不可达 未开错误中断,Bus-Off 不上报也不纳入保护;只开 RFNE,FIFO 满/溢出处理永远进不去。 | 总线故障时静默失联(与无通信超时叠加)。 | 开启 EWIE/BOIE/ERRNIE,记录 TEC/REC,Bus-Off 时请求禁止并按策略恢复。 |
| M25 | 一般 | CAN | device/Can.cpp:394-407;sys/config.h:341 | 硬件过滤器全收,默认 STATUS 1 kHz×48 B 所有帧靠软件过滤。 | 多节点组网时总线与中断负载偏高。 | 按节点 ID 配置硬件过滤器;默认刷新率下调。 |
| M26 | 一般 | CAN/Flash | device/Can.cpp:1034 | 反馈刷新周期无下限且每次设置都写 Flash 可配置为极小周期;频繁设置磨损 Flash。 | 总线饱和、Flash 寿命下降。 | 设定下限(如 1 ms);值未变不写(write 已跳过同值,但应在命令层限频)。 |
| M27 | 一般 | Flash | sys/flash.cpp:230-257 | readFloat 无保留字节防护,可能误读 CRC 字 read() 在 206 行用保留字节排除 CRC 字,readFloat 没有同类防护,扫描至头部 CRC 区。 | 记录不存在时可能把低字节为 0x07 的 CRC 字当作校准角返回,calib==0 判定拦不住。 | float 记录格式加入类型标记/校验位,或扫描时跳过 CRC 区。 |
| M28 | 一般 | Flash/BOOT | sys/flash.cpp:929-1016,1077-1098 | OTA 标志与备份区搬运缺乏原子性 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 | 一般 | FOC | Algorithm/FOC.h:47;Algorithm/FOC.cpp:429,413;device/Timer.cpp:329-342 | v_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 | 一般 | FOC | Algorithm/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 | 一般 | FOC | device/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.json | IDE 配置入库 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 | 建议 | FOC | Algorithm/FOC.cpp(Ud 恒 0);Algorithm/Filter.cpp(CurrentKalman Q=10,R=5e-5) | Id 未闭环;电流卡尔曼增益≈1 等于不滤波 Ud 恒为 0;Kalman 参数使滤波失效。 | 高速/弱磁场景能力受限;无效计算消耗 CPU。 | 增加 Id 电流环(目标 0);重新整定或移除该滤波器。 |
| M47 | 建议 | FOC | Algorithm/FOC.cpp(SVPWM) | SVPWM 量纲约定未注明 Uq 量纲为相幅值的 √3 倍(数值验证扇区与角度误差约 1e-13,变换正确)。 | 参数整定易误解。 | 在注释中写明电压归一化约定。 |
| M48 | 建议 | CAN | device/Can.cpp:366-390 | CAN-FD 位时序裕量待确认 数据段 5 Mbps 仅 6 tq、SJW=1,TDCO=4 单位需对照手册。 | 长线/多节点时误码。 | 按手册核算采样点(70–80%),示波验证 TDC。 |
| M49 | 建议 | 实时性 | system_gd32c10x.c:857 | 未开启时钟监控 CKM 晶振起振失败卡在 while(1)。 | 板级故障时无安全输出。 | 开启 CKM,NMI 中安全停机。 |
| M50 | 建议 | CAN | device/Can.cpp:331,1292;Can.h:226-228 | CAN 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. 亮点
RunInhibit位图闸门:功率级动作收拢为单一执行者,上电默认 INHIBIT_NOT_ENABLED,闸门位于模式分发之前,非法模式也能封住输出。- 节点 ID 双页乒乓 + 魔数 + 计数器 + CRC,写后校验重试,写成功才回 ACK。
- ADC0 只跑注入组、VBUS/温度移到 ADC1 连续模式,消除规则/注入组互扰;电流零点配平带独立错误位上报。
- Clarke/Park/逆 Park 与 SVPWM 数值正确;PID Tustin 积分 + 测量值微分低通 + 条件积分抗饱和设计合理。
- CAN DLC 合法化(CANFD_NormalizeLength)、DWT 按任务统计负载、Doxygen 注释完整。
6. 优先级修复路线图
- P0(上电机前必须修,1–2 天):M01 控制帧输入校验与 PID 限幅取正;M02/M10 EEPROM 重建重写校准角并修正 system_config_saved;M03 通信超时禁止;M06 HardFault 先关 PWM;M07 motReset 交给闸门;M16 NaN/Inf 过滤。
- P1(一周内):M04 零位校准非阻塞化、delay 不喂狗;M05 过压保护;M08 运行中禁止 Flash 擦写;M09 广播改 ID 防护;M12 故障解除需重新使能;M17 编码器故障禁止;M19 深睡眠位优先级 bug。
- P2(迭代内):M13/M14/M15 由 ADC 中断驱动 FOC、影子寄存器、丢拍计数;M11 EEPROM 双页原子化;M33 电流序号双读;Bus-Off/错误中断;看门狗前移与复位原因上报;补软件过流/堵转。
- P3(持续改进):构建选项清理(-O3、诊断抑制)、厂商库还原、README/协议文档/CI/主机单元测试、死代码清理、Id 闭环。
7. 总结评分
| 维度 | 评分 | 说明 |
|---|---|---|
| 功能安全与故障保护 | 5.0 / 10 | 有统一运行禁止闸门与上电默认禁止,但缺通信超时/过压/过流/编码器故障禁止,故障后自动恢复 |
| 电机控制算法 | 6.5 / 10 | 变换与离散化正确;限幅符号、NaN、windup、采样窗口问题 |
| 实时性与中断 | 6.0 / 10 | 执行模型清晰、临界区合理;节拍与 PWM 不同步、无丢拍检测、异常不关 PWM |
| CAN 通信协议 | 5.5 / 10 | DLC 合法化、ACK 回写较好;输入校验、Bus-Off、广播防护不足 |
| 参数存储/Flash | 4.5 / 10 | 节点 ID 存储设计好;EEPROM 重建丢校准角、无原子性、标志位逻辑缺陷 |
| 代码质量与可维护性 | 6.5 / 10 | 注释充分(Doxygen)、函数已拆分;头文件/死代码/魔数 |
| 构建与仓库卫生 | 5.0 / 10 | csolution 规范;-O3 覆盖、诊断抑制、厂商库改动、无 README/CI |
| 综合 | 5.6 / 10 | 架构方向正确、近期在安全闸门上投入明显;但输入校验、通信超时、参数存储一致性三处缺陷可直接导致失控,修完 P0 前不建议无人值守或带负载运行。 |