零基础学习笔记 - ADF4159

1.准备工作

1.1.前言

  • 最近在学习ADF4159, 感觉受益匪浅, 有必要记录下来, 以免日后忘记. 也是为了帮助后人.
  • 我默认读者你, 已经掌握了单片机的使用方法, 包括不限于熟用寄存器, 了解时钟树.
  • 另外, 因为我对雷达/高频/傅里叶等了解不深, 所以本文对专业术语的表达解释很可能不够严谨, 甚至是错的. 如果有大佬发现, 请理性清楚地在评论区提出, 我看到后会立刻修改. 提前谢谢.
  • 因此,本笔记止步于基础应用,更多高级应用并未涉及!

1.2.资料

1.3.介绍

  • 官方介绍 ADF4159直接调制/快速波形产生13 GHz小数N分频频率合成器, 由低噪声数字鉴频鉴相器(PFD),精密电荷泵和可编程参考分频器组成.
  • 调制? 专业术语,具体百度, 这里我简单理解就是调频/相/幅.
  • 快速波形产生? 这里我简单理解就是可以快速产生周期波形.
  • 小数N分频?一般分频都是整数,而且还是2个倍数,简单理解就是分频系数可以是小数.
  • 鉴频鉴相器(PFD)?专业术语,具体百度,这里我简单理解,输入2个信号a与b,输出a与b的频/相差值,一般输入为参考信号和采集信号,如果采集信号不等于参考信号就有差值,把这个频率差值和相位差值返回.就是一个闭环系统中最重要的反馈部分,
  • 精密电荷泵,这个是我完全没概念,就不比喻了.应用中有参考值,我是直接用参考值.
  • 可编程参考分频器,这里我简单理解就是输入的参考频率可以分频.这个功能貌似挺基本的.

1.4.应用

  • 手册介绍了一堆,我也没看懂到底是干嘛的.因为很多专业术语没看懂.
  • 我这里简单理解一下, 其实就是一个信号发生器,可以生成指定信号,这个信号可以是固定幅值,也可以是周期变化幅值.这个信号可以是固定频率,也可以是周期变化频率.
  • 也就是PPL(锁相回路或锁相环),专业术语,具体百度.如果你熟用配置单片机时钟树,应该不对这个词不陌生.单片机的系统时钟一般可由外/内的高/低速时钟提供,但这些都是固定的,正常更加希望不一样的时钟频率,这时就用到PLL,将固定的时钟通过分频得到想要的时钟频率.
  • 总结:简单理解就是ADF4159的功能就是可以将参考频率按小数分频输出,同时支持反馈,形成闭环.

1.5.应用电路

在这里插入图片描述

  • 上图是官网下载的参考应用电路框图.左上就是ADF4159,用于产生频率信号并输出CP.右上就是环路滤波器,最简单的滤波电路就是电容电阻,上图使用的是运放组合.下中就是VCO(压控振荡器).频率信号走一圈后返回输入RFIN,作闭环反馈.
  • 环路滤波器?专业术语,具体百度.这里我简单理解,就是滤波用的,不然信号噪声会很大.简单点理解就是有助于信号稳定.问题就是这个滤波电路怎么设计和选择.手册里对于这部分的设置与设计有较多的说明,但我看不懂,所以是直接抄典型方案的.
  • VCO(压控振荡器)?专业术语,具体百度.之前只接触过晶振(晶体振荡器),可以类比理解.根据图来理解,它的作用就是接受一个输入VTUNE,然后输出RFOUT,同时返回输出的n分频RFOU0T/2.因为ADF4159最大工作频率在13GHz以内,如果临近或超过这个数值的,就需要有分频功能的VCO.
  • 比如ADF4159工作在1GHz,输出CP输入RFIN都是1GHz的信号,这时用2分频VCO,那输出RFOUT就是2GHz.
  • 调频(变化频率)同理. 比如ADF4159工作在12GHz,`输出CP`和`输入RFIN`都是12GHz的信号,这时用2分频VCO,那输出RFOUT就是2~4GHz.
  • 因为我的电路和高频知识不足,对环路滤波器,VCO(压控振荡器)的解释并不完全正确,我只能从应用角度解释.我也不会设计电路方案.所以下面都是照抄官方提供的例子 .本教程着重ADF4159的应用,主要还是寄存器配置讲解.

