AD9371 系列快速入口
AD9371+ZCU102 移植到 ZCU106 : AD9371 官方例程构建及单音信号收发
ad9371_tx_jesd -->util_ad9371_xcvr接口映射: AD9371 官方例程之 tx_jesd 与 xcvr接口映射
AD9371 官方例程 时钟间的关系与生成 : AD9371 官方例程HDL详解之JESD204B TX侧时钟生成(一)
JESD204B相关IP端口信号 : AD9371 官方例程HDL JESD204B相关IP端口信号
裸机程序配置 AD9528、AD9371、FPGA IP: AD9371 官方例程裸机SW 和 HDL配置概述(一)
裸机程序配置 AD9528、AD9371、FPGA IP: AD9371 官方例程裸机SW 和 HDL配置概述(二)
裸机程序配置 AD9528、AD9371、FPGA IP: AD9371 官方例程裸机SW 和 HDL配置概述(三)
后续重心会转移到算法上,本篇算 AD9371 系列的一个小结,前后也花费了近一个月时间,学习了JESD204B、GTH、ADI官方HDL和裸机驱动 等,还有一些内容用文字记录太麻烦,有时间再整理。
有所帮助的话,多多点赞、关注,感谢!
接 AD9371 官方例程 NO-OS 主函数 headless 梳理(一),DAC(TX) 对于FPGA 是 framer ,对于AD9371是 Deframer 。ADC时相反。
执行 MCS 时发送的 SYSREF 脉冲用于多个AD9371之间的多芯片同步,但由于 【6.4节执行 MCS】 代码运行时 AD9371 的 framers/deframers 还不能接收 SYSREF 信号 。并且 FPGA 中 JESD204B 的物理层 和 链路层等IP还未使能,不能工作,所以确定性延时这一步并未完成,还需要 SYSREF 脉冲来复位同步 AD9371和FPGA链路层中的LMFC,以保证确定性延迟。
Rx和ORx Framer 忽略 SYSREF (enable = 0),令enable = 1,允许设备外部的SYSREF(AD9528)到达 Rx 和 ORx framer 中的SYSREF输入端口,等待 SYSREF,以便开始从 AD9371的 Rx和ORx Framer 传输 CGS (K码)
MYKONOS_enableSysrefToRxFramer(&mykDevice,1)
MYKONOS_enableSysrefToObsRxFramer(&mykDevice,1)
对 Deframer 复位 ,来清除之前检测到的 disparity bit 错误。并且如果FPGA内部的SERDES锁相环复位,则可能导致lane fifo 上溢/下溢,也需要复位 Deframer
MYKONOS_enableSysrefToDeframer(&mykDevice,0)
MYKONOS_resetDeframer(&mykDevice)
adxcvr_write(xcvr, ADXCVR_REG_RESETN, 1),解除 JESD 物理层 ip 复位信号,使其逻辑工作,up_resetn 为1后,等几个时钟后,up_pll_rst 变为 0,其连接QPLL,QPLL0RESET (up_qpll_rst), 0 复位失效,使物理层QPLL 工作 ,RX 类似,CPLLPD (up_cpll_rst), adxcvr_clk_enable(rx_adxcvr) CPLL解除复位
if (up_rstn == 0) begin
up_resetn <= 'd0;
end else begin
if ((up_wreq == 1'b1) && (up_waddr == 10'h004)) begin
up_resetn <= up_wdata[0];
end
adxcvr_clk_enable(tx_adxcvr);
axi_jesd204_tx_write(jesd, JESD204_TX_REG_LINK_DISABLE, 0x0),解除链路层复位信号 ,up_reset_core 为 0 后,解除 core_reset_all 复位信号,进而 core_reset 变为0,解除 链路层主逻辑 axi_ad9371_tx_jesd/tx IP 的复位信号,JESD 链路层主逻辑开始工作,现在 FPGA 中的 JESD 链路层和物理层已经开始工作,链路中的 serializer 可以输出 K 字符(CGS)
12'h030: up_reset_core <= up_wdata[0];
core_reset_vector <= {1'b0,core_reset_vector[4:1]};
core_reset = core_reset_vector[0];
axi_jesd204_tx_lane_clk_enable(tx_jesd);
允许设备外部的SYSREF(AD9528)到达 AD9371 的 TX Deframer 中的SYSREF输入端口,等待 SYSREF脉冲,完成 [ AD9371 的 Deframer 和 FPGA 中TX链路层 ] 各自的LMFC 同步复位,保证 DAC 链路的 确定性延迟
同时 AD9371 的 Rx和ORx Framer 开始传输 K 字符(CGS )
MYKONOS_enableSysrefToDeframer(&mykDevice,1)
AD9528_requestSysref(clockAD9528_device, 1);
no_os_mdelay(1);
同TX,使能 FPGA中RX和RX_OS 链路层和物理层的 主逻辑,使其工作,但对链路层而言,由于还没有接收到 SYSREF 脉冲 ,链路将保持在CGS状态。
adxcvr_clk_enable(rx_adxcvr);
axi_jesd204_rx_lane_clk_enable(rx_jesd);
adxcvr_clk_enable(rx_os_adxcvr);
axi_jesd204_rx_lane_clk_enable(rx_os_jesd);
请求SYSREF脉冲,完成 [ AD9371 RX和RX_OS framer 和 FPGA 中RX和RX_OS 链路层 ] 各自的LMFC 同步复位,保证 ADC 链路的 确定性延迟
AD9528_requestSysref(clockAD9528_device, 1);
no_os_mdelay(1);
AD9528_requestSysref(clockAD9528_device, 1);
no_os_mdelay(5);
这时 [ AD9371 的 Deframer 和 FPGA 中TX链路层 ] 各自的LMFC 在之前的 SYSREF 脉冲已经完成同步复位,新请求的 这两次 SYSREF脉冲是否会影响 之前已经同步好的 LMFC ?
不会影响 , 后续AD9528产生的 SYSREF 和 LMFC 是对齐的,不会在 LMFC 计数中间 抓到 sysref_edge ,导致其LMFC 计数清零,新的 SYSREF脉冲 对同步好的 LMFC没有影响。
下面对AD9528做些测试
sysref_edge:抓取到的 SYSREF 上升沿
lmfc_clk:抓到第一次 SYSREF 后产生的 lmfc 时钟
lmfc_edge:抓到第一次 SYSREF 后产生的 lmfc 边沿
sysref_alignment_error: lmfc 计数器和 sysref_edge 对齐错误标志,当LMFC和SYSREF频率是整数倍关系时,必然不会拉高
if (sysref_edge == 1'b1 && lmfc_active == 1'b1 &&
lmfc_counter_next != cfg_lmfc_offset) begin
sysref_alignment_error <= 1'b1;
end
随机请求一次 SYSREF脉冲
sysref_alignment_error都没有拉高,同时经过 验证 AD9528 后续产生的 SYSREF脉冲 和 LMFC 频率满足整数倍关系
MYKONOS_readRxFramerStatus(&mykDevice,&framerStatus)
MYKONOS_readOrxFramerStatus(&mykDevice,&obsFramerStatus)
MYKONOS_readDeframerStatus(&mykDevice,&deframerStatus)
选择在 radioOn 状态期间使用哪些跟踪校准,必须在 radioOff 状态下设置
* enableMask | Bit description
* [0] | TRACK_RX1_QEC
* [1] | TRACK_RX2_QEC
* [2] | TRACK_ORX1_QEC
* [3] | TRACK_ORX2_QEC
* [4] | TRACK_TX1_LOL
* [5] | TRACK_TX2_LOL
* [6] | TRACK_TX1_QEC
* [7] | TRACK_TX2_QEC
* [8] | TRACK_TX1_DPD
* [9] | TRACK_TX2_DPD
* [10] | TRACK_TX1_CLGC
* [11] | TRACK_TX2_CLGC
* [12] | TRACK_TX1_VSWR
* [13] | TRACK_TX2_VSWR
* [16] | TRACK_ORX1_QEC_SNLO
* [17] | TRACK_ORX2_QEC_SNLO
* [18] | TRACK_SRX_QEC
uint32_t trackingCalMask = TRACK_ORX1_QEC | TRACK_ORX2_QEC | TRACK_RX1_QEC |
TRACK_RX2_QEC | TRACK_TX1_QEC | TRACK_TX2_QEC;
MYKONOS_enableTrackingCals(&mykDevice,trackingCalMask)
AD9371 转入 radio on 状态,使能的(之前配置的使能链路) Rx和Tx信号链 将上电,并且开始之前设置的跟踪校准,要退出 radio on 状态回到低功耗,可以使用 MYKONOS_radioOff() 函数。
MYKONOS_radioOn(&mykDevice)
Tx校准只有在 radioOn状态 ,并且 obsRx 路径设置为OBS_INTERNAL_CALS时,才能运行。通过下面函数在 radioOn 状态下启动或关闭Obs Rx信号链,先关闭当前 obsRx 路径,再更改到所需的 obsRx 路径
MYKONOS_setObsRxPathSource(&mykDevice,OBS_RXOFF)
MYKONOS_setObsRxPathSource(&mykDevice,OBS_INTERNALCALS)
CGS 顺利完成后,jesd204_rx_ctrl 控制其状态机进入 STATE_SYNCHRONIZED 状态 ,根据物理层GTH的接收通道提供的RXCTRL1 和3, (RXCTRL1 ( rx_disperr) 表示对应的接收字节有 disparity error),(RXCTRL3 (rx_not in table),表示对应接收字节 不是8B/10B 表里的有效字节),通过逻辑 ( phy_notintable | phy_disperr ) 确定当前接收有无发生错误,如果所有LANE 都发生错误,或着累积到设定的一定数目错误,jesd204_rx_cgs 控制其转到 CGS_STATE_INIT 状态
axi_jesd204_rx_watchdog 检查 RX 和 RX_OS 链路状态,如果 jesd204_rx_ctrl 在 STATE_SYNCHRONIZED 状态,而 jesd204_rx_cgs 在 CGS_STATE_INIT 状态,说明接收数据出现严重错误,控制链路进入 restart
axi_jesd204_rx_watchdog(rx_jesd);
axi_jesd204_rx_watchdog(rx_os_jesd);
axi_jesd204_rx_status_read(rx_jesd);
for (i = 0; i < rx_jesd->num_lanes; i++)
axi_jesd204_rx_laneinfo_read(rx_jesd, i);
axi_jesd204_tx_status_read(tx_jesd);
axi_jesd204_rx_status_read(rx_os_jesd);
for (i = 0; i < rx_os_jesd->num_lanes; i++)
axi_jesd204_rx_laneinfo_read(rx_os_jesd, i);
axi_dac_init(&tx_dac, &tx_dac_init);
通过 函数 axi_dac_write(dac, AXI_DAC_REG_RSTN,AXI_DAC_MMCM_RSTN | AXI_DAC_RSTN) 使 up_resetn由0变成 1 ,进而 up_core_preset 1 变 0,up_core_preset 传递给 dac_rst (高电平复位),使FPGA中的JESD传输层 部分逻辑使能,退出复位状态 。mmcm_rst 信号暂未使用
axi_dac_init_finish(dac)获取DAC 时钟。DAC CLK = ratio * LINK CLK(传输层时钟)。2T2R,DAC 速率和传输层时钟比值 = 32 * L / M / NP = 2; 后续通过 axi_dac_read(dac, AXI_DAC_REG_CLK_RATIO, &ratio) 获得比值
先得到传输层时钟速率,通过 100M 时钟基准计数 2^16,得到用传输层时钟计数的 freq 值,
LINK clock_hz = freq * 100M / 2^16 = freq *390625/ 2^8 = freq * 1525.8789,dac->clock_hz = LINK clock_hz *ratio
传输层时钟频率 freq 基于100Mhz axi_clk测量,有一定的抖动,得到的DAC 时钟 会有一些误差,只是为了调试目的。
设置DDS 频率 相位等参数,并选择 传输层组帧的数据源,比如 DDS DMA 等数据来源,例程中先默认选择的0,DDS
enum axi_dac_data_sel {
AXI_DAC_DATA_SEL_DDS,
AXI_DAC_DATA_SEL_SED,
AXI_DAC_DATA_SEL_DMA,
AXI_DAC_DATA_SEL_ZERO,
AXI_DAC_DATA_SEL_PN7,
AXI_DAC_DATA_SEL_PN15,
AXI_DAC_DATA_SEL_PN23,
AXI_DAC_DATA_SEL_PN31,
AXI_DAC_DATA_SEL_LB,
AXI_DAC_DATA_SEL_PNXX,
};
axi_dac_write(dac, AXI_DAC_REG_DATA_SELECT((i*2)+0), 0);
4'h7: dac_data <= pn15_data;
4'h6: dac_data <= pn7_data;
4'h5: dac_data <= ~pn15_data;
4'h4: dac_data <= ~pn7_data;
4'h3: dac_data <= 'h00;
4'h2: dac_data <= dac_dma_data_s;
4'h1: dac_data <= dac_pat_data_s;
default: dac_data <= dac_dds_data_s;
函数 axi_dac_write(dac, AXI_DAC_REG_SYNC_CONTROL, AXI_DAC_SYNC) 会将传输层主逻辑 复位几个时钟 ,再开始工作
使能 RX_OS 传输层之前,先把ObsRx 路径切换到 OBS_RX1_SNIFFERLO
axi_adc_init(&rx_adc, &rx_adc_init);
MYKONOS_setObsRxPathSource(&mykDevice,OBS_RX1_SNIFFERLO)
axi_adc_init(&rx_obs_adc, &rx_obs_adc_init);
官方例程默认使用 TX 传输层 产生的DDS 信号,可以设置 频率 相位 幅度,用 ILA 连接在 RX 的传输层 IP核输出,可以看到接收到的正弦波
axi_dac_data_setup(dac);
axi_dac_dds_set_frequency(dac, ((i*2)+0), 3*1000*1000);
axi_dac_dds_set_frequency(dac, ((i*2)+1), 3*1000*1000);
axi_dac_dds_set_phase(dac, ((i*2)+0), (i % 2) ? 0 : 90000);
axi_dac_dds_set_phase(dac, ((i*2)+1), (i % 2) ? 0 : 90000);
axi_dac_dds_set_scale(dac, ((i*2)+0), 50*1000);
axi_dac_dds_set_scale(dac, ((i*2)+1), 50*1000);
axi_dac_write(dac, AXI_DAC_REG_DATA_SELECT((i*2)+0), 0);
axi_dac_write(dac, AXI_DAC_REG_DATA_SELECT((i*2)+1), 0);