对AD9361的数据接口延迟设置的分析和记录

通过参看AD9361的寄存器说明手册,收发数据线的时钟和数据DELAY 各自是16级可调

打印出了NO-OS代码写006,007号寄存器的操作:

Hello World

lw:reg[6]=0x04
lw:reg[7]=0x70
lw:ad9361_dig_tune_rx

lw:ad9361_dig_tune_delay
lw:reg[6]=0x00
lw:reg[6]=0x01
lw:reg[6]=0x02
lw:reg[6]=0x03
lw:reg[6]=0x04
lw:reg[6]=0x05
lw:reg[6]=0x06
lw:reg[6]=0x07
lw:reg[6]=0x08
lw:reg[6]=0x09
lw:reg[6]=0x0a
lw:reg[6]=0x0b
lw:reg[6]=0x0c
lw:reg[6]=0x0d
lw:reg[6]=0x0e
lw:reg[6]=0x0f
lw:reg[6]=0xff
lw:reg[6]=0xfe
lw:reg[6]=0xfd
lw:reg[6]=0xfc
lw:reg[6]=0xfb
lw:reg[6]=0xfa
lw:reg[6]=0xf9
lw:reg[6]=0xf8
lw:reg[6]=0xf7
lw:reg[6]=0xf6
lw:reg[6]=0xf5
lw:reg[6]=0xf4
lw:reg[6]=0xf3
lw:reg[6]=0xf2
lw:reg[6]=0xf1
lw:reg[6]=0xf0
lw:reg[6]=0x00
lw:reg[6]=0x01
lw:reg[6]=0x02
lw:reg[6]=0x03
lw:reg[6]=0x04
lw:reg[6]=0x05
lw:reg[6]=0x06
lw:reg[6]=0x07
lw:reg[6]=0x08
lw:reg[6]=0x09
lw:reg[6]=0x0a
lw:reg[6]=0x0b
lw:reg[6]=0x0c
lw:reg[6]=0x0d
lw:reg[6]=0x0e
lw:reg[6]=0x0f
lw:reg[6]=0xff
lw:reg[6]=0xfe
lw:reg[6]=0xfd
lw:reg[6]=0xfc
lw:reg[6]=0xfb
lw:reg[6]=0xfa
lw:reg[6]=0xf9
lw:reg[6]=0xf8
lw:reg[6]=0xf7
lw:reg[6]=0xf6
lw:reg[6]=0xf5
lw:reg[6]=0xf4
lw:reg[6]=0xf3
lw:reg[6]=0xf2
lw:reg[6]=0xf1
lw:reg[6]=0xf0
lw:reg[6]=0x00
lw:reg[6]=0x01
lw:reg[6]=0x02
lw:reg[6]=0x03
lw:reg[6]=0x04
lw:reg[6]=0x05
lw:reg[6]=0x06
lw:reg[6]=0x07
lw:reg[6]=0x08
lw:reg[6]=0x09
lw:reg[6]=0x0a
lw:reg[6]=0x0b
lw:reg[6]=0x0c
lw:reg[6]=0x0d
lw:reg[6]=0x0e
lw:reg[6]=0x0f
lw:reg[6]=0xff
lw:reg[6]=0xfe
lw:reg[6]=0xfd
lw:reg[6]=0xfc
lw:reg[6]=0xfb
lw:reg[6]=0xfa
lw:reg[6]=0xf9
lw:reg[6]=0xf8
lw:reg[6]=0xf7
lw:reg[6]=0xf6
lw:reg[6]=0xf5
lw:reg[6]=0xf4
lw:reg[6]=0xf3
lw:reg[6]=0xf2
lw:reg[6]=0xf1
lw:reg[6]=0xf0
lw:ad9361_dig_tune_delay wit BE_VERBOSE : 
SAMPL CLK: 61440000 tuning: RX
  0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:
0:# o o o # # # # # o o o o o # # 
1:o o o o o O o o o o o # # # # # 
lw:gen the final delay : lw:reg[6]=0x50
lw:exit from ad9361_dig_tune_delay
lw:ad9361_dig_tune_tx

