博宸精芯开源ADC数据采集显示上位机通信协议
发布时间: 2026-08-24 14:11
|
作者: yang
|
状态: published
|
更新时间: 2026-08-24 14:18
# net_adc 通信协议说明文档
> **PC 端 (net_adc) ↔ FPGA 端 (lwIP) 以太网通信协议规范**
>
> | 项目 | 内容 |
|------|------|
| 版本 | v1.0 |
| 传输层 | TCP |
| 默认端口 | 7 |
| 日期 | 2026-08-24 |
>
>
---
## 目录
1. [协议概述](#1-协议概述)
2. [帧格式规范](#2-帧格式规范)
3. [命令详细说明](#3-命令详细说明)
4. [响应帧详细说明](#4-响应帧详细说明)
5. [ADC 数据解析](#5-adc-数据解析)
6. [数据采集流程](#6-数据采集流程)
7. [错误处理与重传](#7-错误处理与重传)
8. [附录](#8-附录)
---
## 1. 协议概述
### 1.1 通信模型
net_adc 与 FPGA 之间采用主从式请求-响应模型。PC 端作为主设备主动发送命令,FPGA 端作为从设备被动响应。所有通信均由 PC 端发起。
PC (net_adc) FPGA (lwIP)
│ │
│ ① CMD_01: 触发ADC采样 │
│ ────────────────────────────────────► │
│ │
│ ADC采样 → DDR3存储
│ │
│ ② CMD_05: 读取数据 (addr=0x00000000) │
│ ────────────────────────────────────► │
│ │
│ ③ 响应帧: 1032字节 (addr + 1024B数据) │
│ ◄──────────────────────────────────── │
│ │
│ ② CMD_05: 读取数据 (addr=0x00000400) │
│ ────────────────────────────────────► │
│ │
│ ③ 响应帧: 1032字节 (addr + 1024B数据) │
│ ◄──────────────────────────────────── │
│ │
│ ... 重复直至数据读完 ... │
│ │
### 1.2 传输层配置
| 参数 | 默认值 | 可配置 |
|------|--------|--------|
| 协议类型 | TCP | 固定 TCP |
| 工作模式 | 客户端 | 客户端 / 服务端 (界面切换) |
| FPGA IP 地址 | 192.168.1.10 | 是 (界面输入) |
| 通信端口 | 7 | 是 (界面输入) |
### 1.3 帧标识符
协议使用 4 字节帧头标识符区分命令类型和响应类型:
| 帧头字节 | 类型 | 方向 | 说明 |
|----------|------|------|------|
| `0x01 0x01 0x55 0xAA` | 命令 | PC → FPGA | 触发 ADC 采样 |
| `0x01 0x05 0x55 0xAA` | 命令 | PC → FPGA | 读取 DDR3 数据 |
| `0x02 0x05 0x55 0xAA` | 响应 | FPGA → PC | 数据帧 (含 ADC 采样数据) |
> **帧头编码规则:**
>
> - 第 1 字节:`0x01` = 命令帧,`0x02` = 响应帧
> - 第 2 字节:命令/响应编号 (`0x01` = 触发,`0x05` = 数据传输)
> - 第 3-4 字节:固定魔数 `0x55 0xAA`,用于帧同步校验
---
## 2. 帧格式规范
### 2.1 触发 ADC 命令帧
**CMD_01 — 触发 ADC 采样** | PC → FPGA | 4 字节
| 字节 | 值 | 说明 |
|------|-----|------|
| 0 | `0x01` | 帧类型: 命令 |
| 1 | `0x01` | 命令编号: 触发 |
| 2 | `0x55` | 魔数 (同步) |
| 3 | `0xAA` | 魔数 (同步) |
### 2.2 读取数据命令帧
**CMD_05 — 读取 DDR3 数据** | PC → FPGA | 8 字节
| 字节 | 值 | 说明 |
|------|-----|------|
| 0 | `0x01` | 帧类型: 命令 |
| 1 | `0x05` | 命令编号: 读数据 |
| 2 | `0x55` | 魔数 (同步) |
| 3 | `0xAA` | 魔数 (同步) |
| 4 | Addr[31:24] | 起始地址 (高字节) |
| 5 | Addr[23:16] | 起始地址 |
| 6 | Addr[15:8] | 起始地址 |
| 7 | Addr[7:0] | 起始地址 (低字节) |
**地址编码:** 大端序 (Big-Endian),高字节在前。每次读取 1024 字节 (256 个采样点)。
### 2.3 数据响应帧
**RESP_05 — 数据帧 (ADC 采样数据)** | FPGA → PC | 1032 字节
| 字节偏移 | 长度 | 内容 | 说明 |
|----------|------|------|------|
| 0 - 3 | 4 字节 | `0x02 0x05 0x55 0xAA` | 帧头标识 |
| 4 - 7 | 4 字节 | 起始地址 | 大端序,与本帧数据在 DDR3 中的起始地址对应 |
| 8 - 1031 | 1024 字节 | ADC 采样数据 | 256 个采样点 × 4 字节/点 |
---
## 3. 命令详细说明
### 3.1 CMD_01 — 触发 ADC 采样
| 属性 | 值 |
|------|-----|
| 命令标识 | `0x01 0x01 0x55 0xAA` |
| 帧长度 | 4 字节 |
| 方向 | PC → FPGA |
| 功能 | 通知 FPGA 启动 ADC 采样,采样结果写入 DDR3 |
| 无响应 | 此命令不产生响应帧,FPGA 静默执行 |
```csharp
// C# 实现
byte[] data = new byte[] { 0x01, 0x01, 0x55, 0xAA };
_socket.Send(data); // TCP 发送
```
### 3.2 CMD_05 — 读取 DDR3 数据
| 属性 | 值 |
|------|-----|
| 命令标识 | `0x01 0x05 0x55 0xAA` |
| 帧长度 | 8 字节 (4 字节帧头 + 4 字节地址) |
| 方向 | PC → FPGA |
| 功能 | 请求 FPGA 从指定 DDR3 地址读取 1024 字节数据并返回 |
| 响应 | 1 帧 RESP_05 数据帧 (1032 字节) |
#### 地址参数
- **编码方式**:大端序 (Big-Endian),高字节在前
- **起始地址**:0x00000000 (首次采集从地址 0 开始)
- **地址递增**:每次 +1024 (0x400),对应一个数据帧的 1024 字节
- **地址范围**:0x00000000 ~ (缓冲区大小 - 1024)
```csharp
// C# 实现 - 构造读取命令
byte[] data = new byte[8];
data[0] = 0x01; // 帧类型: 命令
data[1] = 0x05; // 命令编号: 读数据
data[2] = 0x55; // 魔数
data[3] = 0xAA; // 魔数
data[4] = (byte)(currentAddr >> 24); // 地址 [31:24]
data[5] = (byte)(currentAddr >> 16); // 地址 [23:16]
data[6] = (byte)(currentAddr >> 8); // 地址 [15:8]
data[7] = (byte)(currentAddr & 0xFF); // 地址 [7:0]
_socket.Send(data); // 发送
// 地址递增: currentAddr += 1024;
```
---
## 4. 响应帧详细说明
### 4.1 RESP_05 — 数据帧解析
FPGA 返回的 1032 字节数据帧,PC 端在 `ProcessReceivedData()` 中解析:
```csharp
// 帧校验: 检查长度和帧头
if (data.Length >= 1032 &&
data[0] == 0x02 && data[1] == 0x05 &&
data[2] == 0x55 && data[3] == 0xAA)
{
// 解析起始地址 (大端序)
uint offset = (uint)(data[4] << 24) | (uint)(data[5] << 16) |
(uint)(data[6] << 8) | (uint)data[7];
// 地址范围校验
uint maxOffset = (uint)_dataBuffer.Length - 1024;
if (offset <= maxOffset)
{
// 将 1024 字节 ADC 数据拷贝到缓冲区对应位置
Array.Copy(data, 8, _dataBuffer, offset, 1024);
_receivedPacketCount++;
}
}
```
### 4.2 帧校验规则
| 校验项 | 条件 | 失败处理 |
|--------|------|----------|
| 最小长度 | data.Length >= 1032 | 忽略该数据包 |
| 帧头标识 | data[0..3] == {0x02, 0x05, 0x55, 0xAA} | 忽略该数据包 |
| 地址范围 | offset <= _dataBuffer.Length - 1024 | 记录"地址超出范围"日志 |
---
## 5. ADC 数据解析
### 5.1 采样点数据结构
每个采样点占用 4 字节 (32 位),在缓冲区中以小端序存储。高 16 位为 ADC1 数据,低 16 位为 ADC2 数据。
**单采样点数据格式 (4 字节, 小端序 Little-Endian)**
| 字节 | 内容 |
|------|------|
| Byte 0 | ADC2 [7:0] |
| Byte 1 | ADC2 [15:8] |
| Byte 2 | ADC1 [7:0] |
| Byte 3 | ADC1 [15:8] |
| 位域 | 通道 | 说明 |
|------|------|------|
| [31:16] | ADC1 | ADC1 原始 16 位数据 |
| [15:0] | ADC2 | ADC2 原始 16 位数据 |
### 5.2 数据转换流程
```csharp
// 1. 从缓冲区读取 32 位数据 (小端序)
uint adc_buf = data[i*4] | (data[i*4+1] << 8) | (data[i*4+2] << 16) | (data[i*4+3] << 24);
// 2. 提取双通道原始值
short raw_adc1 = (short)((adc_buf >> 16) & 0xFFFF); // 高16位
short raw_adc2 = (short)(adc_buf & 0xFFFF); // 低16位
// 3. 右移2位,获取14位有效数据
short adc1 = (short)(raw_adc1 / 4); // 范围: -8192 ~ +8191
short adc2 = (short)(raw_adc2 / 4);
// 4. 电压换算
double voltage = adc_value * 2.15 / 8192.0; // 参考电压 2.15V
```
### 5.3 数值范围
| 参数 | 原始值 | 有效值 (/4) | 电压值 |
|------|--------|-------------|--------|
| 最小值 | -32768 (0x8000) | -8192 | -2.15 V |
| 零点 | 0 | 0 | 0.00 V |
| 最大值 | +32767 (0x7FFF) | +8191 | +2.147 V |
| 分辨率 | 16 位 | 14 位 | 2.15/8192 ≈ 0.262 mV |
---
## 6. 数据采集流程
### 6.1 完整采集时序
```
时间轴 ──────────────────────────────────────────────────────────►
PC: [触发ADC]──20ms──[读#0 addr=0]──100ms──[读#1 addr=0x400]──100ms──[读#2]──►
│ │ │ │
FPGA: [采样→DDR3] [返回1032B] [返回1032B] [返回1032B]
│ │ │ │
进度: 0% 25% 50% 75% 100%
```
### 6.2 采集参数
| 参数 | 值 | 说明 |
|------|-----|------|
| 每帧采样点数 | 256 | 1024 字节 / 4 字节每点 |
| 地址递增步长 | 1024 (0x400) | 对应每帧 1024 字节 |
| 单包超时 | 100 ms | 等待响应的最大时间 |
| 最大重试次数 | 3 | 超时后重发,最多 3 次 |
| 轮询间隔 | 5 ms | 检查接收计数的间隔 |
| 包间间隔 | 20 ms | 两个请求之间的延迟 |
| 采集后等待 | 200 ms | 等待残余数据包到达 |
### 6.3 采集算法伪代码
```
packetsCount = sampleCount / 256 // 总包数
currentAddr = 0x00000000 // 起始地址
receivedCount = 0 // 已接收包计数
for i = 0 to packetsCount - 1:
for retry = 0 to 2: // 最多3次重试
// 发送读取命令
send CMD_05 with currentAddr
expectedPacket = i + 1
// 等待响应 (100ms超时)
waitStart = now()
while now() - waitStart < 100ms:
if receivedCount >= expectedPacket:
break // 收到响应
sleep(5ms)
if receivedCount >= expectedPacket:
break // 成功,跳出重试循环
currentAddr += 1024 // 地址递增
sleep(20ms) // 包间间隔
sleep(200ms) // 等待残余数据
DrawWaveform() // 绘制波形+频谱
```
### 6.4 采样点数与数据量
| 采样点数 | 数据包数 | 每包采样点 | 总数据量 | DDR3 地址范围 |
|----------|----------|------------|----------|---------------|
| 1,024 | 4 | 256 | 4 KB | 0x0000 ~ 0x0FFF |
| 2,048 | 8 | 256 | 8 KB | 0x0000 ~ 0x1FFF |
| 4,096 | 16 | 256 | 16 KB | 0x0000 ~ 0x3FFF |
| 8,192 | 32 | 256 | 32 KB | 0x0000 ~ 0x7FFF |
| 16,384 | 64 | 256 | 64 KB | 0x0000 ~ 0xFFFF |
| 32,768 | 128 | 256 | 128 KB | 0x0000 ~ 0x1FFFF |
| 65,536 | 256 | 256 | 256 KB | 0x0000 ~ 0x3FFFF |
| 131,072 | 512 | 256 | 512 KB | 0x0000 ~ 0x7FFFF |
---
## 7. 错误处理与重传
### 7.1 重传机制
数据采集过程中,如果发送读取命令后 100ms 内未收到对应数据帧,将重发该命令,最多重试 3 次。
| 重试次数 | 超时时间 | 动作 |
|----------|----------|------|
| 第 1 次 | 100 ms | 发送 CMD_05,等待响应 |
| 第 2 次 | 100 ms | 重发 CMD_05,等待响应 |
| 第 3 次 | 100 ms | 重发 CMD_05,等待响应 |
| 超过 3 次 | — | 跳过该包,继续下一包 |
### 7.2 连接异常处理
| 异常类型 | 处理方式 |
|----------|----------|
| TCP 连接正常关闭 | 记录"连接已正常关闭"日志,自动断开 |
| Socket 接收异常 | 记录异常类型和消息,自动断开连接 |
| TCP 连接异常关闭 | 记录日志,自动断开 |
| 地址超出范围 | 记录"地址超出范围"日志,丢弃该帧 |
| 帧头不匹配 | 静默丢弃 (不满足帧格式) |
| 数据导出权限不足 | 提示"没有权限访问该目录" |
### 7.3 帧校验失败处理
> **注意:** 如果接收到的数据不满足帧头校验条件 (长度 < 1032 或帧头不匹配),该数据将被静默丢弃,不计入接收包计数。这意味着只有有效数据帧才会触发进度条更新。
---
## 8. 附录
### 8.1 协议命令速查表
| 命令 | 方向 | 帧头 | 长度 | 功能 |
|------|------|------|------|------|
| CMD_01 | PC → FPGA | `01 01 55 AA` | 4B | 触发 ADC 采样 |
| CMD_05 | PC → FPGA | `01 05 55 AA [Addr]` | 8B | 读取 DDR3 数据 |
| RESP_05 | FPGA → PC | `02 05 55 AA [Addr] [Data]` | 1032B | 返回 ADC 采样数据 |
### 8.2 常量定义
| 常量 | 值 | 说明 |
|------|-----|------|
| 帧头魔数 | 0x55 0xAA | 帧同步标识 |
| 命令帧标识 | 0x01 | 第 1 字节,表示命令帧 |
| 响应帧标识 | 0x02 | 第 1 字节,表示响应帧 |
| 触发命令编号 | 0x01 | 第 2 字节,触发 ADC |
| 数据命令编号 | 0x05 | 第 2 字节,数据传输 |
| 每帧数据大小 | 1024 字节 | 每帧携带的 ADC 数据量 |
| 每帧采样点数 | 256 | 1024 / 4 字节每点 |
| 响应帧总长度 | 1032 字节 | 4 (帧头) + 4 (地址) + 1024 (数据) |
| 缓冲区大小 | 64 MB | 16,777,216 × 4 字节 |
| ADC 参考电压 | 2.15 V | 电压换算基准 |
| ADC 有效位数 | 14 位 | 原始 16 位 / 4 |
| 采样率 | 250 MHz | FFT 频率计算基准 |
| FFT 点数 | 1024 | 频率分辨率 ~244 kHz |
### 8.3 地址计算示例
以采集 4096 个采样点为例 (16 个数据包):
| 包号 | 发送地址 (Hex) | 地址 (Decimal) | 数据范围 |
|------|----------------|----------------|----------|
| 0 | 0x00000000 | 0 | Byte 0 ~ 1023 |
| 1 | 0x00000400 | 1024 | Byte 1024 ~ 2047 |
| 2 | 0x00000800 | 2048 | Byte 2048 ~ 3071 |
| ... | ... | ... | ... |
| 15 | 0x00003C00 | 15360 | Byte 15360 ~ 16383 |
### 8.4 电压换算速查
| ADC 原始值 (16位) | 有效值 (14位) | 电压 (V) |
|---------------------|---------------|----------|
| 0x8000 (-32768) | -8192 | -2.150 |
| 0xC000 (-16384) | -4096 | -1.075 |
| 0x0000 (0) | 0 | 0.000 |
| 0x4000 (16384) | 4096 | +1.075 |
| 0x7FFC (32764) | 8191 | +2.147 |
```
```
加载中...
正在加载内容...
评论
正在加载评论...