2.ADF4159

2.1.功能框图

在这里插入图片描述

  • 先从手册的第一页的功能框图理解,ADF4159的工作过程.
  1. 输入参考频率, 然后进行5位分频,在分频可选择进行一次2倍频,在分频可选择进行一次2除频;
  2. 通讯输出引脚, 可以选择输出不同内容,包括正负极电压,各个频率,和寄存器内容.
  3. 通讯输入引脚, 包括功能控制,使能,数据,时钟等.用于和模块内的32位寄存器读写通讯.
  4. 输出频率信号. 利用参考频率和反馈频率,生成输出频率.就是上面提到的鉴频鉴相器(PFD=PHASE FREQUENCY DETECTOR);
  5. 输入反馈信号, 将反馈信号小数分频,然后输入到PFD中.
  • 寄存器中主要需要配置的内容,基本都在上面的框图中了.其他属于特殊高级功能或是VCO环路滤波器用到的,我一律采用例程参考值,也就是0,设置为不开启或是默认.

2.2.通信协议时序

  • 手册有贴出时序图,想研究的可以自己看.我就不解释了.

在这里插入图片描述
在这里插入图片描述

  • 官方参考例程有驱动代码,直接复制粘贴就可以了,如果没通讯上改一下软件延时就好了.
  • 这个模块读数据有点特殊,就是固定37位的(?)上面的读取时序示意图.不过使用时比较少读取它的寄存器数据,而是读时钟之类的触发信号.
  • 可以直接把官方例程修改后烧进去测试板,测试能不能读取ADF4159的返回数据,且输出有没有波形.如果都正常就代表驱动这部分没有问题.
// 下面内容为官方例程,我修改了小部分排版等内容.
void GET_MUXOUT(){} // 获取数据输出引脚的电平
void SET_CE(){} // 和使能引脚的控制
void CLR_CE(){}
void Delay(){} // 可有可无的软件延时

void SET_SCLK(){} // 时钟
void CLR_SCLK(){}
void SET_LE(){} // 读写控制
void CLR_LE(){}	
void SET_DATA(){} // 写数据
void CLR_DATA(){}
void SET_TxDATA(){} // 读数据控制
void CLR_TxDATA(){}

// Write 
void ADF4159_Write(unsigned long ulDACValue)
{
	unsigned long SendValue = 0;
	unsigned int i = 0;
	CLR_SCLK();	
	SendValue = ulDACValue;
	CLR_LE();	                                 		 //bring LE low
	Delay(0x5);	
 
	for(i=0;i<32;i++)
	{
		if(SendValue&0x80000000)
		 	SET_DATA();			                         //Send 1 to DATA pin
		else
		 	CLR_DATA();			                         //Send 0 to DATA pin
		Delay(0x50);	
		SET_SCLK();                                //SCLK rising		
		Delay(0x50);
		CLR_SCLK();					                     	 //SCLK falling	
		SendValue <<= 1;	                         //Rotate data
	}

	SET_LE();	                                 		//bring LE high again
	Delay(0x50);	
}

// Read. Return 40-bit, the 37-bit MSB includes the 12-bit integer word and 25-bit FRAC word. 								
unsigned long long ADF4159_Read(void)
{
	unsigned long long ulValue = 0;
	unsigned long long ulData = 0; 
	unsigned long long BitIN = 0; 	 
	unsigned int i = 0;
	CLR_TxDATA();
	CLR_SCLK();
	Delay(0x20);
	SET_LE();
	SET_TxDATA();
	Delay(0x50);
	CLR_TxDATA();
	
	for(i=0;i<37;i++)
	{
		SET_SCLK();                              //SCLK rising
		Delay(0x5);
		BitIN=GET_MUXOUT(); // 例程这里是读取单片机的gpio寄存器以获取引脚电平,我规范一下
		ulValue+=BitIN;
	
		Delay(0x45);		     
		CLR_SCLK();					                     //SCLK falling
		Delay(0x50);
		if(i==36)
		{}
		else 
			ulValue <<= 1;	 
	}
	
	CLR_LE();
	ulData = ulValue<<3;											//ulData is 40-bit
	return ulData;
}

