Files
DCU_APP/README.md
T

551 lines
13 KiB
Markdown
Raw Normal View History

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 模块对外接口
2026-07-15 02:49:37 +08:00
- 定义诊断结构 `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()`
---
2026-07-15 02:49:37 +08:00
### `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
2026-07-15 02:49:37 +08:00
│ ├─ device/canfd.cpp
│ ├─ sys/task_manager.cpp
│ └─ device/Timer.cpp
│ └─ TIMER2_IRQHandler -> task_manager_tick_100us()
│
└─ sys/task_runner.cpp
├─ device/ADC.cpp
2026-07-15 02:49:37 +08:00
├─ 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`
2026-07-15 02:49:37 +08:00
- `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,避免它变成过期文档。