✨ feat(system-overview): 创建系统总览文档 - 描述项目背景与硬件平台配置 - 提供 FreeRTOS 任务拓扑表(任务优先级、栈大小、职责) - 详细说明系统启动序列和初始化依赖关系 - 绘制 2D/1D 状态机完整流程图 - 解释 TEMP_REQ 辅助通道工作机制 - 说明任务间同步机制(Frame_Ready_Flag、双缓冲 TX) ✨ feat(dvp-module-design): 创建 DVP 模块设计文档 - 提供 DVP 硬件连接引脚映射表 - 描述 DVP 时序配置(信号极性、工作模式) - 解释 DMA ping-pong 行缓冲机制和切换逻辑 - 说明 DVP IRQ 帧组装流程(STR_FRM/ROW_DONE) - 定义 FrameBuffer 数据格式和像素访问方式 - 说明 TMP 模式温度换算公式和字节序要求 ✨ feat(qdx-protocol-design): 创建 QDX 协议设计文档 - 描述完整 TLV 帧结构(FrameHeader + TLV + CRC) - 列出所有 Class/Type 映射表和用途说明 - 解释零拷贝 TX 缓冲区架构(HeadOffset 机制) - 说明分片机制和最大载荷限制 - 定义 Flags 字段各位含义和使用场景 ✨ feat(tcp-module-design): 创建 TCP 通信模块设计文档 - 描述双流连接架构(控制流 5511 / 数据流 5512) - 说明握手流程和连接建立时序 - 解释心跳机制和 TCP Keepalive 配置 - 描述配置下发与缓存机制 - 说明数据发送队列和背压处理策略 - 解释 WCHNET 网络栈驱动任务工作机制 ✨ feat(integration-guide): 创建对接集成指南 - 提供网络接入参数表(IP、端口、协议) - 详细说明握手流程和配置下发格式 - 提供 2D/1D 温度帧解析方法和示例代码 - 说明检测结果上报和 NG 响应机制 - 解释 TEMP_REQ 按需截图工作方式 - 列出错误码表和对接故障排查步骤
199 lines
5.7 KiB
Markdown
199 lines
5.7 KiB
Markdown
# DVP 模块设计文档
|
||
|
||
> 文档版本:1.0 · 日期:2026-03-15 · 状态:已发布
|
||
|
||
---
|
||
|
||
## 1. 模块概述
|
||
|
||
DVP(Digital Video Port)模块负责将 Mini212G2 传感器输出的 8-bit CMOS 并行数据转换为内存中可访问的帧缓冲(FrameBuffer)。整个采集链路通过硬件 DMA ping-pong 和快速中断实现,CPU 占用极低。
|
||
|
||
源文件:`Debug/dvp.c` / `Debug/dvp.h`
|
||
|
||
---
|
||
|
||
## 2. DVP 硬件连接与引脚映射
|
||
|
||
所有 DVP 引脚配置为 **浮空输入(GPIO_Mode_IN_FLOATING)**。
|
||
|
||
| 引脚 | DVP 信号 | 说明 |
|
||
|------|----------|------|
|
||
| PA4 | D0 | 数据位 0 |
|
||
| PA5 | D1 | 数据位 1 |
|
||
| PA6 | D2 | 数据位 2 |
|
||
| PA9 | D3 | 数据位 3 |
|
||
| PA10 | D4 | 数据位 4 |
|
||
| PC8 | D5 | 数据位 5 |
|
||
| PC9 | D6 | 数据位 6 |
|
||
| PC11 | D7 | 数据位 7 |
|
||
| PB3 | VSYNC | 帧同步信号 |
|
||
| PB8 | HSYNC | 行同步信号 |
|
||
| PB9 | PIXCLK | 像素时钟 |
|
||
|
||
---
|
||
|
||
## 3. DVP 时序配置
|
||
|
||
在 `DVP_Init()` 中完成以下配置:
|
||
|
||
### 3.1 工作模式
|
||
|
||
| 配置项 | 值 | 说明 |
|
||
|--------|-----|------|
|
||
| 数据宽度 | `RB_DVP_D8_MOD` | 8-bit 并行数据 |
|
||
| 采集模式 | `Video_Mode` | 连续帧采集(非快照模式) |
|
||
| 捕获控制 | 持续捕获(CR1 CM=0) | 不限帧数 |
|
||
|
||
### 3.2 信号极性
|
||
|
||
| 信号 | 寄存器位 | 配置值 | 说明 |
|
||
|------|----------|--------|------|
|
||
| VSYNC | `RB_DVP_V_POLAR` | **1(高有效)** | DIGITAL_FIELD_VALID 高电平期间为有效帧行 |
|
||
| HSYNC | `RB_DVP_H_POLAR` | 0(高有效)| 标准高有效行同步 |
|
||
| PCLK | `RB_DVP_P_POLAR` | 0(上升沿采样)| 正常时钟极性 |
|
||
|
||
> **与手册对应**:Mini212G2 FIELD_VALID 高电平为有效期,因此 V_POLAR 置 1(高有效),与硬件手册时序图一致。
|
||
|
||
### 3.3 图像尺寸配置
|
||
|
||
| 寄存器 | 值 | 说明 |
|
||
|--------|-----|------|
|
||
| `DVP->COL_NUM` | 512(`BYTES_PER_LINE`) | 每行字节数 = 256 像素 × 2 字节 |
|
||
| `DVP->ROW_NUM` | 1 | 每行触发一次 ROW_DONE 中断 |
|
||
|
||
---
|
||
|
||
## 4. DMA ping-pong 行缓冲机制
|
||
|
||
### 4.1 缓冲区配置
|
||
|
||
```c
|
||
__attribute__((aligned(4))) uint8_t DMA_LineBuf0[512]; /* DMA_BUF0 */
|
||
__attribute__((aligned(4))) uint8_t DMA_LineBuf1[512]; /* DMA_BUF1 */
|
||
```
|
||
|
||
两个缓冲区分别挂载在 `DVP->DMA_BUF0` 和 `DVP->DMA_BUF1`,DVP 硬件在两者之间自动切换,无需 CPU 干预。
|
||
|
||
### 4.2 缓冲切换逻辑
|
||
|
||
ROW_DONE 中断触发时,硬件已切换到 **下一个缓冲**开始写入。因此正确读取方法为:
|
||
|
||
```c
|
||
/* BUF_TOG=1 表示 DMA 正在写 BUF0,此时应读 BUF1(刚写完的那个) */
|
||
uint8_t *src = (DVP->CR1 & RB_DVP_BUF_TOG) ? DMA_LineBuf0 : DMA_LineBuf1;
|
||
```
|
||
|
||
即:`BUF_TOG` 状态位指示**当前正在写入的缓冲**,应读取**另一个**刚刚完成写入的缓冲。
|
||
|
||
### 4.3 尺寸约束
|
||
|
||
修改传感器分辨率时,必须同时更新以下三个宏(`dvp.h`):
|
||
|
||
```c
|
||
#define SENSOR_WIDTH 256 /* 像素列数 */
|
||
#define SENSOR_HEIGHT 192 /* 像素行数 */
|
||
#define BYTES_PER_LINE 512 /* SENSOR_WIDTH × 2 字节/像素 */
|
||
```
|
||
|
||
---
|
||
|
||
## 5. DVP IRQ 帧组装逻辑
|
||
|
||
中断处理函数声明:
|
||
|
||
```c
|
||
void DVP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||
```
|
||
|
||
`WCH-Interrupt-fast` 属性使中断跳过通用寄存器入栈,显著降低中断延迟,确保在下一行像素时钟到来(Mini212G2 @ 25 Hz,每行约 42.67 µs)前完成 512 B 的 `memcpy`。
|
||
|
||
### 5.1 帧同步(STR_FRM 中断)
|
||
|
||
VSYNC 上升沿触发,是帧同步的**唯一锚点**:
|
||
|
||
```c
|
||
if (DVP->IFR & RB_DVP_IF_STR_FRM) {
|
||
DVP->IFR = RB_DVP_IF_STR_FRM;
|
||
current_line_idx = 0; /* 重置行计数器 */
|
||
dvp_frame_count++;
|
||
}
|
||
```
|
||
|
||
### 5.2 行完成(ROW_DONE 中断)
|
||
|
||
每行像素传输完成后触发:
|
||
|
||
```c
|
||
if (DVP->IFR & RB_DVP_IF_ROW_DONE) {
|
||
DVP->IFR = RB_DVP_IF_ROW_DONE;
|
||
uint8_t *src = (DVP->CR1 & RB_DVP_BUF_TOG) ? DMA_LineBuf0 : DMA_LineBuf1;
|
||
uint32_t idx = current_line_idx;
|
||
current_line_idx++;
|
||
if (idx < SENSOR_HEIGHT) {
|
||
memcpy(FrameBuffer[idx], src, BYTES_PER_LINE);
|
||
if (idx == SENSOR_HEIGHT - 1) { /* 第 191 行完成 */
|
||
Frame_Ready_Flag = 1; /* 通知业务任务 */
|
||
Ready_Frame_Count = dvp_frame_count; /* 记录帧号 */
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
> **注意:先读 `idx` 再递增**,避免 off-by-one。STR_FRM 将 `idx` 置 0,首次 ROW_DONE 时 `idx=0`,将数据写入 `FrameBuffer[0]`,符合预期。
|
||
|
||
---
|
||
|
||
## 6. FrameBuffer 数据格式
|
||
|
||
```c
|
||
__attribute__((aligned(4))) uint8_t FrameBuffer[SENSOR_HEIGHT][BYTES_PER_LINE];
|
||
/* = uint8_t[192][512] */
|
||
```
|
||
|
||
### 6.1 像素访问方式
|
||
|
||
FrameBuffer 声明为 `uint8_t` 数组,实际存储 `uint16_t` 小端序温度值:
|
||
|
||
```c
|
||
/* 访问第 row 行、第 col 列的温度 */
|
||
uint16_t *pixels = (uint16_t *)FrameBuffer;
|
||
uint16_t raw_val = pixels[row * SENSOR_WIDTH + col];
|
||
```
|
||
|
||
### 6.2 温度换算(TMP 模式)
|
||
|
||
```
|
||
温度(°C)= raw_val × 0.1
|
||
```
|
||
|
||
例:`raw_val = 370` → `37.0°C`
|
||
|
||
### 6.3 字节序说明
|
||
|
||
CH32V307 为**小端序**(Little-Endian):
|
||
|
||
| 偏移 | 内容 |
|
||
|------|------|
|
||
| `FrameBuffer[row][col*2 + 0]` | 温度低字节 |
|
||
| `FrameBuffer[row][col*2 + 1]` | 温度高字节 |
|
||
|
||
传感器必须配置为 **CMOS8(LSB) 模式**(低字节先发),否则字节顺序反转,温度值错误。
|
||
|
||
### 6.4 内存布局摘要
|
||
|
||
| 参数 | 值 |
|
||
|------|-----|
|
||
| 总大小 | 192 × 512 = 98,304 字节 ≈ 96 KB |
|
||
| 每行 | 512 字节 = 256 像素 |
|
||
| 像素格式 | uint16_t,小端,0.1°C/LSB,TMP 模式绝对温度 |
|
||
| 对齐 | 4 字节对齐(`__attribute__((aligned(4)))`) |
|
||
|
||
---
|
||
|
||
## 7. 相关文档
|
||
|
||
| 文档 | 内容 |
|
||
|------|------|
|
||
| [系统总览.md](系统总览.md) | FreeRTOS 任务拓扑、Frame_Ready_Flag 同步机制 |
|
||
| [Mini212G2预配置指南.md](../Mini212G2预配置指南.md) | CMOS8(LSB) + TMP 模式配置命令 |
|