本文档详细描述了 OpenNeuro PTP (IEEE 1588 v2) 协议栈的完整架构设计,包括系统分层、核心算法、状态机设计和跨平台适配方案。
文档版本: v1.0
创建日期: 2026年1月20日
预计完成: 2026年2月2日
┌─────────────────────────────────────┐
│ 应用层 (Application) │
│ 用户应用 / ROS 2 集成 │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ API 层 (Public API) │
│ ptp_init() / ptp_step() / ptp_get() │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ 协议层 (PTP Protocol Core) │
│ State Machine / Messages / Servo │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ 平台层 (Platform Abstraction) │
│ Timestamp / Network / Timer │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ 硬件层 (Hardware Drivers) │
│ STM32H7 / RK3588 / ESP32 │
└─────────────────────────────────────┘
Master 模式状态机:
┌─────────────┐
│ INITIALIZING ◄─────┐
└────────┬────────────┘
│
├────▼──────────────────────────┐
│ LISTENING │
│ (等待成为 Master 或 Slave) │
│ - 监听 ANNOUNCE 消息 │
│ - 比较 Clock Identity │
└────┬─────────────────────────┘
│
├────▼──────────────────────────┐
│ MASTER │
│ (时钟源) │
│ - 发送 SYNC 消息 │
│ - 处理 DELAY_REQ │
│ - 维护时间 │
└────┬─────────────────────────┘
│
├────▼──────────────────────────┐
│ SLAVE │
│ (跟随 Master) │
│ - 接收 SYNC 消息 │
│ - 发送 DELAY_REQ │
│ - 调整本地时钟 │
└────────────────────────────────┘
状态转移条件:
- INITIALIZING → LISTENING: 初始化完成
- LISTENING → MASTER: 赢得 BMC (Best Master Clock) 算法
- LISTENING → SLAVE: 识别更好的 Master
- MASTER ↔ SLAVE: PTP 域内时钟比较
支持的消息类型:
| 消息 | 方向 | 用途 | 周期 |
|---|---|---|---|
| ANNOUNCE | Master → All | 宣告自己为时钟源 | 1-16s |
| SYNC | Master → Slave | 主时钟同步 | 1-128ms |
| FOLLOW_UP | Master → Slave | SYNC 发送时间戳 | 同 SYNC |
| DELAY_REQ | Slave → Master | 测量往返延迟 | 1-128s |
| DELAY_RESP | Master → Slave | 返回延迟响应 | 同 DELAY_REQ |
| PDELAY_REQ | P2P模式 | 点对点延迟测量 | 1-128s |
| PDELAY_RESP | P2P模式 | 点对点延迟响应 | 同 PDELAY_REQ |
消息格式 (IEEE 1588 v2):
struct ptp_header {
uint8_t transport_specific; // 4 bits: PTP_OVER_UDP_IPV4 = 0
uint8_t message_type; // 4 bits: SYNC, FOLLOW_UP, 等
uint8_t version_ptp; // 4 bits: PTP v2.0 = 2
uint8_t minor_version; // 4 bits: 0
uint16_t message_length; // 消息总长度
uint8_t domain_number; // PTP 域号 (默认 0)
uint8_t flags[2]; // 标志位
int64_t correction_field; // 路径延迟补正
uint32_t source_port_id[3]; // 源端口标识符
uint16_t sequence_id; // 序列号
uint8_t control; // 控制字段
uint8_t log_message_interval; // 消息间隔 (2^n ms)
};使用 PI (Proportional-Integral) Servo 算法 调整本地时钟:
误差 (nanoseconds)
│
├──► Proportional 增益 (KP)
│
├──► Integral 增益 (KI) ──► 频率调整 (PPM)
│
└──► 限制器 (Limiter)
- 最大 ±500 PPM
- 缓慢收敛 (防止时钟跳跃)
Servo 伪代码:
// 每次收到 SYNC 消息后执行
void servo_step(ptp_state_t *state, int64_t time_error_ns) {
// 计算 PI 输出
int32_t proportional = KP * time_error_ns;
state->integral_sum += time_error_ns;
int32_t integral = KI * state->integral_sum;
// 频率调整 (PPM)
int32_t freq_adj_ppm = (proportional + integral) / NORM;
// 限制频率调整范围
if (freq_adj_ppm > 500) freq_adj_ppm = 500;
if (freq_adj_ppm < -500) freq_adj_ppm = -500;
// 应用到硬件时钟
apply_clock_adjustment(freq_adj_ppm);
}/**
* 初始化 PTP 协议栈
* @param role: PTP_MASTER (1) 或 PTP_SLAVE (0)
* @param domain: PTP 域号 (0-127, 默认 0)
* @param config: 配置结构指针
* @return: 成功返回 PTP 句柄, 失败返回 NULL
*/
ptp_handle_t ptp_init(uint8_t role, uint8_t domain,
const ptp_config_t *config);
/**
* 反初始化, 释放资源
* @param handle: PTP 句柄
*/
void ptp_deinit(ptp_handle_t handle);/**
* PTP 协议栈主循环, 需周期性调用 (建议 1ms)
* @param handle: PTP 句柄
* @return: 0 成功, 非 0 表示错误
*/
int ptp_step(ptp_handle_t handle);
/**
* 处理收到的网络数据包
* @param handle: PTP 句柄
* @param data: 接收的数据指针
* @param length: 数据长度
* @param hw_timestamp: 硬件时间戳 (nanoseconds)
* @return: 0 成功处理, -1 表示无效数据
*/
int ptp_process_packet(ptp_handle_t handle, const uint8_t *data,
uint16_t length, uint64_t hw_timestamp);/**
* 获取当前时间 (synchronized time)
* @param handle: PTP 句柄
* @param time_ns: 输出指针, 接收时间值 (nanoseconds)
* @return: 0 成功, -1 表示未同步
*/
int ptp_get_time(ptp_handle_t handle, uint64_t *time_ns);
/**
* 获取同步统计信息
* @param handle: PTP 句柄
* @param stats: 输出指针, 接收统计数据
* @return: 0 成功
*/
int ptp_get_stats(ptp_handle_t handle, ptp_stats_t *stats);
/**
* 查询同步状态
* @param handle: PTP 句柄
* @return: 0=未同步, 1=同步中, 2=已同步
*/
uint8_t ptp_get_sync_status(ptp_handle_t handle);
/**
* 获取最后同步误差 (nanoseconds)
* @param handle: PTP 句柄
* @return: 最后测量的时间误差
*/
int64_t ptp_get_last_sync_error(ptp_handle_t handle);每个平台需实现以下接口:
// 平台特定的初始化
int platform_timestamp_init(void);
// 获取当前硬件时间 (nanoseconds, 绝对时间)
uint64_t platform_get_timestamp(void);
// 调整硬件时钟频率 (PPM: -500 ~ +500)
int platform_adjust_clock(int32_t ppm);
// 设置硬件时钟 (仅在初始化时使用)
int platform_set_time(uint64_t time_ns);- 使用内部计时器 (TIM7) 提供高精度时间戳
- 以太网 DMA 捕获报文接收时间
- 频率调整通过改变定时器预分频
- 使用 CLOCKSOURCE_ACPI_PM (ARM 通用计时器)
- 从网卡驱动获取硬件时间戳 (如果支持)
- 通过调整 PLL 频率实现 Servo
- 使用 CPU 内部计时器 (Timer Group 0)
- 以太网接收中断记录时间戳
- 通过 XTAL 分频实现频率调整
| 指标 | 目标 | 测试方法 |
|---|---|---|
| 同步精度 | <10µs | 与 GPS 参考信号对比 |
| 收敛时间 | <10s | 从启动到 <1µs 误差 |
| 消息处理延迟 | <100µs | 测量 SYNC 收到到 PI Servo 调整 |
| CPU 占用率 | <5% | 在 100MHz MCU 上 |
| 内存占用 | <256KB | 堆 + 栈 + 全局变量 |
- 消息编解码测试
- 状态机转移测试
- Servo 算法测试
- 时间计算精度测试
- Master-Slave 同步测试
- 多 Slave 并发测试
- 网络延迟变化适应性测试
- 长期稳定性测试 (24h+)
- 精度测量 (对标 GPS/高精度参考)
- 延迟分析 (使用示波器或逻辑分析仪)
- 抖动 (Jitter) 测量
- 能耗分析
| 周 | 任务 | 交付物 |
|---|---|---|
| W1-W2 | 架构设计 + API 定义 | 本文档 + 头文件 |
| W3-W4 | 架构评审 | 架构评审记录 |
| W5-W7 | Master 实现 | Master 消息处理代码 |
| W8-W9 | Slave + Servo 实现 | Slave 同步代码 |
| W10 | PI Servo 优化 | 精度优化报告 |
| W11-W14 | 跨平台适配 | 3 个平台驱动完成 |
| W15-W16 | 集成验证 | 集成测试报告 |
| W17-W20 | 文档完善 | 完整 API 文档 |
- API 接口的完整性和易用性
- 状态机的健壮性 (无死锁、无无限循环)
- 内存和 CPU 使用是否在预期范围
- 硬件时间戳接口的通用性
- 错误处理的充分性
- 代码注释的完整性
下一步: 等待架构评审,计划 2026年2月2日完成评审并启动编码。