cbb d8b3c9767c feat(ota): 电机 OTA 支持 EtherCAT 模式(CoE 邮箱进料 + 通道独占锁)
进料口从「只有 ESP32 SPI 一条」扩成两条,中继引擎不变:主站经 CoE 0x2511 数据窗
把电机固件明文灌进 GD32 的 48KB SRAM 暂存区,再由 comm/ecat_motor_ota 泵进原有
4KB 环缓;AES 握手、CAN 单发停等、重发、0AAC 运行确认全部沿用 MotorOtaRelay。
纯网线(ESP32 WiFi 关断、/motor/ota 打不通)场合因此也能刷电机。
偏移/幂等判据仍只有一份:feedData 拆出 feedAt,两个进料口共用。

同时把审计报告 VULN-12/13/14 落地(此前只存在于文档,一行未实现):start() 第一条
语句在 PRIMASK 内原子置位 s_channel_lock_mask,EtherCAT 桥接 sendBatch/processOutput
与 SPI 0xC0/0xC7 对锁定通道回新码 0xE7=「被电机 OTA 独占」,不冒充「邮箱满」0xE4。
反向互斥一并补上:电机 OTA 活跃时 requestEnterBoot() 直接拒绝——SPI 0xB0、CoE 0x2502、
CAN 0x320 三条交接入口共用这一个判据,避免复位把刷写腰斩在 erase 之后。

完整性口径按链路分开,不互相冒充:块级 CRC32 + 整镜像 CRC32 都在从站核,且核过才
让电机进 BOOT——失败时电机仍跑旧 APP、擦除没开始,不存在「先擦再验」的变砖路径。
CRC 为 CRC-32/B(poly 0x04C11DB7,初值 0xFFFFFFFF,无反射无末尾异或),与 v2_crc32
同算法(用公开向量 123456789=0x0376E6E7 对过)。

块长取 1024 而不是 BOOT 用的 4096:SSC 的分段下载缓冲是全工程唯一的 malloc 用户,
而 APP 的 __HEAP_SIZE 只有 3KB,4096 会被从站当场回 abort 0x05040005 Out of memory
(BOOT 的堆是 16KB 才撑得住 4096——块长能抄,堆抄不了)。这是跨仓常量,须与
tools/ecat 的 MFO_CHUNK_OBJ 同步。

APP 1.7.4(RAM ZI 97156)。已实测:0x2510 参数写与一块 1016B 数据写均被从站接受
(staged=1016、phase bit4);端到端电机刷写待复测(native 块长修复后未跑完整一轮)。
2026-10-11 02:47:19 +08:00
2026-07-15 02:49:37 +08:00
2026-07-15 02:49:37 +08:00

GD32E508_DCU_APP README

本 README 用来介绍 /workzone/ROBOT_V2/DCU/DCU_APP/GD32E508_DCU_APP 目录下各个代码文件的作用、分层关系和阅读顺序。


1. 项目概览

这是一个基于 GD32E508 的 DCU 应用工程,当前代码已经整理为:

  • 应用入口层:main.cpp / main.h
  • 系统层(sys):负责初始化、节拍、任务调度、任务执行
  • 设备层(device):负责 ADC、CANFD、Timer、串口、温度采样封装,以及 SPI 命令总线与命令处理器拆分
  • RTE / Device 层:芯片启动文件、链接脚本、厂商外设驱动

当前整体执行逻辑是:

  1. main.cpp 调用 app_init() 完成硬件初始化
  2. task_runner_init() 初始化任务运行时数据
  3. Timer 周期中断驱动 task_manager 置位任务标志
  4. 主循环中 task_runner_run_pending() 读取并执行任务
  5. ADC / CANFD / temp_sensor / usart0 等模块提供具体功能

2. 推荐阅读顺序

