# 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. 当前应用层模块关系图(逻辑上) ```text 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,避免它变成过期文档。