2.2.寄存器

  • 确认通讯没有问题就开始理解寄存器配置了. 总共有7个寄存器,需要配置的不多,所以我讲解一遍.

2.2.0.注意

  1. 寄存器中有很多没有使用的保留位RESERVED,手册会说明需要配置为0或1,大部分都是0.

  2. 寄存器的选择,是通过32位的低3位决定.

在这里插入图片描述

  1. 模块(上电)初始化时,需要对7个寄存器都配置一遍.特别是R6/5/4,这3个寄存器需要发送2次数据.而这个STEP/DEV/CLKDIV SEL位,在手册的寄存器说明中,很奇葩是这样描述的:位DB23置0时,选择步进字1.位DB23置1时,选择步进字2; 位DB23置0时,选择第一个偏差字.位DB23置1时,选择第二个偏差字;将位DB6设为0后,CLK2便用作标准斜坡的CLK2值.将位DB6设为1后,CLK2便用作快速斜坡或双斜坡功能的第二斜坡CLK2值.导致我一开始看得一头雾水,找半天找不到所指的内容.回来才知道改变不是描述的那回事.并不是用于选择内容,而是用于固定初始化的.

在这里插入图片描述

  1. 除了初始化很奇怪外,再初始化之后,如果希望单独修改某个寄存器的数据,也有特殊操作,也需要连续写入2次,参考官方例程中的代码.一般我使用是固定使用场景,即只会配置一次初始化参数,这样就不用考虑初始化后还要修改了.
// 截取例程中的一部分
R6=0x406;                   //R6-Ramp 1
ADF4159_Write(R6);
R6=0x800006;								 //R6-Ramp 2
ADF4159_Write(R6);
R5=0xC400805;
ADF4159_Write(R5);
R5=0xC800005;
ADF4159_Write(R5);	
R4=0x580184;
ADF4159_Write(R4);
R4=0x580144;
ADF4159_Write(R4);
R0=0xF81E0000;											//Set Muxout as READBACK TO MUXOUT
ADF4159_Write(R0);

在这里插入图片描述

2.2.1.延迟寄存器(R7)映射

  • 如其名,这个寄存器主要配置一些延时功能.启动延时之类的.
  • 我使用时没有这个需求.所以全部配置0.
#define DIV_ADF4159_R7()    (0x00000007)

这里是引用

2.2.2.步进寄存器(R6)映射

  • 主要是配置步进数,当设置输出信号周期变动频率时,就需要设置.
  • 就是指每个周期中,从最小频率到最大频率,分为几段.如果分的越多,步进数越大,那频率变化就越平缓.
  • 不要忘记还有个STEP SEL需要单独设置.
#define DIV_ADF4159_R6(STEP)    (0x00000006|(((STEP)&0xFFFFF)<<3))
#define DIV_ADF4159_R62()       (0x00800006)

在这里插入图片描述

在这里插入图片描述

2.2.3.偏差寄存器(R5)映射

  • 主要是配置偏差,当设置输出信号周期变动频率时,就需要设置.
  • 这里的偏差指每次变动的频率范围,即每次步进时跳变的频率,如果越小则代表变化越平滑.
  • 该寄存器的其他值属于特殊功能使用,我没有用到,所以全部设置0.
  • 不要忘记还有个DEV SEL需要单独设置.
#define DIV_ADF4159_R5(DEV_OFFSET, DEV)    (0x00000005|(((DEV_OFFSET)&0xF)<<19)|(((DEV)&0xFFFF)<<3))
#define DIV_ADF4159_R52()                  (0x00800005)

在这里插入图片描述

在这里插入图片描述