如果第一次接手这个工程,建议按这个顺序看:

  1. main.cpp
  2. main.h
  3. sys/initial.*
  4. sys/task_manager.*
  5. sys/task_runner.*
  6. device/Timer.*
  7. device/ADC.*
  8. device/temp_sensor.*
  9. device/CANFD.*
  10. device/usart0.*
  11. sys/systick.*
  12. RTE/Device/GD32E508VE/*

这样能先看清主流程,再逐层下钻。


3. 应用层代码文件说明

3.1 根目录文件

main.cpp

作用:

  • 应用主入口
  • 调用系统初始化
  • 启动任务运行时
  • 进入主循环执行待处理任务

当前职责很轻:

  • 不直接处理 ADC
  • 不直接处理 CANFD
  • 不直接实现业务任务逻辑

这是当前工程的“总入口 + 调度外壳”。


main.h

作用:

  • 全局基础头文件
  • 引入 RTE_Components.h 和芯片头文件
  • 定义系统任务枚举 system_task_t
  • 定义调度器状态结构 task_scheduler_t
  • 声明全局调度器实例 g_scheduler

这里的核心内容:

  • 任务类型定义
  • 调度节拍状态定义

可以把它理解为“任务系统公共协议头”。


4. 系统层 sys/ 文件说明

sys/initial.h

作用:

  • 声明应用初始化函数 app_init()

这是初始化入口的头文件。


sys/initial.cpp

作用:

  • 实现 app_init()
  • 负责按顺序初始化各基础模块

当前初始化内容包括:

  • SysTick
  • USART0 GPIO
  • USART0 串口
  • 温度采样模块
  • CANFD 模块
  • 任务调度器
  • 用户定时器

这是系统启动时的“初始化编排器”。


sys/systick.h

作用:

  • 声明系统毫秒节拍相关接口

当前提供:

  • systick_config_ms()
  • delay_ms()

sys/systick.cpp

作用:

  • 实现 SysTick 中断处理
  • 维护毫秒计数器
  • 提供毫秒级阻塞延时

当前功能:

  • SysTick_Handler():系统滴答中断
  • delay_ms():基于滴答计数的阻塞延时
  • systick_config_ms():配置 1ms 节拍

这是系统时间基准模块。


sys/task_manager.h

作用:

  • 声明任务调度器接口

当前提供:

  • task_manager_init()
  • task_manager_tick_100us()
  • task_manager_take_pending()
  • task_manager_set()

sys/task_manager.cpp

作用:

  • 维护全局任务标志位和节拍计数
  • 根据 100us 节拍分发不同周期任务

当前任务节拍划分:

  • 500us:采样 VREF 原始值
  • 1ms:采样温度原始值 + 计算工程值
  • CAN RX 中断:置位接收解析任务,主循环按预算尽快消费
  • 10ms:保留系统 10ms 节拍计数
  • 100ms:CAN 发送准备 + CAN 发送 + 状态灯任务
  • 1s:心跳任务 + 诊断打印任务

这是“什么时候执行任务”的核心模块。


sys/task_runner.h

作用:

  • 声明任务执行器接口

当前提供:

  • task_runner_init()
  • task_runner_run_pending()

sys/task_runner.cpp

作用:

  • 真正执行任务逻辑
  • 保存应用运行时缓存
  • 将任务位映射到具体函数

当前内部任务包括:

  • ADC 原始采样任务
  • ADC 工程值计算任务
  • CAN RX 轮询任务
  • CAN RX 解析任务
  • CAN TX 准备任务
  • CAN TX 发送任务
  • 状态灯任务(占位)
  • 心跳任务(占位)
  • 诊断打印任务

当前内部运行时缓存:

  • 最近一次温度采样结果
  • 最近一次 VREF 原始值
  • 最近一次温度原始值
  • 最近一次接收 CAN 帧 ID / 长度 / 数据

这是“执行什么任务”的核心模块。


5. 设备层 device/ 文件说明

SPI 命令总线拆分说明

  • device/spi_command_handler.h:SPI 命令处理器抽象与上下文结构。
  • device/app_spi_command_defs.h:APP 运行期 SPI 协议公共常量。
  • device/app_spi_command.cpp:当前仅负责 SPI 链路和命令路由。
  • device/app_spi_cmd_boot_request.cpp:进入 Bootloader 的 SPI 命令处理器。
  • device/app_spi_cmd_ota_wait.cpp:OTA 相关命令的 WAIT 响应处理器。
  • device/app_spi_cmd_ping.cpp:APP Ping 命令处理器。
  • device/app_spi_cmd_can_bridge.cpp:SPI→CAN 桥接命令处理器。
  • 新增 SPI 业务时优先新增 device/app_spi_cmd_*.cpp,而不是继续膨胀 app_spi_command.cpp。

device/adc.h

作用:

  • 定义 ADC 采样结果结构 adc_sample_t
  • 声明 ADC 硬件初始化、采样、换算接口

主要接口:

  • adc_hw_init()
  • adc_single_read()
  • adc_read_vref_raw()
  • adc_read_temp_raw()
  • adc_calculate_vdda()
  • adc_calculate_temperature()
  • adc_collect_sample()

device/ADC.cpp

作用:

  • 实现内部温度/VREF 的 ADC 采样流程
  • 提供原始值读取与工程值换算

当前能力:

  • 初始化 ADC0
  • 读取内部参考电压
  • 读取内部温度通道
  • 根据参考电压估算 VDDA
  • 根据内部温度特性曲线估算温度
  • 输出完整采样结构

这是 ADC 采样核心模块。


device/temp_sensor.h

作用:

  • 对温度采样模块做轻量封装
  • 将 adc_sample_t 别名为 temp_sensor_data_t

主要接口:

  • temp_sensor_init()
  • temp_sensor_sample()

device/temp_sensor.cpp

作用:

  • 基于 ADC 模块提供温度采样初始化和采样包装

本质上:

  • temp_sensor_init() → 调用 adc_hw_init()
  • temp_sensor_sample() → 调用 adc_collect_sample()

这是一个轻量适配层,让上层按“温度传感器模块”来理解,而不直接依赖 ADC 细节。


device/usart0.h

作用:

  • 声明 USART0 串口相关接口

当前提供:

  • usart0_gpio_config()
  • usart0_config()
  • fputc()

device/usart0.cpp

作用:

  • 配置 USART0 的 GPIO 和串口参数
  • 重定向 printf 到 USART0

主要用途:

  • 启动信息输出
  • 运行时诊断打印

这是当前工程的串口调试输出模块。


device/Timer.h

作用:

  • 声明用户任务定时器初始化接口

当前提供:

  • user_timer_init()

device/Timer.cpp

作用:

  • 配置 TIMER2
  • 配置 TIMER2 中断
  • 在中断里驱动任务系统节拍

当前逻辑:

  • user_timer_init() 完成 TIMER2 配置与 NVIC 配置
  • TIMER2_IRQHandler() 在每次更新中断中调用 task_manager_tick_100us()

这是任务节拍的硬件入口模块。


device/canfd.h

作用:

  • 定义 CANFD 模块对外接口
  • 定义诊断结构 CanFd::Diag
  • 定义状态发送载荷结构 canfd_status_payload_t

主要接口:

  • canfd_init()
  • canfd_poll()
  • canfd_prepare_status()
  • canfd_send_prepared()
  • canfd_has_rx_frame()
  • canfd_consume_rx_frame()
  • canfd_get_diag()

device/canfd.cpp

作用:

  • 初始化 CANFD 工作模式
  • RX0 中断批量搬空硬件 FIFO0
  • 按通道缓存接收帧
  • 构建状态发送帧
  • 发送准备好的 FD 帧
  • 维护 CANFD 诊断统计信息

内部拆分特点:

  • RX 和 TX 已拆成两段式
  • 接收侧:rx interrupt -> queue -> consume
  • 发送侧:prepare -> send

当前内部缓存:

  • s_rxQueues:三路接收环形缓冲
  • s_txQueues:三路待发送环形缓冲
  • g_can_diag:收发与错误统计

这是当前最重要的通信模块之一。


6. RTE / Device 层文件说明

下面这些文件主要属于:

  • 芯片启动代码
  • 链接脚本
  • 厂商标准外设驱动
  • 自动生成的运行环境文件

原则:

  • 这些文件通常不是业务逻辑主战场
  • 不建议随意直接修改
  • 如果一定要改,最好确认是可持续维护的变更

RTE/_Debug_GD32E508VE/RTE_Components.h

作用:

  • 自动生成的组件配置头文件
  • 指定当前工程启用哪些外设组件
  • 定义 CMSIS_device_header

这是编译入口层配置文件之一。


RTE/Device/GD32E508VE/startup_gd32e50x_cl.s

作用:

  • 启动汇编文件
  • 定义中断向量表
  • 复位入口
  • 弱符号中断处理默认实现

这是 MCU 上电启动时最底层的入口。


RTE/Device/GD32E508VE/system_gd32e50x.c

作用:

  • 系统时钟配置与系统变量维护
  • 提供 SystemCoreClock 相关支持

这是 CMSIS 系统层实现文件。


RTE/Device/GD32E508VE/ac6_linker_script.sct.src

作用:

  • AC6 工具链链接脚本模板
  • 控制代码段、数据段、栈、堆等布局

RTE/Device/GD32E508VE/regions_GD32E508VE.h

作用:

  • 链接内存区域定义头文件
  • 配合链接脚本使用

7. 厂商外设驱动源文件

以下文件属于厂商标准外设驱动,主要为 gd32e50x_xxx.c:

gd32e50x_adc.c

作用: ADC 外设驱动实现。

gd32e50x_can.c

作用: CAN / CANFD 相关底层驱动实现。 说明: 当前项目的 CANFD 能力依赖这个文件中的 GD32E508 分支实现。

gd32e50x_crc.c

作用: CRC 外设驱动实现。

gd32e50x_dbg.c

作用: 调试控制相关外设驱动实现。

gd32e50x_dma.c

作用: DMA 外设驱动实现。

gd32e50x_exti.c

作用: 外部中断控制驱动实现。

gd32e50x_fmc.c

作用: Flash / FMC 相关驱动实现。

gd32e50x_gpio.c

作用: GPIO 外设驱动实现。

gd32e50x_misc.c

作用: 中断优先级 / 杂项系统控制驱动实现。

gd32e50x_pmu.c

作用: 电源管理单元驱动实现。

gd32e50x_rcu.c

作用: 时钟控制单元驱动实现。

gd32e50x_spi.c

作用: SPI 外设驱动实现。

gd32e50x_usart.c

作用: USART 外设驱动实现。


8. .base@版本号 文件说明

例如:

  • gd32e50x_can.c.base@1.0.0
  • gd32e50x_adc.c.base@1.5.0
  • startup_gd32e50x_cl.s.base@1.5.0

这些文件通常表示:

  • 原始基线版本
  • 或工具生成时附带的参考副本

建议:

  • 默认不要动
  • 真要比对升级差异时再看

9. 当前应用层模块关系图(逻辑上)

main.cpp
  ├─ sys/initial.cpp
  │    ├─ sys/systick.cpp
  │    ├─ device/usart0.cpp
  │    ├─ device/temp_sensor.cpp
  │    │    └─ device/ADC.cpp
  │    ├─ device/canfd.cpp
  │    ├─ sys/task_manager.cpp
  │    └─ device/Timer.cpp
  │         └─ TIMER2_IRQHandler -> task_manager_tick_100us()
  │
  └─ sys/task_runner.cpp
       ├─ device/ADC.cpp
       ├─ device/canfd.cpp
       └─ sys/task_manager.cpp

10. 当前代码特点总结

已完成的结构化工作

  • 应用层 .c 已整理为 .cpp
  • main 已瘦身
  • 任务管理与任务执行已分离
  • CANFD 收发流程已拆成两段式
  • CANFD 接收已切换为中断事件驱动和环形缓冲
  • ADC / 温度 / 定时器 / 串口 已模块化

当前仍可继续演进的方向

  • 将 task_runner.cpp 再拆成 task_adc.cpp / task_can.cpp / task_diag.cpp
  • 将协议帧定义抽到单独文件中
  • 完善状态灯任务与心跳任务

11. 维护建议

建议优先修改的位置

如果是改业务逻辑,优先看:

  • sys/task_runner.cpp
  • device/canfd.cpp
  • device/ADC.cpp
  • sys/task_manager.cpp

不建议随便改的位置

除非你明确知道在干什么,否则不要轻易改:

  • RTE/Device/GD32E508VE/startup_gd32e50x_cl.s
  • RTE/Device/GD32E508VE/system_gd32e50x.c
  • RTE/Device/GD32E508VE/gd32e50x_*.c
  • 链接脚本相关文件

12. 后续建议

如果准备继续把这个项目做成更长期可维护的结构,下一步最值的动作是:

  1. 增加 protocol/ 或 frames/ 目录,专门放 CANFD 帧定义
  2. 将 task_runner.cpp 按任务领域继续拆文件
  3. 给应用层全部源码统一补齐函数级注释和参数说明
  4. 根据目标总线速率进一步细化 CANFD nominal/data timing 参数

如果后面代码结构继续变化,记得同步更新本 README,避免它变成过期文档。

S
Description
No description provided
Readme
2.2 MiB
Languages
C 60.5%
C++ 37.4%
Assembly 1.2%
Python 0.9%