本实验使用ZYNQ的PL(FPGA)对LMX2571芯片进行配置,以下连接为相关的原理和软件使用资料。
TICS Pro 配置时钟芯片
文献阅读–Σ-Δ 小数频率合成器原理
LMX2571芯片数据手册
LMX2571使用24位寄存器进行编程。一个24位移位寄存器用作临时寄存器,间接地对片上寄存器进行编程。移位寄存器由一个数据字段、一个地址字段和一个读写位组成。MSB是读写位。0表示写寄存器,1表示读寄存器。后面的7位,ADDR[6:0],构成地址字段,用来解码内部寄存器地址。剩下的16位组成数据字段data[15:0]。当LE为低时,串行数据在时钟上升沿上被时钟输入移位寄存器。当LE变高时,数据从数据字段传输到选定的寄存器。
读时序分为两部分写地址和读数据。先设R/W位为1,然后写入寄存器地址此时数据字段的内容将被忽略。然后从第9个时钟周期开始,将输出回读串行数据。
参考该文章可以完成配置:TICS Pro 配置时钟芯片
这里就写几个注意事项:不管是什么芯片,寄存器的功能一定要了解清楚特别是一些功能设置的寄存器。
例如:LMX2571的R42是一个锁定模式寄存器,锁定模式下MUXout变为锁定指示,1为锁定频率,0为未锁定。此时读寄存器是没有用的。还有R7-R8的输出接口的选择配置等等一定要和自己的设计对上。
不论是读还写核心代码就是按照手册的时序输出数据,一个简单的SPI时序。以下代码片段为输出24位数据的代码,1位数据使用4个system_clk进行设置。
//开始发送数据
state_sent:
if( i >= 7'd1 ) begin
case(clkcnt)
0: //写使能
begin
PLL_LE<=0;
PLL_SCK<=0;
clkcnt<=clkcnt+1'b1;
PLL_SD<=Reg2571[cnt][23];
end
1: //输出数据
begin
Reg2571[cnt]<=Reg2571[cnt]<<1;
clkcnt<=clkcnt+1'b1;
end
2: //保持数据
begin
PLL_SCK<=1;
clkcnt<=clkcnt+1'b1;
end
3:
begin
i<=i-1'b1;
clkcnt<=8'd0;
end
default:
PLL_SCK<=PLL_SCK;
endcase
end
else if( i == 7'd0 ) state<=state_start;
读代码也类似,只不过是先写地址再读。
//读取寄存器
state_rdata:
if( i >= 7'd17 ) begin //设置读取的寄存器地址
case(clkcnt)
0: //写使能
begin
PLL_LE<=0;
PLL_SCK<=0;
clkcnt<=clkcnt+1'b1;
PLL_SD<=Reg2571adr[7];
Reg2571Rdata[i-1]<= Reg2571adr[7];
end
1: //输出数据
begin
Reg2571adr<=Reg2571adr<<1;
clkcnt<=clkcnt+1'b1;
end
2:
begin
PLL_SCK<=1;
clkcnt<=clkcnt+1'b1;
end
3: begin
i<=i-1'b1;
clkcnt<=8'd0;
end
default: PLL_SCK<=PLL_SCK;
endcase
end
else if( i >=7'd1 && i<=7'd16 ) begin //接收读出的数据
case(clkcnt)
0: //写使能
begin
PLL_SCK<=0;
clkcnt<=clkcnt+1'b1;
end
1: clkcnt<=clkcnt+1'b1;
2:
begin
PLL_SCK<=1;
Reg2571Rdata[i-1]<=PLL_MUXO;//读数据记录
clkcnt<=clkcnt+1'b1;
end
3:
begin
i<=i-1'b1;
clkcnt<=8'd0;
end
default: PLL_SCK<=PLL_SCK;
endcase
end
整体代码就是对读写代码的使用,因为涉及到其他不可公开的信息,展示代码并且以图例说明以下配置代码。整个程序分为 state_init,state_reset,state_start,state_delay,state_sent,state_rdata–六个状态。
各状态的跳转顺序如下图,实验中使用的case语句实现不同状态的跳转
always @(posedge CLK)begin
if(!RST_n)
begin
PLL_SD<=0;
PLL_LE<=1;
PLL_SCK<=0;
i<=7'd24;
cnt<=8'd60;//寄存器计数
delay_cnt<=16'd0;
Reg2571Rdata<=24'd0;
Reg2571Rdataout<=24'd0;
Reg2571adr<=8'd0;
state<=state_init;
clkcnt<=8'd0;
end
else begin
case(state)
//寄存器初始化
state_init:
begin
//----------------------------默认寄存器配置------------------------------------
Reg2571Reset<=24'h002082; //R0_reset
Reg2571[60]<= 24'h3CA000;
//这里依次填入寄存器初始化pei'z
state<= state_reset;
end
//复位LMX2571寄存器
state_reset:
begin
if( i >= 7'd1 ) begin
case(clkcnt)
0: //写使能
begin
PLL_LE<=0;
PLL_SCK<=0;
clkcnt<=clkcnt+1'b1;
PLL_SD<=Reg2571Reset[23];
end
1: //输出数据
begin
Reg2571Reset<=Reg2571Reset<<1;
clkcnt<=clkcnt+1'b1;
end
2:
begin
PLL_SCK<=1;
clkcnt<=clkcnt+1'b1;
end
3: //输出结束
begin
i<=i-1'b1;
clkcnt<=8'd0;
end
default: PLL_SCK<=PLL_SCK;
endcase
end
else if( i == 7'd0 ) begin
PLL_SD<=0;
PLL_SCK<=0;
PLL_LE<=1;
i<=7'd24;
cnt<=8'd60;
state<=state_delay;
end
end
//开始配置LMX2571寄存器
state_start:
case(cnt)
default:
if( i == 7'd24 ) begin
state<=state_sent;
end
else if( i == 7'd0 ) begin //切换寄存器
PLL_SD<=0;
PLL_LE<=1;
PLL_SCK<=0;
i<=7'd24;
if(cnt==0) cnt=61; //切换至读寄存器,锁定模式下读不出
else cnt<=cnt-1'b1;
state<=state_delay;
end
//代码和default类似注意跳转即可
39,40,41,42:;
46,47:;
53,58:;
60:;
endcase
//开始发送数据
state_sent:;
//写入后的延时clk*10
state_delay:
if(delay_cnt<10) delay_cnt<=delay_cnt+1'b1;
else begin
if(cnt==61)
begin //读寄存器数据
state<= state_rdata;
Reg2571adr<=Regadr;
end
else
begin //写寄存器数据
state<=state_start;
end
delay_cnt<=16'd0;
end
//读取寄存器
state_rdata:;
default:begin
PLL_SD<=0;
PLL_LE<=1;
end
endcase