ZHCAE48 June 2024 LMK5B33216
当 PTP 协议栈在冷启动模式 下初始化时,所有硬件寄存器(网络同步器和 PTP 计时 (ToD) 硬件时钟)都必须保持未初始化状态。使用相应的启动值更新 PTP 硬件时钟寄存器后,将写入网络同步器的完整寄存器集以初始化器件。可以使用 TICS Pro 软件,以十六进制文件格式生成启动寄存器初始化值。
仅通过改变网络时序 PTP 基准输入频率,即可调节处于稳定状态的 PTP 硬件计时时钟。PTP 时钟伺服环路通过在 LMK5XXXXXS1 中对内部 DCO 进行编程来修改输出频率。syn1588® PTP 协议栈软件的相应示例代码段如下所示。在下面的示例代码中,实现了两个函数:getDrift 和 setDrift。getDrift 函数从网络同步器读取频率调整的当前值,而 setDrift 函数使用用户提供的值更新频率调整。
从时间戳中提取的原始输入数据会重新进行格式化,并使用源自 TICS Pro 软件的比例因子调整为 ns/s。包含 PTP 事件报文的时间信息通过预滤波器传播,并发送至相位内插 (PI) 伺服器,由其计算新的频率调整值。新的频率值传递给函数 setDrift,后者从网络同步器读取当前频率偏移,计算新的漂移值,相应地重新调整漂移的大小和格式,并使用新的 DCO 调整值以及是递增还是递减 DCO 频率来更新 DPLL。
static constexpr double magic_factor = 247390116249 / 100000.0;
ptp::scalednanoseconds ptp::ti::Osc::getDrift() const
{
auto values = readRegs(ptp::ti::Register::DPLL2_FB_NUM_STAT_4, 4);
std::uint64_t value = 0;
value |= values[0];
value |= static_cast<std::uint64_t>(values[1]) << 8;
value |= static_cast<std::uint64_t>(values[2]) << 16;
value |= static_cast<std::uint64_t>(values[3]) << 24;
// if MSB is 1 handle two's complement
if (value > (1ull << 39)) value = -((value ^ 0xffffffffff) + 1);
auto drift = std::chrono::duration<double>(value / magic_factor);
return std::chrono::duration_cast<ptp::scalednanoseconds>(drift);
}
void ptp::ti::Osc::setDrift(ptp::scalednanoseconds drift)
{
// Check for absolute limits
if(drift > std::chrono::microseconds(400)) drift = std::chrono::microseconds(400);
if(drift < std::chrono::microseconds(-400)) drift = std::chrono::microseconds(-400);
ptp::scalednanoseconds drift_diff = drift - getDrift();
if(drift_diff == std::chrono::seconds(0)) {return;} // nothing to do
// check for limit per change
if(drift_diff > std::chrono::nanoseconds(40000)) drift_diff = std::chrono::nanoseconds(40000);
if(drift_diff < std::chrono::nanoseconds(-40000)) drift_diff = std::chrono::nanoseconds(-40000);
auto driff_f = std::chrono::duration_cast<std::chrono::duration<double, std::nano>>(drift_diff).count();
auto value = static_cast<std::uint64_t>(magic_factor * std::abs(driff_f));
auto values = std::vector<std::uint8_t>(5, 0x00);
std::copy(reinterpret_cast<std::uint8_t *>(&value),reinterpret_cast<std::uint8_t *>(&value)+5, values.rbegin());
writeRegs(ptp::ti::Register::DPLL2_FBFDEV_BY4, values);
// if we have a positive drift, the PLL has to be slowed down 1 is decrement, 0 is increment speed
std::uint32_t direction = drift_diff.count() > 0 ? 1: 0;
writeReg(ptp::ti::Register::DPLL2_FBFDEVUPDATE, direction);
m_currentDrift = m_currentDrift + drift_diff;
}