文章目录
1 问题描述
对于需要多片AD9361同步采集的应用,例如在进行波束形成、DOA估计、MIMO等应用时,需要对所有的收发通道进行同步,保证在收发的逻辑上不会引入相位差,否则将导致误差。AD9361的同步过程可以分为基带同步和相位同步,对于基带同步,可以使用AD9361支持的多设备同步机制(multiple chips synchronization, mcs),通过硬件参考时钟和软件触发来实现多个设备同步;对于相位同步,也被称之为本振同步,虽然AD9361芯片本身没有内部的相位同步机制,但是可以使用测量相位差,后续进行补偿的方式进行同步。
2 AD9361的时钟架构
AD9361的简化框图如图所示,参考时钟(REF_CLK)从左边的XTALP
和XTALN
引脚输入,经过3个PLL频率合成器生成3路所需要的时钟。PLL采用小数N分频器设计,意味着可以通过编程的方式,从参考时钟生成需要的时钟频率。输出的3路时钟分别为:
- RX接收本振,可编程的输出范围是70 MHz - 6 GHz,与RXLO引脚输入的外部本振共同MUX产生最终的RX本振。
- TX发射本振,与RX的结构类似,并且用于生成TXLO的PLL与RXLO的PLL完全相同。
- BB基带相关信号时钟,提供ADC和DAC的采样时钟、并行数据输出时钟(DATA_CLK),可编程的输出范围715 MHz - 1430 MHz。
- 产生ADC采样频率:25 - 640 MSPS,最大值Rx=61.44 MSPS
- 产生DAC采样频率:320 MSPS,最大值Tx=61.44 MSPS
上面提到,LO时钟除了可以由PLL产生,还可以由外部引脚输入,即RXLO和TXLO引脚,并经过MUX产生最终的LO信号。我们可以把由PLL产生的LO称为内部本振,由外部输入的LO称为外部本振(Ext LO),具体使用哪个由用户的配置决定,如果不使用外部本振,可以把对应的RXLO和TXLO引脚悬空。在后面可以看到,在AD-FMCOMMS3-EBZ评估板设计中,就是把RXLO和TXLO以TP点的方式悬空设计的,不支持本振同步。而在AD-FMCOMMS5-EBZ评估板中,则是由外部的板载PLL芯片AD5355产生本振,同步输入到RXLO和TXLO引脚,这种方式可以真正实现本振同步,相比内部本振的方式具有更高的时钟精度。
因此,对于多片AD9361的同步问题,可以拆解为两部分:
- 基带同步:首先是参考时钟同步,需要给多片AD9361输入相同的REF_CLK,其次是通过内部的mcs机制,分别同步AD9361内部的BB、BBPLL、RF模块,这个过程需要外部的处理器驱动AD9361的SYNC_IN引脚在合适的时候产生同步脉冲。
- 相位同步(本振同步):即RXLO和TXLO的同步,需要给多片AD9361输入相同的外部本振。这里可能有人会问,如果不使用外部本振,而是使用相同的REF_CLK时钟源,通过内部PLL生成LO可以实现本振同步吗?答案是不行的,因为尽管使用了相同的参考时钟,但是不同AD9361的内部PLL无法保证在同一时刻锁定输出,因此不能确保输出LO是同步的。
3 硬件设计
3.1 AD9361芯片DataSheet参数
与时钟相关的引脚:
引脚编号 | 引脚名称 | 描述 |
---|---|---|
XTALP, XTALN | M11, M12 | 参考时钟输入(差分)。可以选择由专用晶振或外部振荡器来提供。 当使用专用晶振时,连接到XTALN和XTALP中间。REF_CLK频率范围19MHz - 50MHz 当使用外部振荡器时,仅将其连接到XTALN,断开XTALP。REF_CLK频率范围10MHz-80MHZ |
RX_EXT_LO_IN | G1 | 外部的RXLO本振输入 |
TX_EXT_LO_IN | A12 | 外部的TXLO本振输入 |
SYNC_IN | H5 | 多器件同步引脚。用于同步多片AD9361的数字脉冲,应当在外部处理器中编写产生该信号的逻辑 |
3.2 AD-FMCOMMS3-EBZ评估板设计
节选部分AD-FMCOMMS3-EBZ评估板的官方硬件原理图,可以看到在XTALP和XTALN引脚中间,跨接了一个40 MHz的晶振。并且XTALN引脚通过一个隔直电容与外部参考时钟REF_CLK连接,对应于评估板上的SMA输入接口。
对于多器件同步引脚SYNC_IN,则是引出到FMC接口,并通过下拉电阻接地。当需要同步多片AD9361时,外部处理器可以通过在同一时刻拉高这些AD9361的SYNC_IN引脚,使得器件在同一时刻进行采样。
而外部本振输入引脚RX_EXT_LO_IN和TX_EXT_LO_IN,则是连接到TP(Test Point)点来引出,TP点在硬件上就是一个裸焊盘,不支持连接SMA连接器,因此对于AD-FMCOMMS3-EBZ评估板,不能像是输入REF_CLK一样输入外部本振。
参考链接:
AD-FMCOMMS3-EBZ Evaluation Board | Analog Devices
AD-FMCOMMS3-EBZ User Guide | Analog Devices Wiki
3.3 AD-FMCOMMS5-EBZ评估板设计
AD-FMCOMMS5-EBZ评估板直接在同一块板上集成了2片AD9361,并且板载PLL芯片ADF5355,支持为两片AD9361提供外部本振输入信号。为方便分析,我把AD-FMCOMMS5-EBZ评估板原理图中关于时钟的部分单独摘除了出来,画成了下方的框图,借助框图可以非常清晰地看到多片AD9361的同步过程:
- 由40MHz晶振或外部REF_CLK输入参考时钟,给ADCLK846芯片。这个芯片是一个时钟缓冲器,主要作用就是将一路时钟复制为多路输出(LVDS或CMOS),同时提供低抖动(jitter)和噪声。输入的REF_CLK被分为3份:
- XTALN_to_A, XTALN_to_B:多片AD9361的参考时钟。
- 5355_REF_IN:ADF5355的输入参考时钟,用于生成多片AD9361的外部LO输入。
- REF_CLK_N, REF_CLK_P:返回FMC连接器,输入到外部FPGA处理器中,以便生成SYNC_IN信号。也就是把REF_CLK告知给FPGA,由FPGA在REF_CLK的上升沿将SYNC_IN信号输入给AD9361。这一部分是由软件控制完成的。
- ADF5355根据参考时钟,产生系统所需要的外部LO信号,LO的具体频率由外部处理器的SPI进行写入。注意这里的时钟频率就发生变化量了,前面的参考时钟REF_CLK的频率典型值在40 MHz左右,属于基带时钟的范畴。而经过ADF5355后生成了本振,频率范围40 MHz - 6 GHz,属于射频信号的范畴。
- HMC744将ADF5355生成的LO信号复制为2份,分别给到两片AD9361。
我们可以看到使用上面的时钟分配网络,理论上可以生成同步多片AD9361,只需要有足够多的时钟扇出缓冲,以及外部处理器需要有足够的控制引脚。至此,硬件的连线已经非常清晰了,下面的问题就是外部软件的设计,如何配置逻辑,在恰当的时刻assert生成SYNC_IN脉冲,实现多器件同步。
相关链接:
ADCLK846 Datasheet and Product Info | Analog Devices
HMC744 Datasheet and Product Info | Analog Devices
ADF5355 Datasheet and Product Info | Analog Devices
4 HDL设计
在system_top.v
中
module system_top (
input ref_clk_p;
input ref_clk_n;
output reg mcs_sync;
......
)
always @(posedge ref_clk or negedge sys_100m_resetn) begin
if (sys_100m_resetn == 1'b0) begin
mcs_sync_m <= 3'd0;
mcs_sync <= 1'd0;
end else begin
mcs_sync_m <= {mcs_sync_m[1:0], gpio_o[45]};
mcs_sync <= mcs_sync_m[2] & ~mcs_sync_m[1];
end
end
其中gpio_o[45]
用于产生脉冲,具体对应着PS中的GPIO定义#define gpio_sync 99
。由于GPIO是在PS端软件中的while循环中产生,相对于ref_clk
属于慢时钟域信号,因此需要一个同步器,把脉冲同步到ref_clk
的快始终域中,上面代码中的mcs_sync_ m
寄存器本质上是一个同步器,用于捕获gpio_o
的下降沿,并将其维持一个ref_clk
周期。
其中ref_clk
以差分的形式从FMC接口返回,并通过Buffer输出ref_clk
信号。
IBUFGDS i_ref_clk_ibuf (
.I (ref_clk_p),
.IB (ref_clk_n),
.O (ref_clk_s));
BUFR #(
.BUFR_DIVIDE ("BYPASS")
) i_ref_clk_rbuf (
.CLR (1'b0),
.CE (1'b1),
.I (ref_clk_s),
.O (ref_clk));
5 软件设计
需要注意的是,这里只考虑逻辑(No-OS)中是如何实现同步的,当然在Linux中也有对应的库来支持。
5.1 基带同步(MCS)
首先在进行器件初始化前,需要定义同步引脚main.c#L521。
default_init_param.gpio_sync = GPIO_SYNC_PIN
设置好所有相关参数后,分别对两片AD0361进行器件初始化:
ad9361_init(&ad9361_phy, &default_init_param);
ad9361_init(&ad9361_phy_b, &default_init_param);
其次需要执行ad9361_do_mcs
函数即可完成同步。
#ifdef FMCOMMS5
ad9361_do_mcs(ad9361_phy, ad9361_phy_b);
#endif
ad9361_do_mcs()
函数的实现位于ad9361_api.c
中,核心代码如图所示:
int32_t ad9361_do_mcs(struct ad9361_rf_phy *phy_master, struct ad9361_rf_phy *phy_slave)
{
uint32_t ensm_mode;
int32_t step;
int32_t reg;
// 读取ad9361-phy的时钟延迟,写入ad9361-phy-b
reg = ad9361_spi_read(phy_master->spi, REG_RX_CLOCK_DATA_DELAY);
ad9361_spi_write(phy_slave->spi, REG_RX_CLOCK_DATA_DELAY, reg);
reg = ad9361_spi_read(phy_master->spi, REG_TX_CLOCK_DATA_DELAY);
ad9361_spi_write(phy_slave->spi, REG_TX_CLOCK_DATA_DELAY, reg);
ad9361_get_en_state_machine_mode(phy_master, &ensm_mode);
// 设为警报模式(Alert),停止数据传输,作同步前的准备
ad9361_set_en_state_machine_mode(phy_master, ENSM_MODE_ALERT);
ad9361_set_en_state_machine_mode(phy_slave, ENSM_MODE_ALERT);
for (step = 0; step <= 5; step++) {
ad9361_mcs(phy_slave, step);
ad9361_mcs(phy_master, step);
no_os_mdelay(100);
}
// 通过ensm_mode变量恢复同步之前的使用状态
ad9361_set_en_state_machine_mode(phy_master, ensm_mode);
ad9361_set_en_state_machine_mode(phy_slave, ensm_mode);
return 0;
}
注意:在每次更改基带PLL频率、FIR使能/失能、改变TX或RX的LO设置时,都需要重新执行ad9361_do_mcs
函数。
ad9361_mcs()
函数位于ad9361.c
中,核心代码:
int32_t ad9361_mcs(struct ad9361_rf_phy *phy, int32_t step)
{
// 定义位掩码,用于在以下阶段启用/关闭不同的模块
int32_t mcs_mask = MCS_RF_ENABLE | MCS_BBPLL_ENABLE |
MCS_DIGITAL_CLK_ENABLE | MCS_BB_ENABLE;
switch (step) {
// 阶段1:同步BBPLL模块(关闭TX和RX合成器,启用BB, BBPLL, RF模块)
case 1:
ad9361_spi_writef(phy->spi, REG_ENSM_CONFIG_2,
POWER_DOWN_TX_SYNTH | POWER_DOWN_RX_SYNTH, 0);
ad9361_spi_writef(phy->spi, REG_MULTICHIP_SYNC_AND_TX_MON_CTRL,
mcs_mask, MCS_BB_ENABLE | MCS_BBPLL_ENABLE | MCS_RF_ENABLE);
ad9361_spi_writef(phy->spi, REG_CP_BLEED_CURRENT,
MCS_REFCLK_SCALE_EN, 1);
break;
// 阶段2:通过GPIO控制SYNC_IN引脚生成同步脉冲
case 2:
if (!phy->gpio_desc_sync)
break;
/*
* NOTE: This is not a regular GPIO -
* HDL ensures Multi-chip Synchronization SYNC_IN Pulse Timing
* relative to rising and falling edge of REF_CLK
*/
no_os_gpio_set_value(phy->gpio_desc_sync, 1);
no_os_gpio_set_value(phy->gpio_desc_sync, 0);
break;
// 阶段3:同步DIGITAL_CLK模块(启用BB, DIGITAL_CLK, RF模块,关闭BBPLL)
case 3:
ad9361_spi_writef(phy->spi, REG_MULTICHIP_SYNC_AND_TX_MON_CTRL,
mcs_mask, MCS_BB_ENABLE | MCS_DIGITAL_CLK_ENABLE | MCS_RF_ENABLE);
break;
// 阶段4:再次通过生成SYNC_IN引脚生成同步脉冲
case 4:
if (!phy->gpio_desc_sync)
break;
no_os_gpio_set_value(phy->gpio_desc_sync, 1);
no_os_gpio_set_value(phy->gpio_desc_sync, 0);
break;
// 阶段5:关闭其他所有模块,只保留RF模块使能
case 5:
ad9361_spi_writef(phy->spi, REG_MULTICHIP_SYNC_AND_TX_MON_CTRL,
mcs_mask, MCS_RF_ENABLE);
break;
}
return 0;
}
总的来说,ad9361_mcs
函数通过多个步骤,完成单片AD9361芯片的同步过程:
- 在步骤1中关闭发射和接收合成器,配置MCS控制寄存器,启用各模块。
- 在步骤2和步骤3用于同步BBPLL模块:先开启BBPLL模块,步骤3通过GPIO控制同步脉冲的产生,输入到AD9361的SYNC_IN。
- 在步骤4和步骤5用于同步DIGITAL_CLK模块:先开启DIGITAL_CLK模块,步骤5产生SYNC_IN脉冲。
具体的在片内的同步过程是怎样进行的,可以查看UG-570 AD9361 Reference Manual Page 88。MCS控制寄存器的内容可以在UG671 AD9361 Register Map Reference Manual中查询到:这里主要用到了低4位。
、
- D3——MCS RF Enable:设置后使得RFLO在Alert模式下保持使能状态,从而保证多片AD9361的相位关系保持恒定。
- D2——MCS BBPLL Enable:同步多片AD9361的BBPLL,需要先写向该位bit 1,再下一阶段生成SYNC_IN脉冲。
- D1——MCS DIgital CLK Enable:同步多片AD9361的Digital CLK,必须在BBPLL同步后才能同步Digital CLK。同步过程与BBPLL一样,先向该位写bit 1,下一阶段生成SYNC_IN脉冲。
- D0——MCS BB Enable:同步多片AD9361的的基带。
5.2 本振同步(RF相位差补偿)
5.2.1 相位差测量
如上提到,AD9361本身不支持内部PLL的RFLO同步,也被称之为相位同步/相位对齐。有两种方法解决这个问题:
- 测量内部LO的相位差,并在FPGA中进行校正
- 使用外部LO。但是需要注意,即便使用了外部LO(例如FMCOMMS的板载ADF5355),最终的本振也不能理想同步,而是会有0或180度的相位差。(根据FMComms5 Phase Synchronization | Analog Devices Wiki)
FMCOMMS板载两个射频开关,允许将任意一个AD9361的TX接回到任意一个AD9361的RX,这样就可以使用一个AD9361的TX通道作为参考基准,分别连接到两片AD9361的RX,这样就能测量得到两片AD9361的RX通道相位差。或者以一个AD9361的RX通道作为基准,测量两片AD9361的TX通道相位差。
下面是计算AD9361-A和AD9361-B之间的RX通道相位差
Θ
R
X
\Theta_{RX}
ΘRX的过程:
首先让AD9361-A自发自收。信号经过A的TX链路的移相为
Θ
T
X
A
\Theta^A_{TX}
ΘTXA,经过模拟线路后回环到A的RX端口,在A的RX链路中产生移相为
Θ
R
X
A
\Theta^A_{RX}
ΘRXA。最终得到:
Θ
1
=
Θ
T
X
A
−
Θ
R
X
A
\Theta_1 = \Theta^A_{TX} - \Theta^A_{RX}
Θ1=ΘTXA−ΘRXA
然后切换开关,让AD9361-A发射信号,由AD9361-B接收信号。信号经过A的TX链路的移相为
Θ
T
X
A
\Theta^A_{TX}
ΘTXA,经过模拟线路后输出到B的RX端口,在B的RX链路中产生移相为
Θ
R
X
B
\Theta^B_{RX}
ΘRXB。得到:
Θ
2
=
Θ
T
X
A
−
Θ
R
X
B
\Theta_2 = \Theta^A_{TX} - \Theta^B_{RX}
Θ2=ΘTXA−ΘRXB
在处理器中存储相位差
Θ
1
\Theta_1
Θ1和
Θ
2
\Theta_2
Θ2,并进行计算即可得到AD9361-A和AD9361-B的RX通道相位差。可以看到由于我们选取了A的TX通道作为公共参考基准,因此在计算相位差的最终表达式中该部分被抵消了,从而得到A和B的RX通道相位差。保证公式成立的前提是,A的TX端口到达A的RX端口和B的RX端口需要路径等长匹配,否则在模拟域会引起额外的相移。
Θ
R
X
=
Θ
1
−
Θ
2
=
(
Θ
T
X
A
−
Θ
R
X
A
)
−
(
Θ
T
X
A
−
Θ
R
X
B
)
=
Θ
R
X
B
−
Θ
R
X
A
\Theta_{RX} = \Theta_1 - \Theta_2 = (\Theta^A_{TX} - \Theta^A_{RX}) - (\Theta^A_{TX} - \Theta^B_{RX}) \\ =\Theta^B_{RX} - \Theta^A_{RX}
ΘRX=Θ1−Θ2=(ΘTXA−ΘRXA)−(ΘTXA−ΘRXB)=ΘRXB−ΘRXA
计算TX通道的相位差的过程也是同理,只需要以A的RX通道为基准,如下所示:
Θ
T
X
=
(
Θ
T
X
A
−
Θ
R
X
A
)
−
(
Θ
T
X
B
−
Θ
R
X
A
)
\Theta_{TX} = (\Theta^A_{TX} - \Theta^A_{RX}) - (\Theta^B_{TX} - \Theta^A_{RX})
ΘTX=(ΘTXA−ΘRXA)−(ΘTXB−ΘRXA)
参考链接:Synchronizing multiple AD9361 devices | Analog Devices Wiki
5.2.2 相位补偿
以接收为例,得到两片AD9361的接收通道相位差 Θ R X \Theta_{RX} ΘRX后,以A为基准,对B的接收数据作相位补偿(校正),就可以实现相位对齐了。相位补偿有多种可以实现的方式,例如直接对基带信号进行移相等,官方提出了IQ Rotation和IQ Correction方法。这里简单介绍IQ Rotation的方法。
假设由B通道接收到的IQ信号为
I
(
t
)
=
c
o
s
(
ω
t
)
Q
(
t
)
=
s
i
n
(
ω
t
)
I(t) = cos(\omega t) \\ Q(t) = sin(\omega t)
I(t)=cos(ωt)Q(t)=sin(ωt)
我们的目的是让其移相
ϕ
=
−
Θ
R
X
\phi = -\Theta_{RX}
ϕ=−ΘRX,使得移相后的IQ信号与A对齐。
I
′
(
t
)
=
c
o
s
(
ω
t
+
ϕ
)
Q
′
(
t
)
=
s
i
n
(
ω
t
+
ϕ
)
I'(t) = cos(\omega t + \phi) \\ Q'(t) = sin(\omega t + \phi)
I′(t)=cos(ωt+ϕ)Q′(t)=sin(ωt+ϕ)
分解后可以得到
I
′
(
t
)
=
c
o
s
(
ω
t
)
×
c
o
s
(
ϕ
)
−
s
i
n
(
ω
t
)
×
s
i
n
(
ϕ
)
Q
′
(
t
)
=
s
i
n
(
ω
t
)
×
c
o
s
(
ϕ
)
+
c
o
s
(
ω
t
)
×
s
i
n
(
ϕ
)
I'(t) = cos(\omega t) \times cos(\phi) - sin(\omega t) \times sin(\phi) \\ Q'(t) = sin(\omega t) \times cos(\phi) + cos(\omega t) \times sin(\phi)
I′(t)=cos(ωt)×cos(ϕ)−sin(ωt)×sin(ϕ)Q′(t)=sin(ωt)×cos(ϕ)+cos(ωt)×sin(ϕ)
代入原始的IQ信号表达式:
I
′
(
t
)
=
I
(
t
)
×
c
o
s
(
ϕ
)
−
Q
(
t
)
×
s
i
n
(
ϕ
)
Q
′
(
t
)
=
I
(
t
)
×
s
i
n
(
ϕ
)
+
Q
(
t
)
×
c
o
s
(
ϕ
)
I'(t) = I(t) \times cos(\phi) - Q(t) \times sin(\phi) \\ Q'(t) = I(t) \times sin(\phi) + Q(t) \times cos(\phi)
I′(t)=I(t)×cos(ϕ)−Q(t)×sin(ϕ)Q′(t)=I(t)×sin(ϕ)+Q(t)×cos(ϕ)
接下来可以写为矩阵形式:
[
I
′
(
t
)
Q
′
(
t
)
]
=
[
cos
(
ϕ
)
−
sin
(
ϕ
)
sin
(
ϕ
)
cos
(
ϕ
)
]
[
I
(
t
)
Q
(
t
)
]
\left[ \begin{array}{c} I'\left( t \right)\\ Q'\left( t \right)\\ \end{array} \right] =\left[ \begin{matrix} \cos \left( \phi \right)& -\sin \left( \phi \right)\\ \sin \left( \phi \right)& \cos \left( \phi \right)\\ \end{matrix} \right] \left[ \begin{array}{c} I\left( t \right)\\ Q\left( t \right)\\ \end{array} \right]
[I′(t)Q′(t)]=[cos(ϕ)sin(ϕ)−sin(ϕ)cos(ϕ)][I(t)Q(t)]
至此,在RX接收信号后,只需要一个
2
×
2
2 \times 2
2×2的矩阵乘法就可以补偿接RX通道的相位。需要注意的是,在FPGA中定点实现时,这种方法可能会导致输出的幅值超出ADC的最大分辨率(最大量程),造成溢出。因此可以采用缩放的方式进行处理,具体方法参见I/Q Rotation | Analog Devices Wiki。
参考链接:
I/Q Rotation | Analog Devices Wiki
I/Q Correction | Analog Devices Wiki
参考链接
Synchronizing multiple AD9361 devices | Analog Devices Wiki
FMComms5 Phase Synchronization | Analog Devices Wiki
PDF | Phase Synchronization Capability of the Analog Devices FMComms5 and DoA Estimation
Digital Interface Timing Verification | Analog Devices Wiki
关于AD9361的多芯片同步的问题 - 数字IC设计讨论(IC前端|FPGA|ASIC) - EETOP 创芯网论坛 (原名:电子顶级开发网) -
I/Q Rotation | Analog Devices Wiki
I/Q Correction | Analog Devices Wiki