2.2.4.时钟寄存器(R4)映射

  • 主要是配置时钟,用于设置超时间隔,代表每两次步进之间的间隔,也就是每次频率保持多久后就改变.
  • 另外,根据功能需要,要配置斜坡状态 位DB[25:21]时钟分频器模式位DB[20:19],我要讲解连续变频三角波,所以这里我设定为0x00x3.
  • 不要忘记还有个CLK DIV SEL需要单独设置.
#define DIV_ADF4159_R4(CLK2)                                (0x00180004|(((CLK2)&0xFFF)<<7))
#define DIV_ADF4159_R42(CLK2)                               (0x00180044|(((CLK2)&0xFFF)<<7))

在这里插入图片描述
在这里插入图片描述

2.2.5.功能寄存器(R3)映射

  • 主要是配置功能,比如 斜坡模式, 关断 等. 其他一堆我也不会解释的专业术语和功能,略过.我们直接参考例程的设定值.
  • 根据手册描述,虽然部分功能没看懂,但是手册里会有一句: 如需使工作更稳定, 请将 xxx 设为1,这时一般就配置为1,其他不懂的用不到的功能都设置为0.又或者会有这样一句: 正常工作时, 此位应设置为0.这时就要配置0,一般就是作为使能开启的功能(?).
  • 注意:正常工作时, 除位DB17外的所有保留位必须设置为0. 位DB17必须置1才能正常工作.
#define DIV_ADF4159_R3(RAMP_MODE)                           (0x000280C3|(((RAMP_MODE)&0x3)<<10))

在这里插入图片描述

2.2.6.R分频器寄存器(R2)映射

  • 主要设置分频系数R,这个是用于设置PFD的正输入频率,也就是固定频率.这个频率由参考频率分频得到,这个分频系数就是R.
  • 回顾一下上面的框图①,就能更加生动的理解了.
  • 还有其他功能位我没用到,就不解释了,全部设置0.
#define DIV_ADF4159_R2(I_CP, P, D, R, CLK1)    (0x00000002|(((I_CP)&0xF)<<24)|(((P)&0x1)<<22)|(((D)&0x1)<<20)|(((R)&0x1F)<<15)|(((CLK1)&0xFFF)<<3))

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2.7.LSB FRAC寄存器(R1)映射

  • 主要设置低13位小数(LSB FRAC), 用于设置最终的输出频率,有个分频系数,是由整数和小数组成.小数共25位,这里记录了低13位.
#define DIV_ADF4159_R1(FRAC_LSB)    (0x00000001|(((FRAC_LSB)&0x1FFF)<<15))

在这里插入图片描述
在这里插入图片描述

2.2.8.FRAC/INT寄存器(R0)映射

  • 对应上一个寄存器,主要就是设置最终输出频率的分频系数,设置小数剩余的高12位,和整数12位.
  • 另外还有设置MUXOUT引脚的返回内容,和使能输出.
#define DIV_ADF4159_R0(RAMP_ON, MUXOUT, INT_12, FRAC_MSB)   (0x00000000|(((RAMP_ON)&0x1)<<31)|(((MUXOUT)&0xF)<<27)|(((INT_12)&0xFFF)<<15)|(((FRAC_MSB)&0xFFF)<<3))

在这里插入图片描述

2.2.9.总结

  • 功能框图寄存器描述, 对照着看可以加深理解, 结合手册的公式描述明白到底设置了什么.
  • 最后结合实际的仿真例子,再自己计算一遍,基本就能掌握基础应用了.就是这样一个学习思路.
  • 题外话, 安利(记录)一下,推荐几个宏定义使用,在GD32库中看到的,感觉很实用.
/* 枚举定义 */
typedef enum {DISABLE = 0, ENABLE = !DISABLE} EventStatus, ControlStatus; // 失能和使能
typedef enum {RESET = 0, SET = !RESET} FlagStatus; // 复位和置位
typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrStatus; // 错误和成功

/* 位操作 */
#define VAR32(var)                   (REG32(&var)) // 按32位读取,值的地址
#define VAR16(var)                   (REG16(&var))
#define VAR8(var)                    (REG8(&var))