lw:ad9361_dig_tune_delay
lw:reg[7]=0x00
lw:reg[7]=0x01
lw:reg[7]=0x02
lw:reg[7]=0x03
lw:reg[7]=0x04
lw:reg[7]=0x05
lw:reg[7]=0x06
lw:reg[7]=0x07
lw:reg[7]=0x08
lw:reg[7]=0x09
lw:reg[7]=0x0a
lw:reg[7]=0x0b
lw:reg[7]=0x0c
lw:reg[7]=0x0d
lw:reg[7]=0x0e
lw:reg[7]=0x0f
lw:reg[7]=0xff
lw:reg[7]=0xfe
lw:reg[7]=0xfd
lw:reg[7]=0xfc
lw:reg[7]=0xfb
lw:reg[7]=0xfa
lw:reg[7]=0xf9
lw:reg[7]=0xf8
lw:reg[7]=0xf7
lw:reg[7]=0xf6
lw:reg[7]=0xf5
lw:reg[7]=0xf4
lw:reg[7]=0xf3
lw:reg[7]=0xf2
lw:reg[7]=0xf1
lw:reg[7]=0xf0
lw:reg[7]=0x00
lw:reg[7]=0x01
lw:reg[7]=0x02
lw:reg[7]=0x03
lw:reg[7]=0x04
lw:reg[7]=0x05
lw:reg[7]=0x06
lw:reg[7]=0x07
lw:reg[7]=0x08
lw:reg[7]=0x09
lw:reg[7]=0x0a
lw:reg[7]=0x0b
lw:reg[7]=0x0c
lw:reg[7]=0x0d
lw:reg[7]=0x0e
lw:reg[7]=0x0f
lw:reg[7]=0xff
lw:reg[7]=0xfe
lw:reg[7]=0xfd
lw:reg[7]=0xfc
lw:reg[7]=0xfb
lw:reg[7]=0xfa
lw:reg[7]=0xf9
lw:reg[7]=0xf8
lw:reg[7]=0xf7
lw:reg[7]=0xf6
lw:reg[7]=0xf5
lw:reg[7]=0xf4
lw:reg[7]=0xf3
lw:reg[7]=0xf2
lw:reg[7]=0xf1
lw:reg[7]=0xf0
lw:reg[7]=0x00
lw:reg[7]=0x01
lw:reg[7]=0x02
lw:reg[7]=0x03
lw:reg[7]=0x04
lw:reg[7]=0x05
lw:reg[7]=0x06
lw:reg[7]=0x07
lw:reg[7]=0x08
lw:reg[7]=0x09
lw:reg[7]=0x0a
lw:reg[7]=0x0b
lw:reg[7]=0x0c
lw:reg[7]=0x0d
lw:reg[7]=0x0e
lw:reg[7]=0x0f
lw:reg[7]=0xff
lw:reg[7]=0xfe
lw:reg[7]=0xfd
lw:reg[7]=0xfc
lw:reg[7]=0xfb
lw:reg[7]=0xfa
lw:reg[7]=0xf9
lw:reg[7]=0xf8
lw:reg[7]=0xf7
lw:reg[7]=0xf6
lw:reg[7]=0xf5
lw:reg[7]=0xf4
lw:reg[7]=0xf3
lw:reg[7]=0xf2
lw:reg[7]=0xf1
lw:reg[7]=0xf0
lw:ad9361_dig_tune_delay wit BE_VERBOSE : 
SAMPL CLK: 61440000 tuning: TX
  0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:
0:# # # # # # # # # # # # # # # # 
1:# # # o o o o o o O o o o o o o 
lw:gen the final delay : lw:reg[7]=0x90
lw:exit from ad9361_dig_tune_delay
ad9361_init : AD936x Rev 2 successfully initialized

我们看到主要的操作都在 ad9361_dig_tune_delay里面实施的。

看看ad9361_dig_tune_delay的实现:


static int32_t ad9361_dig_tune_delay(struct ad9361_rf_phy *phy,
		uint32_t max_freq, enum dig_tune_flags flags, bool tx)
{
	static const uint32_t rates[3] = {25000000U, 40000000U, 61440000U};
	uint32_t s0, s1, c0, c1;
	uint32_t i, j, r;
	bool half_data_rate;
	uint8_t field[2][16];
	printf("lw:ad9361_dig_tune_delay\n");
	if (((phy->pdata->port_ctrl.pp_conf[2] & LVDS_MODE) ||
	    !phy->pdata->rx2tx2))
	    half_data_rate = false;
	else
	    half_data_rate = true;

	memset(field, 0, 32);
	for (r = 0; r < (max_freq ? ARRAY_SIZE(rates) : 1); r++) {
		if (max_freq)
			ad9361_set_trx_clock_chain_freq(phy,
				half_data_rate ? rates[r] / 2 : rates[r]);

		for (i = 0; i < 2; i++) {
			for (j = 0; j < 16; j++) {
				/*
				 * i == 0: clock delay = 0, data delay from 0 to 15
				 * i == 1: clock delay = 15, data delay from 15 to 0
				 */
				ad9361_set_intf_delay(phy, tx, i ? 15 : 0,
						      i ? 15 - j : j, j == 0);
				field[i][j] |= ad9361_check_pn(phy, tx, 4);
			}
		}

		if ((flags & BE_MOREVERBOSE) && max_freq) {
			ad9361_dig_tune_verbose_print(phy, field, tx, -1, -1);
		}
	}

	c0 = ad9361_find_opt(&field[0][0], 16, &s0);
	c1 = ad9361_find_opt(&field[1][0], 16, &s1);

	if (!c0 && !c1) {
		ad9361_dig_tune_verbose_print(phy, field, tx, -1, -1);
		dev_err(&phy->spi->dev, "%s: Tuning %s FAILED!", __func__,
			tx ? "TX" : "RX");
		return -EIO;
	} else if (flags & BE_VERBOSE) {
		if (c1 > c0)
			ad9361_dig_tune_verbose_print(phy, field, tx, (s1 + c1 / 2), -1);
		else
			ad9361_dig_tune_verbose_print(phy, field, tx, -1, (s0 + c0 / 2));
	}
	printf("lw:gen the final delay : ");
	if (c1 > c0)
		ad9361_set_intf_delay(phy, tx, s1 + c1 / 2, 0, true);
	else
		ad9361_set_intf_delay(phy, tx, 0, s0 + c0 / 2, true);
	printf("lw:exit from ad9361_dig_tune_delay\n");
	return 0;
}

