前言
Si5351 是一款 I2C 可配置时钟发生器,非常适合在成本敏感型应用中替代晶体、晶体振荡器、压控晶体振荡器 (VCXO)、锁相环 (PLL) 和扇出缓冲器。Si5351 基于 PLL/VCXO + 高分辨率 MultiSynth 小数分频器架构,可在每路输出上产生高达 200 MHz 的任意频率。Si5351 提供三种版本,以满足各种应用需求。Si5351A 使用内部振荡器生成多达 8 个自由运行时钟,可替代晶体和晶体振荡器。Si5351B 增加了一个内部 VCXO,可灵活地替代自由运行时钟和同步时钟。它无需使用成本更高的定制可调晶体,同时在较宽的调谐范围内提供可靠的运行。Si5351C 具有相同的灵活性,但与外部参考时钟 (CLKIN) 同步。
一、SI5351发生器简介
SI5351A是一款I2C 接口、低功耗、高集成度的多输出时钟发生器,由一个固定的晶振25MHz输入,生成最多 3 路独立频率输出(CLK0/CLK1/CLK2),频率范围从8 kHz 到 160MHz(典型为 100MHz)。 主要特性
- 输入时钟源:25MHz 或 27MHz 晶振
- 输出端口:CLK0、CLK1、CLK2(最多三路)
- 输出频率范围:8kHz ~ 160MHz(典型使用不高于 100MHz)
- 内部结构:内部 PLL x2、MSynth x3、分频器、R-divider
- 通讯接口:I2C,支持 400kHz 标准通信速率,器件地址:1100000+读写位
- 输出类型:CMOS 方波输出
- 电源电压:3.3 ~ 5VDC
- 工作温度:-40℃ ~ 85℃
二、功能框图
PLL:两个(PLLA、PLLB),由 XTAL 倍频得到高频时钟(600-900MHz) MSynth:三组,分别控制 CLK0/1/2,通过分频得到最终输出 R-0/1/2:在 MSynth 后,还可进一步进行 1~128 的 2ⁿ次分频(影响输出频率)
三、主要寄存器
地址3:配置输出使能控制,地址1523:配置外部时钟输入分频,每路输出开关,通道时钟源等 41:配置PLLA/B(设置VCO频率),P1, P2, P3 构成 PLL 分数乘法器,使得 PLL freq 在 600 ~ 900 MHz 之间。 地址26
地址42~91:配置Multisynth 分频器(设置输出),也是 P1/P2/P3 三段式分频,要求 R_DIV 分频值在 4~900 且必须为偶数
四、输出频率的计算和配置说明
由上面的功能框图可知,SI5351A包括PLL+MultiSynth(多合成分频器)+输出R分频器,每个通道都有一个独立的多合成分频器和R分频器。此外,还内置了一个工作频率为 25 MHz 或 27 MHz 的普通振荡器电路,但它需要一个外部晶体。PLL由三个主要电子电路组成:相位比较器、VCO 和反馈分频器(FMD)。对于 FMD 的每个不同编程设置,VCO 将产生不同的频率。 为了提高频率分辨率(从宽步长到更细的步长),Si5351A 的PLL后接了一个分频器电路,Skyworks 将其命名为多合成分频器 (OMD)。在 Si5351A 中,Skyworks 增加了第二个分频器级(称为 R),可以进一步划分合成器产生的频率。 输出分频器的缺点是输出频率 (fout) 将低于 VCO 频率 (fvco)。在 Si5351A 中,最小分频为 4。这意味着 VCO 频率总是比输出频率高至少四倍。但是,频率步进可以小得多,例如 1 Hz,而不是很宽的频率步进,例如 25 kHz。这完全取决于如何设置 FMD 和 OMD 比例。 如何根据参考频率 (fref) 生成所需的输出频率 (fout)。输出频率由下面的公式表示
f_{out}=frac{f_{ref}·FMD}/{OMD·R}=f_{vco}/{OMD·R}
其中FMD和OMD的比率也可以表示为 FMD=a+b/c,OMD=d+e/f,即基准频率和输出频率完整关系为:
f_{out}={f_{ref}·(a+b/c)}/{R·(d+e/f)}
根据上述公式,除了 <math xmlns="http://www.w3.org/1998/Math/MathML"> f o u t f_{out} </math>fout和 <math xmlns="http://www.w3.org/1998/Math/MathML"> f r e f f_{ref} </math>fref的数值已知,有七个未知变量, <math xmlns="http://www.w3.org/1998/Math/MathML"> f r e f f_{ref} </math>fref为输入时钟源25M或27M, <math xmlns="http://www.w3.org/1998/Math/MathML"> f o u t f_{out} </math>fout为输出的频率。看手册可知FMD和OMD的比率是有范围限制的,FMD比率可以从15 + 0/1048575到90 + 0/1048575,OMD比率可以是4,也可以是8+1/1048575~2400,根据这个范围可以得到a=15到90,b=0,c=1048575,注意分母不能为0。R分频器只能为1,2,4,8,16,32,64,128。输出低于500KHz,则需使用R分频。
同时你还需要了解小数分频模式 与 整数分频模式,两者的区别是对相位噪声 / 杂散 / 抖动 的影响,FMD和OMD都是可以使用整数或小数进行分频,小数分频方式允许更灵活地产生任意频率,FMD 和 OMD 的比率被称为小数。缺点就是会引入杂散和相位抖动。故如果要求低抖动(比如用于 ADC/DAC 时钟),应尽可能让分频系数为整数,避免小数。使用什么模式则看你的应用,可以都为整数(只要输出频率允许),这样杂散最低,不过产生频率就没有那么灵活。如果你只能选择一个在小数模式下工作,那就尽量让 OMD 是整数模式,FMD 允许小数,因为这样输出频率的杂散更小。OMD 后面直接连接着你的"输出引脚",所以它分频后的信号质量最直接影响外部设备。此外,"a"和"d"分别是 输出频率公式中的分子/分母,如果能选择偶数,可以改善调制器行为,降低杂散。 这里以输出59.779MHz为例来分析计算,通过反推的技巧,计算出未知变量的具体值。由手册的R分频说明,意味着R=1。VCO频率范围要在600M到900MHz内,使用900MHz进行计算。
R·OMD=OMD=d+e/f}={f_{voc}}/{f_{out}}=900000000/59779000=15.05545425651148
这意味着d=15,又因为R=1,所以e / f的比率是0.44133412745682。比率四舍五入,这既不是整数,也不是偶数。因此将d进行四舍五入为偶数整数,即d=16,然后待回去检查VCO频率是否还在600M到900MHz内。如果不在,则增大或减少2个数值。这里16代入换算是超出VCO频率范围的,即d=14。由于希望OMD要在整数模式下,e / f比值是不重要的。因此可以得到,d=14,e=0,f=1或 ≤ 1048575(最大分辨率)的值都可以。 现在OMD的未知变量知道了,后面继续找出FMD的未知变量,即a,b,c。 FMD=a+b/c={R·(d+e/f)·f_{out}}/{f_{ref}}=1·(14+0/1))·59779000/25000000=33.47624
其中33为FMD整数部分的a,b / c = 0.47624。如何求解余数部分等式,最直接的方法,就是将c设为1048575,这样,b就等于499373.358。 通过以上的计算,得到a=33,b=499373.358,c=1048575,d=14,e=0,f=1,R=1。把这些数值代入验证: f_{out}={f_{ref}·(a+b/c)}/{R·(d+e/f)}={25000000·(33+499373.358/1048575)}/{1·(14+0/1)}=59779000
输出频率没有问题。如果输出频率低于500KHz,就要使用R分频,重复上面步骤,变换公式,将有效R值(1,2,4,8,...,128)代入即可。如果想要SI5351A产生最低频率,边界频率就要设置为2048,R分频设置为最大128。 最低输出f_{out}={VCO}/{OMD·R}={600MHz}/{2048·128}≈ 2.288KHz
通过上述的分析,输出频率的计算和配置就基本明了了,SI5351A的基本工作原理可以理解为:将时钟输入源送入到两个PLL锁相环中,然后PLL将将基准频率倍频,输出一个高频的参考时钟,高频范围要在600M~900MHz内,再将PLL输出时钟送入到MultiSynth(多合成器模块),合成器接收到PLL信号,合成器则进行可编程分频,将 PLL 的高频信号变成你需要的输出频率。如果输出频率低于 500 kHz,则需加上R分频。 最后说明下,虽然Si5351A芯片理论上支持最高200MHz,最低2.5kHz。但实际会受晶振偏差,带宽限制,板子电路设计等物理限制因素影响。建议输出频率要在【160MHz,8KHz】使用。
五、STM32F103驱动SI5351A
准备工作
STM32F103C8T6最小系统板、SI5351时钟信号发生器、测量信号的示波器、连接线若干。
引脚接线
STM32F103C8T6 | SI5351时钟信号发生器 |
---|---|
3.3V | VIN |
GND | GND |
PA3 | SCL |
PA5 | SDA |
代码示例
SI5351A.c
c
#include "si5351a.h"
static void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_3; /* PA3-I2C_SCL、PA
5-I2C_SDA*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
///////////IIC初始化//////////////
void IIC_SI5351A_GPIO_Init(void)
{
I2C_GPIO_Config();
}
////////////粗略延时函数//////////
void Delay_1us(u16 n)//约1us,1100k
{
unsigned int x=5,i=0;
for(i=0;i<n;i++)
{while(x--);x=5;}
}
void Delay_ms(u8 n)//约0.5ms,2k
{
unsigned int x=5000,i=0;
for(i=0;i<n;i++)
{while(x--);x=5000;}
}
////////IIC启动函数//////////
void I2C_Start(void)
{
SDA_H;
SCL_H;
Delay_1us(1);
if(!SDA_read) return;//SDA线为低电平则总线忙,退出
SDA_L;
Delay_1us(1);
if(SDA_read) return;//SDA线为高电平则总线出错,退出
SDA_L;
Delay_1us(1);
SCL_L;
}
//**************************************
//IIC停止信号
//**************************************
void I2C_Stop(void)
{
SDA_L;
SCL_L;
Delay_1us(1);
SCL_H;
SDA_H;
Delay_1us(1); //延时
}
//**************************************
//IIC发送应答信号
//入口参数:ack (0:ACK 1:NAK)
//**************************************
void I2C_SendACK(u8 i)
{
if(1==i)SDA_H; //写应答信号
else SDA_L;
SCL_H; //拉高时钟线
Delay_1us(1); //延时
SCL_L ; //拉低时钟线
Delay_1us(1);
}
//**************************************
//IIC等待应答
//返回值:ack (1:ACK 0:NAK)
//**************************************
bool I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
{
unsigned int i;
SDA_H;
Delay_1us(1);
SCL_H;
Delay_1us(1);
while(SDA_read){i++;if(i==5000)break;}
if(SDA_read)
{SCL_L;
Delay_1us(1);
return FALSE;}
SCL_L;
Delay_1us(1);
return TRUE;
}
//**************************************
//向IIC总线发送一个字节数据
//**************************************
void I2C_SendByte(u8 dat)
{
unsigned int i;
SCL_L;
for (i=0; i<8; i++) //8位计数器
{
if(dat&0x80){SDA_H;} //送数据口
else SDA_L;
SCL_H; //拉高时钟线
Delay_1us(1); //延时
SCL_L; //拉低时钟线
Delay_1us(1); //延时
dat <<= 1; //移出数据的最高位
}
}
//**************************************
//从IIC总线接收一个字节数据
//**************************************
u8 I2C_RecvByte()
{
u8 i;
u8 dat = 0;
SDA_H; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
SCL_H; //拉高时钟线
Delay_1us(1); //延时
if(SDA_read) //读数据
{
dat |=0x01;
}
SCL_L; //拉低时钟线
Delay_1us(1);
}
return dat;
}
//**************************************
//向IIC设备写入一个字节数据
//**************************************
bool Single_WriteI2C(u8 Slave_Address,u8 REG_Address,u8 REG_data)
{
I2C_Start(); //起始信号
I2C_SendByte(Slave_Address); //发送设备地址+写信号
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_SendByte(REG_Address); //内部寄存器地址,
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_SendByte(REG_data); //内部寄存器数据,
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_Stop(); //发送停止信号
return TRUE;
}
u8 Single_ReadI2C(u8 Slave_Address,u8 REG_Address)
{
u8 REG_data;
I2C_Start(); //起始信号
I2C_SendByte(Slave_Address); //发送设备地址+写信号
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_SendByte(REG_Address); //发送存储单元地址,从0开始
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_Start(); //起始信号
I2C_SendByte(Slave_Address+1); //发送设备地址+读信号
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
REG_data=I2C_RecvByte(); //读出寄存器数据
I2C_SendACK(1); //发送停止传输信号
I2C_Stop(); //停止信号
return REG_data;
}
uint8_t i2cSendRegister(uint8_t reg, uint8_t data)
{
I2C_Start(); //起始信号
I2C_SendByte(0xC0); //发送设备地址+写信号
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_SendByte(reg); //内部寄存器地址,
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_SendByte(data); //内部寄存器数据,
if(!I2C_WaitAck()){I2C_Stop(); return FALSE;}
I2C_Stop();
return 0;
}
void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom)
{
uint32_t P1; // PLL config register P1
uint32_t P2; // PLL config register P2
uint32_t P3; // PLL config register P3
P1 = (uint32_t)(128 * ((float)num / (float)denom));
P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
P2 = (uint32_t)(128 * ((float)num / (float)denom));
P2 = (uint32_t)(128 * num - denom * P2);
P3 = denom;
i2cSendRegister(pll + 0, (P3 & 0x0000FF00) >> 8);
i2cSendRegister(pll + 1, (P3 & 0x000000FF));
i2cSendRegister(pll + 2, (P1 & 0x00030000) >> 16);
i2cSendRegister(pll + 3, (P1 & 0x0000FF00) >> 8);
i2cSendRegister(pll + 4, (P1 & 0x000000FF));
i2cSendRegister(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
i2cSendRegister(pll + 6, (P2 & 0x0000FF00) >> 8);
i2cSendRegister(pll + 7, (P2 & 0x000000FF));
}
void setupMultisynth(uint8_t synth,uint32_t divider,uint8_t rDiv)
{
uint32_t P1; // Synth config register P1
uint32_t P2; // Synth config register P2
uint32_t P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
i2cSendRegister(synth + 0, (P3 & 0x0000FF00) >> 8);
i2cSendRegister(synth + 1, (P3 & 0x000000FF));
i2cSendRegister(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
i2cSendRegister(synth + 3, (P1 & 0x0000FF00) >> 8);
i2cSendRegister(synth + 4, (P1 & 0x000000FF));
i2cSendRegister(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
i2cSendRegister(synth + 6, (P2 & 0x0000FF00) >> 8);
i2cSendRegister(synth + 7, (P2 & 0x000000FF));
}
void si5351aSetFrequency(uint32_t frequency , u8 Chanal )
{
uint32_t freq_temp;
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;// Crystal frequency
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
freq_temp = frequency * 1; //分频系数
divider = 900000000 / freq_temp;// Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer division ratio
pllFreq = divider * freq_temp; // Calculate the pllFrequency: the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to get to the required pllFrequency 36 0 0
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(SI_SYNTH_PLL_A, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
if( Chanal == 0 ){
setupMultisynth(SI_SYNTH_MS_0,divider,SI_R_DIV_1); //设置分频后,设置频率的系数也需要更改
// Reset the PLL. This causes a glitch in the output. For small changes to
// the parameters, you don't need to reset the PLL, and there is no glitch
i2cSendRegister(SI_PLL_RESET,0xA0);
// Finally switch on the CLK0 output (0x4F)
// and set the MultiSynth0 input to be PLL A
i2cSendRegister(SI_CLK0_CONTROL, 0x4F|SI_CLK_SRC_PLL_A);
}
else if ( Chanal == 1 ){
setupMultisynth(SI_SYNTH_MS_1,divider,SI_R_DIV_1);
i2cSendRegister(SI_PLL_RESET,0xA0);
i2cSendRegister(SI_CLK1_CONTROL, 0x4F|SI_CLK_SRC_PLL_A);
}
else if ( Chanal == 2 ){
setupMultisynth(SI_SYNTH_MS_2,divider,SI_R_DIV_1);
i2cSendRegister(SI_PLL_RESET,0xA0);
i2cSendRegister(SI_CLK2_CONTROL, 0x4F|SI_CLK_SRC_PLL_A);
}
}
void SI5351_SetFreq_Clk0(uint32_t frequency)
{
uint32_t freq_temp;
uint8_t div_factor, R_diV;
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;// Crystal frequency
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
if(frequency < 500000)
{
div_factor = 64;
R_diV = SI_R_DIV_64;
}else{
div_factor = 1;
R_diV = SI_R_DIV_1;
}
freq_temp = frequency * div_factor; //fout * R
divider = 900000000 / freq_temp;// OMD = 900M /(fout * R)
if (divider % 2) divider--; // VCO = 600M - 900M, 取偶,整数模式
pllFreq = divider * freq_temp; // VCO = OMD * fout * R
mult = pllFreq / xtalFreq; // 取整数a,VCO = fref * (a + b/c)
l = pllFreq % xtalFreq; // 取小数:b/c
f = l;
f *= 1048575; // b放大
f /= xtalFreq; // 获取b
num = f;
denom = 1048575;
setupPLL(SI_SYNTH_PLL_A, mult, num, denom);
setupMultisynth(SI_SYNTH_MS_0,divider,R_diV);
i2cSendRegister(SI_PLL_RESET,0xA0);
i2cSendRegister(SI_CLK1_CONTROL, 0x4F|SI_CLK_SRC_PLL_A);
}
main.c
c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "si5351a.h"
int main(void)
{
int Fre_1M = 10000;
int fre = 5;
delay_init(); //延时函数初始化
IIC_SI5351A_GPIO_Init();
si5351aSetFrequency(112500000 , 0);
si5351aSetFrequency(1000000 , 1);
si5351aSetFrequency(10000 , 2);
while(1)
{
// SI5351_SetFreq_Clk0(fre*Fre_1M);
// delay_ms(50);
// fre += 100;
// if(fre*Fre_1M > 150000000) fre = 5;
}
}
效果展示
注意事项
- PLL 频率需始终在 600 ~ 900 MHz 范围
- Multisynth 分频必须为偶数,4~900
- 输出小于 500KHz 时,建议使用 R_DIV 分频
- 3通道不能同时输出高于112MHz