#define REG32(addr)                  (*(volatile uint32_t *)(uint32_t)(addr)) // 按32位读取,地址
#define REG16(addr)                  (*(volatile uint16_t *)(uint32_t)(addr))
#define REG8(addr)                   (*(volatile uint8_t *)(uint32_t)(addr))

#define BIT(x)                       ((uint32_t)((uint32_t)0x01U<<(x))) // 返回指定x位为1的数据,x从0开始
#define BITS(start, end)             ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end)))) // 返回指定(end-start+1)位为1的数据,包含end和start,end大于或等于start,end和start从0开始

#define GET_BIT(regval, x)           (((regval) & BIT(x)) >> (x)) // 返回指定x位的数据,x从0开始
#define GET_BITS(regval, start, end) (((regval) & BITS((start),(end))) >> (start)) // 返回指定(end-start+1)位的数据,包含end和start,end大于或等于start,end和start从0开始

3.ADIsimPLL

  • 找到官方推出的仿真软件,如下.
  • 初次安装软件第一次打开会有一个软件介绍和新手教程,快速下一步跳过即可.
    在这里插入图片描述
  • 我刚开始学时全网只找到这篇仿真教程,贴出来感谢作者;
    基于ADISimPLL的ADF4159连续调频波仿真: https://ez.analog.com/cn/other/f/forum/56433/adisimpll-adf4159

3.1.RF频率合成器 一个成功范例

  • 手册里有一段最简单的范例,只介绍了输出频率的计算方法.

在这里插入图片描述

  • 我们在仿真软件中实现,先看看GIF图的设置过程;大部分都是默认下一步,

在这里插入图片描述

  1. 第一页是选择模块,选择ADF4159;
  2. 第二页是设置模块功能,第一个是选择输出周期变动频率,还是固定频率; 第二个是选择分频类型是整数还是小数,ADF4159支持小数,默认选择小数.
  3. 第三页是设置固定的输出频率,设置PDF的固定输入频率,然后下面2个勾选项分别是,第一个是vco是否分频,目前不需要; 第二个是设置参考时钟频率,后面再设置也可以.
  4. 第四页是选择vco,可以选择官方提供的模型库,但没必要,选择最下面的勾选项,代表理想vco,不设置参数.
  5. 第五页是模块参数,默认,略过;
  6. 第六页是过滤器的选择和设置,默认,略过;仿真认为信号都是理想的;
  7. 第七页是vco参数设置,默认即可;
  8. 第八页是参考时钟频率的设置;
  9. 第九页是滤波器的性能参数设置,最下面有个勾选项,用不到的,去掉;翻译是调制的意思,专业术语,自行百度.
  10. 最后就完成了,然后打开下方的TimeDomain选项卡页面就能看到频率-时间图的输出效果图;默认x坐标范围可能太小,拉长到能看到稳定输出;
  11. 最后的重点,打开左方的FreqDomain选项卡设置,能看到Analysis at - Int(N) Frac(F)的参数设置.这个就是手册算出来的整数和小数, 这里显示的是25位小数,使用计算器,拆分前12位,后13位,就对上手册里的数值了.
  12. 可以尝试修改分频系数 Int(N) Frac(F),能看到输出频率Analysis at也发生了变化.仿真软件会自动实时计算.
  13. 最后,我们再从代码的角度复刻这个例子的计算.
// 考虑到变量溢出截断,这里规定传参频率单位相同即可,不必一定是Hz.
// 计算分频系数,输入:基准频率输入(/k/M/GHz),RF频率输出(/k/M/GHz),RF基准分频系数;输出:整数部分,小数部分;
void int_frac_value(float REF_IN, float RF_OUT, float R, uint32_t *N, uint32_t *FRAC)
{	
	float f_PFD = REF_IN * ((1+0)/(R*(1+0))); // PFD频率
	printf("f_PFD = %f\n",f_PFD);
	
	float N_FRAC = RF_OUT / f_PFD; // 包含整数和小数部分的分频系数
	printf("N_FRAC = RF_OUT / f_PFD\n%f = %f / %f\n", N_FRAC, RF_OUT, f_PFD);
	
	N[0] = (uint32_t)N_FRAC; // 只取整数部分
	printf("N = %d\n",N[0]);
	
	FRAC[0] = (uint32_t)((N_FRAC - N[0]) * 33554432.0f); // 只取小数部分的前25位
	printf("FRAC = %d\n",FRAC[0]);
}
  • PFD频率(f_PFD )的公式中,DT我都默认设置为0,只开放一个R分频的设置.
  • 注意程序的变量储存最大4字节,32位,所以当变量过大时会截取.切记!因此程序设置允许传参为同数量级单位即可.

