test_led_strip/doc/光磁头软件架构文档.md

318 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 光磁头软件架构文档
> 本文档为光磁头(小板 / 温度传感端)固件的**设计规范**,源码实现应遵循本文档的模块划分、数据流与设计约束。
> 配套协议:[`通讯协议.md`](./通讯协议.md)
> 硬件平台STM32G0B0板级 `dr2501a_g0b0ce`
---
## 1. 系统定位
光磁头是光磁热疗系统的**温度传感端**,通过一根 UART 线与主板(控制端)通信,向主板提供 9 路皮肤温度反馈,供主板 PID 温控闭环使用。
| 职责 | 说明 |
|---|---|
| 温度采集 | 9 路 godtek 温度传感器8 路经 CH9438 扩展 + 1 路片内直连) |
| 温度上报 | 每 20ms 主动上报 9 路**最大值**(温度闭环反馈) |
| 命令响应 | 响应主板查询ID / 温度)与运行状态设置 |
| 状态指示 | 按主板运行状态点亮红外灯与灯带 |
```mermaid
flowchart LR
subgraph 光磁头[光磁头 传感端]
S[9 路 godtek 传感器] -->|UART 触发| C[采集聚合 infrared]
C -->|20ms 周期| T[温度上报 temp]
T --> P[协议 com<br/>usart1 0x7EE7]
P -->|运行状态| L[LED 指示 led]
end
P <-->|UART 115200| M[主板 控制端]
```
---
## 2. 硬件资源
| 外设 | 用途 | 关键配置 |
|---|---|---|
| `spi2` + CH9438INT# PB13 | SPI→8×UART 扩展,传感器 ch0~7 | SPI 500kHz8 口均 9600 8N1overlay `use_ms.overlay` |
| `usart2`PA2/PA3 | 片内第 9 路传感器ch8 | 9600 8N1 |
| `usart1`PA9/PA10 | 与主板通信协议口 | 115200帧头 0x7EE7 + CRC16 |
| `usart3`PA5/PB0 | 调试 console | 115200 |
| `spi1` + WS281240 灯) | 灯带指示standby/running/pause/error | SPI 4MHz |
| `led_inf`PB1 | 红外加热指示 LED | 运行中点亮 |
| `led_mcu_state`PA15 | 心跳灯 | 1s 周期闪烁 |
| IWDG | 系统看门狗 | 20ms 喂狗 |
```mermaid
graph TD
subgraph MCU[STM32G0B0]
U1[usart1 协议口<br/>115200] -->|0x7EE7 帧| MB[主板]
U2[usart2 第9路<br/>9600] --> G8[godtek ch8]
U3[usart3 console]
SP2[spi2 500kHz] --> CH[CH9438<br/>INT# PB13]
CH --> G0[godtek ch0]
CH --> G1[godtek ch1]
CH --> G7[godtek ch7]
SP1[spi1 4MHz] --> WS[WS2812 灯带 ×40]
LED1[led_inf PB1]
LED2[led_mcu_state PA15]
WDT[IWDG]
end
```
> 传感器工作模式8 路外置为 `wrist`0xAC 测量命令),片内第 9 路默认 `surface`0xAA
---
## 3. 软件架构
```mermaid
graph TD
subgraph 应用层
MAIN[main 主线程]
TEMP[temp 采集调度<br/>20ms 上报]
COM[com 协议处理<br/>回调表/上电发ID]
LED[led 状态指示]
WDG[watdog 喂狗]
end
subgraph 聚合层
IR[infrared 9路聚合<br/>触发注册/缓存/最大值]
end
subgraph 驱动层
UC[uart_com 帧协议<br/>0x7EE7+CRC16]
GD[godtek_temp 传感器驱动<br/>组帧/校验/触发]
CH8[ch9438 SPI→8×UART]
IND[led_strip_indicator 灯带]
end
TEMP --> IR
TEMP --> COM
COM --> UC
IR --> GD
GD --> CH8
GD --> U2[usart2]
LED --> COM
LED --> IND
MAIN -.后台驻留.-> TEMP
```
### 模块职责
| 模块 | 职责 | 关键约束 |
|---|---|---|
| `infrared`(聚合层) | 9 路传感器统一抽象:设备列表、触发注册、通道缓存、取最大值 | 缓存须 ISR 安全;通道编号固定 ch0~7=CH9438、ch8=片内 |
| `temp`(应用层) | 采集触发注册 + 20ms 周期上报最大值 | 触发注册必须在传感器驱动初始化之后 |
| `com`(应用层) | 协议帧收发、命令回调、运行状态信号广播 | 回调在系统 workqueue 线程执行;上电主动发 ID |
| `led`(应用层) | 运行状态 → 红外灯 + 灯带;心跳灯 | 状态变化由 com 信号驱动,不轮询 |
| `watdog`(应用层) | IWDG 喂狗 | 20ms 周期;配置失败不得阻塞启动 |
| `main`(应用层) | 入口 + 后台驻留 | 各模块由 SYS_INIT 初始化 |
---
## 4. 数据流
### 4.1 温度采集链(触发驱动,无轮询)
9 路传感器**全部由 UART 数据触发驱动**,不占用 CPU 轮询:
```mermaid
flowchart LR
S[godtek 传感器自发上报] --> CH[CH9438 INT# 中断<br/>或 usart2 RX 中断]
CH --> WQ[系统 workqueue<br/>或 ISR]
WQ --> GD[godtek 驱动<br/>组帧 + 校验]
GD -->|有效帧| TRIG[触发回调<br/>更新第 I 路缓存]
TRIG --> CACHE[volatile 通道缓存]
```
- **帧校验**`+`/`-` 符号 + 6 位十进制数字 + 温度范围(-40.0 ~ +125.0°C坏帧直接丢弃不上报
- **上下文**CH9438 端口回调在系统 workqueueSPI 安全);片内 usart2 回调在 ISR —— 回调内不得做任何阻塞操作
### 4.2 温度上报链20ms 周期)
```mermaid
flowchart LR
T[temp 周期任务<br/>20ms] --> M[取 9 路缓存最大值]
M --> C[组帧上报]
C -->|0x7EE7 帧 00 02 整数 小数 CRC| U[usart1 → 主板]
```
温度值格式×10 整数(如 `345` = 34.5°C上报数据 2 字节 `[整数][小数]`
### 4.3 命令响应链RX ISR → workqueue
```mermaid
flowchart LR
RX[usart1 RX ISR<br/>逐字节帧状态机] -->|完整帧| P[拷贝到 pending 缓冲<br/>提交 work]
P --> WQ2[系统 workqueue<br/>执行命令回调]
WQ2 --> H[ID / 温度查询 / 运行状态]
H --> LED2[运行状态 → LED 指示]
H --> R[ID / 温度查询 → 回帧]
```
> 命令回调必须在 workqueue 线程上下文执行ISR 只做轻量拷贝),可安全使用 `printk` / `uart_poll_out`,避免 ISR 内阻塞导致温度上报停止。
---
## 5. 通信协议
帧结构(详见 `通讯协议.md`
```
| 7E | E7 | CMD | LEN | DATA[0..LEN-1] | CRC_L | CRC_H |
|----- 帧头 -----| | |-- CRC16 Modbus (lsb-msb) --|
```
| 指令 | 方向 | 内容 | 响应行为 |
|---|---|---|---|
| `0x00` 温度 | 小板→主板(主动) | 每 20ms 上报最大值2 字节 `[整数][小数]` | — |
| `0x00` 温度 | 主板请求→小板回复 | 请求时回复当前最大值 | 查询回复 |
| `0x01` ID | 小板→主板(主动) | **上电主动发一次**3 字节hwinfo 前 3 字节) | — |
| `0x01` ID | 主板请求→小板回复 | 请求时回复 | 查询回复 |
| `0x02` 运行状态 | 主板→小板 | 1 字节0x00 待机 / 0x01 运行 / 0x02 暂停 / 0x03 故障 | 更新状态并驱动 LED |
```mermaid
sequenceDiagram
participant S as 小板 光磁头
participant M as 主板 控制端
Note over S: 系统上电
S->>M: 【主动】ID 帧 (0x01)
loop 每 20ms
S->>M: 【主动】温度最大值帧 (0x00)
end
Note over M: 运行状态变化
M->>S: 运行状态帧 (0x02) → LED 指示
opt 主板查询
M->>S: 请求 ID (0x01)
S-->>M: 回复 ID
M->>S: 请求温度 (0x00)
S-->>M: 回复温度最大值
end
```
---
## 6. 初始化顺序
各模块通过 SYS_INIT 按以下顺序初始化(同优先级内不得存在跨模块依赖):
| 阶段 | 优先级 | 模块 | 说明 |
|---|---|---|---|
| POST_KERNEL | 驱动默认 | ch9438 | SPI 初始化、**波特率配置9600含 FCR 时序处理)**、中断使能 |
| POST_KERNEL | 传感器默认 | godtek | UART 回调注册、500ms 周期测量命令 |
| APPLICATION | 40 | led | GPIO / 灯带初始化 + 注册状态槽 |
| APPLICATION | 45 | temp | **触发注册**(必须在 godtek 之后)+ 启动 20ms 上报 |
| APPLICATION | 50 | com | 协议回调表注册 + **上电主动发 ID** |
| APPLICATION | 60 | watdog | IWDG 安装 + 启动喂狗 |
| APPLICATION | 90 | ch9438 flush | POR 残留 FIFO 清空(边沿中断补偿) |
| — | — | main | 主循环(后台线程) |
```mermaid
sequenceDiagram
participant B as 启动
participant D as 驱动层
participant A as 应用层
B->>D: ch9438 初始化(波特率 9600 时序)
B->>D: godtek 初始化(回调 + 500ms 测量命令)
B->>A: led 初始化APPLICATION 40
B->>A: temp 初始化APPLICATION 45触发注册
B->>A: com 初始化APPLICATION 50上电发 ID
B->>A: watdog 初始化APPLICATION 60
B->>A: ch9438 flushAPPLICATION 90
A->>D: 传感器数据触发 → 缓存 → 20ms 上报
```
---
## 7. 关键设计决策
### 7.1 波特率 POR 时序(重点坑)
**现象**烧录后波特率正常9600断电重启后回退为 115200部分端口只收到 `0x00`
**根因**CH9438 的 FCR 复位位RFIFORST/TFIFORST会**异步重置波特率分频器**。POR 冷启动时 FCR 复位持续较久,把紧随其后的 9600 配置LCR/DLL/DLM清回芯片默认值 115200烧录时芯片未断电、复位瞬间完成因此正常。
**修复**(初始化顺序):
```
写 LCR(DLAB=1) → 写 DLL/DLM(9600) → 验证
→ 引脚配置 → FCR=0x07复位+使能,触发发生器重锁存)→ 1ms 延时
→ 重写 LCR(DLAB=1) → 重写 DLL/DLM(9600) → 回读验证(连 LCR 一起检查)→ LCR(DLAB=0)
```
**回读验证假象**DLAB 未锁存时,读 "DLL" 实际读到 RBRuart7 短接回环的 0x20、"DLM" 读到 IER0x4E——自洽的谎言。**必须连 LCR 一起回读比对**,确认 DLAB 真正置位;再加 8 次 ×20ms 重试兜底POR 后 UART 模块可能晚就绪,写入被静默丢弃)。
### 7.2 触发驱动采集
9 路全部由 UART 数据触发更新缓存,无轮询,响应实时;发送侧固定 20ms 周期取缓存最大值,采集与上报解耦。
### 7.3 缓存线程安全
volatile 字段 + 编译期通道索引触发回调ISR / workqueue 双上下文)与查询无锁,避免死锁与中断延迟。
### 7.4 回调上下文
协议命令回调全部在系统 workqueue 线程执行ISR 只做数据拷贝 —— 避免 ISR 内 `uart_poll_out` / `printk` 阻塞导致温度上报停止。
### 7.5 通道编号稳定
`DT_FOREACH` 按设备树节点顺序展开,若 usart2 排在 spi2 前会导致通道错位ch0 变成片内传感器)。通过按父节点 compatible 分两段构建设备列表,保证 ch0~7 = CH9438、ch8 = 片内。
### 7.6 坏帧丢弃
帧校验含符号、6 位数字与温度范围三重检查,字节丢失/错位产生的坏帧直接丢弃,不污染缓存。
---
## 8. 调试与诊断
### 8.1 打印规范
所有诊断打印由 `APP_DEBUG_PRINT` 宏控制(各模块默认 0默认只保留启动确认与错误打印
| 宏 | 位置 | 打印内容 |
|---|---|---|
| `APP_DEBUG_PRINT=1` | ch9438 | 波特率回读、work 计数、FIFO 扫描、运行期诊断 |
| `APP_DEBUG_PRINT=1` | godtek | 原始字节 dump、命令追踪 |
| `APP_DEBUG_PRINT=1` | temp | 每秒 9 路通道状态(含有效掩码) |
| `APP_DEBUG_PRINT=1` | com | 协议错误统计 |
启动确认打印(应保留的最小集):
```
[ch9438] v1.0 port=0 ok ← CH9438 8 端口初始化成功
[godtek] mode = 0xac: baudrate = 9600 ← 传感器模式与波特率确认
[app_led] Init: ... ← LED 初始化
[app_temp]temp init ← 温度模块初始化
[infra] ch0 ready=1 ... ch8 ready=1 ← 9 路设备就绪
[com] init: rx table=3, id sent ← 协议就绪 + 上电 ID
[watchdog] init ← 看门狗就绪
```
### 8.2 常见问题排查
| 现象 | 排查方向 |
|---|---|
| 重启后波特率异常0x00 / 乱码) | 确认 ch9438 初始化含 FCR 复位后重写波特率 + 回读验证§7.1 |
| 温度恒为 0.0 / 无数据 | 检查传感器 UART 波特率9600、测量命令周期500ms、帧校验是否丢帧 |
| 灯带无指示 | 检查 `led_strip_indicator` 节点、WS2812 SPI 时序 |
| 主板收不到上报 | 检查 usart1 115200、帧头 0x7EE7、CRC16 lsb-msb 与主板一致 |
### 8.3 回环自测
短接 CH9438 UART7 的 TX/RXPIN25 ↔ PIN26验证中断接收链路ISR → workqueue → 回调 → FIFO 读取),用于驱动回归测试。
---
## 9. 构建与烧录
```bash
# 构建board 定义在 boards/dr2501aoverlay 配置传感器波特率/模式)
west build -p auto -b dr2501a_g0b0ce/stm32g0b0xx app/app_photomagnetic \
-d build -DOVERLAY_CONFIG=boards/use_ms.overlay
# 烧录
west flash -d build
```
> 板级传感器配置(波特率、模式)统一在 `app/app_photomagnetic/boards/use_ms.overlay` 中,不修改板级 dts。