用microblaze搭配sdk配置AD9528芯片

AD9528是ADI(亚德诺半导体技术有限公司, Analog Devices, Inc. 简称ADI )出品的一款双级PLL,集成JESD204B SYSREF发生器,可用于多器件同步。

一级锁相环(PLL1):通过减少系统时钟的抖动,从而实现输入基准电压调理;

二级锁相环(PLL2):提供高频时钟,可实现来自时钟输出驱动器的较低积分抖动以及较低宽带噪声;

外部VCXO晶振(晶振频率范围:0~400MHz):提供PLL2所需的低噪声基准电压,以满足苛刻的相位噪声和抖动要求,实现可以接受的性能;

片内压控振荡器VCO:调谐频率范围为3.450 GHz至4.025 GHz;

集成的SYSREF发生器输出单次、N次或连续信号,并与PLL1和PLL2输出同步,以便对齐多个器件的时间。

AD9528的六路(channel0、channel1、channel2、channel3、channel12和channel13)输出最高频率可达1.25 GHz,剩余的八路输出最高频率可达1 GHz。每一路输出均可配置为直接从PLL1、PLL2或内部SYSREF发生器输出。14路输出通道的每一路都包含一个带数字相位粗调功能的分频器、一个模拟微调相位延迟模块,芯片的14路输出都具有时序对齐的高度灵活性。AD9528还可用作灵活的双通道输入缓冲器,以便实现14路器件时钟和/或SYSREF信号的分配。

芯片内部详细图解如下所示:

 一、VIVADO中micro blaze连线:

 二、SDK中代码配置步骤说明:

1、初始化SPI控制器:

	struct xil_spi_init_param xil_spi_param = {
		.type = SPI_PL,
		.device_id = 0,
	};
	ad9528_param.spi_init = clkchip_spi_init_param;

2、定义配置并关联结构体:

struct ad9528_dev* clkchip_device;

struct ad9528_channel_spec ad9528_channels[14];
struct ad9528_init_param ad9528_param;
struct ad9528_platform_data ad9528_pdata;

// ad9528 defaults
ad9528_param.pdata = &ad9528_pdata;
ad9528_param.pdata->num_channels = 14;
ad9528_param.pdata->channels = &ad9528_channels[0];

3、初始化参数配置,以及通过返回值判断是否配置正确:

	status = ad9528_init(&ad9528_param);
	if(status) {
		printf("error: ad9528_init() failed with %d\n", status);
    }

 4、PLL1、PLL2、输出通道使能、输出通道模式、输出通道分频等相关参数的配置,以及通过返回值判断是否配置正确:

	status = ad9528_setup(&clkchip_device, ad9528_param);
	if(status < 0) {
		printf("error: ad9528_setup() failed with %d\n", status);
		goto error_1;
	}
	else {
		printf("success: ad9528_setup() is succeed %d\n", status);
	}

三、部分配置程序说明:

1、PLL1 bypass:(主要是通过0X0108寄存器来进行配置,不需要REFA和REFB,用VCXO晶振作为PLL2的输入)

	/*PLL1 Setup*/
	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL1_REF_A_DIVIDER,
				 0X02
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL1_REF_B_DIVIDER,
				 0X02
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL1_FEEDBACK_DIVIDER,
				 0X02
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL1_CHARGE_PUMP_CTRL,
				 0X18
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL1_CTRL,
				 0X61);
	if (ret < 0)
		return ret;

 2、PLL2 配置:

	pll2_ndiv = dev->pdata->pll2_vco_div_m1 * dev->pdata->pll2_n2_div;
	if (!ad9528_pll2_valid_calib_div(pll2_ndiv)) {
		printf("Feedback calibration divider value (%u) out of range\n", pll2_ndiv);
		return -1;
	}

	pll2_ndiv_a_cnt = pll2_ndiv % 4;
	pll2_ndiv_b_cnt = pll2_ndiv / 4;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_CHARGE_PUMP,
				 0X49
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_FEEDBACK_DIVIDER_AB,
				 0X87
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_CTRL,
				 0X03
				 );
	if (ret < 0)
		return ret;

	vco_freq = div_u64((uint64_t)dev->pdata->vcxo_freq *
			   (dev->pdata->pll2_freq_doubler_en ? 2 : 1) * pll2_ndiv,
			   dev->pdata->pll2_r1_div);

	vco_ctrl = AD_IF(pll2_freq_doubler_en || dev->pdata->pll2_r1_div != 1,
			 AD9528_PLL2_DOUBLER_R1_EN);
	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_VCO_CTRL, //0x0203
				 0X05
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_VCO_DIVIDER,
				 0X03
				 );
	if (ret < 0)
		return ret;

	if (dev->pdata->pll2_vco_div_m1)
		dev->ad9528_st.vco_out_freq[AD9528_VCO] =
			vco_freq / dev->pdata->pll2_vco_div_m1;
	else
		dev->ad9528_st.vco_out_freq[AD9528_VCO] = vco_freq;

	dev->ad9528_st.vco_out_freq[AD9528_VCXO] = dev->pdata->vcxo_freq;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_R1_DIVIDER,
				 0X02
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_N2_DIVIDER,
				 0X09
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_spi_write_n(dev,
				 AD9528_PLL2_LOOP_FILTER_CTRL,
				 0X00
				 );
	if (ret < 0)
		return ret;
	ret = ad9528_spi_write_n(dev,
			AD9528_CHANNEL_PD_EN,
				 0XF5
				 );
	if (ret < 0)
		return ret;
	ret = ad9528_spi_write_n(dev,
				 AD9528_PD_EN,
				 0X10
				 );
	if (ret < 0)
		return ret;

	ret = ad9528_io_update(dev);
	if (ret < 0)
		return ret;

	if (dev->pdata->stat0_pin_func_sel != 0xFF) {
		ret = ad9528_spi_write_n(dev, AD9528_STAT_MON0,
					 0X0A
					 );
		if (ret < 0)
			return ret;

		stat_en_mask |= AD9528_STAT0_PIN_EN;
	}

	if (dev->pdata->stat1_pin_func_sel != 0xFF) {
		ret = ad9528_spi_write_n(dev, AD9528_STAT_MON1,
					 0X03
					 );
		if (ret < 0)
			return ret;

		stat_en_mask |= AD9528_STAT1_PIN_EN;
	}

	if (stat_en_mask) {
		ret = ad9528_spi_write_n(dev, AD9528_STAT_PIN_EN,
					 0X0C
					 );
		if (ret < 0)
			return ret;
	}

	ret = ad9528_io_update(dev);
	if (ret < 0)
		return ret;

3、通道分频配置(参数初始化配置的时候就设置好了各个通道需要的分频系数):

    for (i = 0; i < init_param->pdata->num_channels; i++) {
		(&init_param->pdata->channels[i])->channel_num = 0;
		(&init_param->pdata->channels[i])->sync_ignore_en = 0;
		(&init_param->pdata->channels[i])->output_dis = 0;
		(&init_param->pdata->channels[i])->driver_mode = DRIVER_MODE_LVDS;
		(&init_param->pdata->channels[i])->signal_source = SOURCE_VCO;
		(&init_param->pdata->channels[i])->divider_phase = 0;
		(&init_param->pdata->channels[i])->channel_divider = 10;
	}

4、判断配置是否成功:

1)、通过上面提及到的每个函数的返回值来判断是否配置正确;

2)、芯片上有两个状态信号,这里我是直接连到了板子上的两个LED灯,并通过灯的亮灭状态来判断PLL2是否锁定;

3)、用示波器点测通道是否能正确输出所配置的时钟频率大小。

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值