3.2.FMCW雷达斜坡设置成功范例

  • 紧接着开始第二个范例的仿真,这个范例是生成频率会周期变动的,幅值也会周期变动的,信号.

在这里插入图片描述在这里插入图片描述

  • 接下来看仿真设置过程:

在这里插入图片描述

  • 一开始的基本设置和上一个范例差不多,就是固定频率改成了变动频率;
  • 然后设置最大最小频率,和PDF固定输入频率,和参考时钟频率,其他设置一样.
  • 然后进入到细节参数设置:
  1. 注意,修改参数之前,建议手动修改一次TimeDomain - Stop TimeTimeDomain - Max Time Step的值,它代表了仿真输出的时间范围,如果不修改,默认会随着你的参数修改而自动改变,越大仿真需要的时间就越长,整个软件未响应卡死很久,
  2. TimeDomain - Type 选择Modulation,就可以自定义频率变动参数,TimeDomain - Type - Modulation就选择Sawtooth,代表连续锯齿波,
  3. 然后就能看到TimeDomain - Type - Modulation - Ramp DevTimeDomain - Type - Modulation - Mod Period里可以填写偏差值和分频值了.
  4. 直接照抄手册里计算好的答案,就能看到Ramp DevMod Period变成了题目要求的50MHz范围,和2ms周期间隔.
  5. 最后再设置浮点数分频值,找到FreqDomain - Analysis at,这里填写的是最小输出频率.(目前的理解,根据公式和配置反推得到,但是仿真软件默认这个是中间值,而不是最小值.所以我也不确定.我尝试修改但是波形却没有变化?)
  6. 手册里没有给出Int(N)Frac(F),所以自己算一下,使用vc6.0,输入参数,计算得到整数为232,小数为0是,正好输出5.8GHz,而整数为233时输出5.825GHz;直接修改仿真软件上的FreqDomain - Analysis at值,也会自动计算整数和小数,可以相互校验一下.
  7. 注意:数值5800*1000*1000已经超过了32位长度,属于溢出截取的情况.这种情况一定要注意,不然会计算错误,最后我采用kHz的单位传参5800*1000.
  8. 所有参数修改完毕后,就能在输出仿真的频率-时间图看到效果;在200us范围内,能看到阶梯效果的斜坡频率,保持一段时间后就步进,增加频率,依次循环.和手册的描述一直.然后修改仿真时间为5ms,就能看到两个半的连续锯齿波了.
  9. 到此仿真结束.总结,对于基本功能的寄存器配置,只需要计算以下几个参数即可;

在这里插入图片描述

  • 第一个范例已经打包好计算IntFrac,接下来,只需要剩余的Ramp DevMod Period即可完成对寄存器的配置.看看我下面的代码
// 范例代码被我吃了,
// 懒得写了,
// 授人以鱼不如授人以渔,我已经讲解到这了,应该都会写吧.
// 如果之后无聊再补上,

3.3.总结

  • 在网上的一些教程中,会用到很多专业术语,对于零基础的我来说看得一头雾水.
  • 比如啥是带宽?后来才明白,是指周期变动的频率范围,即最大频率减去最小频率.
  • 所以本篇教程尽量不采用专业术语,用很口头的预言简述应用中的实际效果.
  • 希望本篇教程能帮助到你,如果你发现有错误的地方,请理性且详细的在评论区指出.我会立刻更正.谢谢.
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6