其实这里面的逻辑很简单,我们以006寄存器为例子,就是clk和data的先后延迟关系,

第一种情况是:将clk可以延迟0-15个单位(每个单位是大约是0.3ns)。

第一种情况是:将data可以延迟0-15个单位(每个单位是大约是0.3ns)。

这样就总共有32种情况了。

是否存在clk和data都设置延迟的情况,这实际是没有意义的。因为都延迟的话,实际有意义的仅仅是他们延迟的差值。具体而言,比如006设置为0XF9是就相当于:时钟CLK延迟15个单位,数据DATA延迟9个单位,那么他们之间的差值是6吧。就相当于0X60。

我们看到打印出来的代码设置了CLK的延迟是0和F这两种情况下列举例虽有DATA的延迟。

我们看到0X00....0X0F 很好理解,就是CLK不延迟,数据延迟0...15.

而看到0XFF...0XF0实际就是对应0X00...XF0。

 

其实有了32种情况以后确定一个合适的延迟数值的算法也是很明显和简单的:找几个连续的可用数值,取中间那个就OK。

比如:

 

SAMPL CLK: 61440000 tuning: RX
  0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:
0:# o o o # # # # # o o o o o # # 
1:o o o o o O o o o o o # # # # # 

lw:gen the final delay : lw:reg[6]=0x50

006 寄存器取的是0x50

 

0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:
0:# # # # # # # # # # # # # # # # 
1:# # # o o o o o o O o o o o o o 

007这里取的就是0X90

图中#是表示对应组合数据通路出错

o表示OK 没有错。O表示被选用的。我们看出O是位于多个o之间取一个中间数值。左右偏移5个数值(约和5*0.3ns)都是OK的。

 

不知道写这些代码的人是怎么想的,故意让代码看上去难以理解,这代码就是让人用,而不想让你学明白,从而保持对他们依赖。

查看打印出来的代码实际可以看到进行了三轮测试,某一延迟设置只要有一轮数据不对应就会设置对应filed为1,标志该位出错不能用。 

另外考虑到AD9361本身支持BIST各种测试和校验,自行编写一个设置寄存器的程序不是很难。

还有一个问题就是如果BBPLL或者一些滤波配置的一些参数设置进行了修改导致了SAMPLE 发生了变化,是否需要调整这个已经校准好的006 和007寄存器呢。带着这个问题我也做了一个实验:我做了LOGO文件,修改RX_SAMPLE_RATE和TX_SAMPLE_RATE后发现006和007寄存器没有被修改。另外从理论角度,修改此两个寄存器就是为了满足数据采集的RX_DATA,TX_DATA部分数据采集时间,这两个时间都是硬确定的,不以频率大小为转移的。而输出端的TCO时间也一个确定的数值,是由芯片内部布线延迟和逻辑延迟所确定的,再加上PCB上线的长度是确定,所以延迟也确定,因此这个数据确定就可以不变了。

进一步推论,这个数据实际可以在产品中却行下来,之后写死。你可能会说不通时候编译FPGA的结果也可能是会有差别。是的别忘记咱们得到的数据本身就是有很大荣誉的。从这个例子看,前后差别1ns(3个延迟单位)是没有问题的。这样就使得问题得到了简化:在设计时候时候我们让外设提供一个简单的输入006寄存器内容的方法,确定好一个稳定的中间值。之后在后续的程序里面直接使用这个数值就好。问题简化!

以上对006寄存器的讨论同样适用于寄存器007.

这里使用的平台是ZEDBOARD+AD9361。REG[006]=0X50,REG[007]=0X90这个配置应该是适合这个套硬件的。根据我们之上大胆的分析以后可以直接这样用。因此在使用纯PL生成SPI 接口的寄存器配置时候,可以直接设置.

如果使用配置界面,则配置如下图红框处:

 

以上!

 

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值