笔者研0在实验室打工时,被要求用ZYNQ7020驱动芯片,根据b站教程用大约1周的时间完成了AD5420芯片的驱动,将时序图思路和代码分享~希望一起学习进步。
b站教程指路:根据ADS1256数据手册编写Verilog驱动_哔哩哔哩_bilibili
一、引脚功能说明
- GND:接地
- DVCC :数字电源,2.7V-5.5V
- DVCC SELECT:(1)连接至GND时,禁用内部电源,外部电源连接至DVCC 引脚;(2)不连接这个引脚,就启用内部资源。DVCC 和GND之间最好连接0.1μF 的电容
- FAULT :故障警报,IOUT 与GND之间如果温度过高或者开路,FAULT 低电平有效。且该引脚为开漏输出,通过10kΩ 上拉电阻连接至DVCC
- CLEAR:异步清零引脚,范围:0-20mA/0-24mA/4-20mA
- LATCH:锁存器,利用电平控制数据的输入
- SCLK:串行时钟输入,SCLK上升沿触发,数据写入寄存器中,工作时钟为30MHz(遵循SPI协议)
- SDIN:串行数据输入,SCLK上升沿触发,数据有效
- SDO:串行数据输出,SCLK下降沿触发,数据被输出
- RSET :连接15kΩ 电阻,以提升设备的整体性能
- REFOUT :内部参考电压输出,温度为25℃时VREFOUT =5V±5mA ,温度漂移为1.8ppm/℃
- REFIN:外部参考电压输入,规定性能VREFIN =5V±50mA
- R3SENSE :监控反馈功能,该引脚与BOOST引脚之间的电压与输出电流成正比。只用作电压测量,电流不经过该引脚。
- IOUT :电流输出。
- BOOST :可选外部晶体管连接,能够降低功耗
- CAP1 :可选输出滤波电容连接
- CAP2 :可选输出滤波电容连接,同时是HART输入连接
- AVDD :器件内部的工作电压,10.8V-40V
- Exposed pad :外露焊盘,接地
二、时序图
输入24位宽(8地址位+16数据位)的移位寄存器。在数据字的MSB中时钟的SCLK的第一个上升沿标志着写周期的开始。一个SCLK的上升沿触发,对应一个SDIN数据的写入,SCLK触发24次上升沿后,LATCH调高所存数据,上升沿次数多于24次或小于24次都会导致数据输入无效。
CLEAR为异步清零,高电平有效,需要清零时,ZYNQ发出信号(output)至AD5420,实现清零功能。FAULT为故障警报,低电平有效,当芯片内部出现故障时,芯片发出信号至ZYNQ(input),实现警报功能。
ZYNQ的时钟频率为50MHz,通过MMCM IP核生成芯片需要的时钟SCLK,频率为30MHz。每24个SCLK时钟信号为一个周期记录数据,记录数据时LATCH始终为低电平,一个周期结束后,LATCH立刻拉高,将数据锁存于SDin中,高八位为地址位,低16位为数据位。
三、代码
1 定义输入输出,输入:ZYNQ时钟clk、复位reset_n、8位地址address、16位数据current、故障警报FAULT_n;输出:异步清零CLEAR、锁存器LATCH、芯片时钟SCLK、芯片输入SDIN。
2 时钟生成器,采用clock wizard ip核生成时钟,设置输入时钟clk频率为50MHz,输出时钟SCLK频率为30MHz,采用MMCM方式生成。调用ip核,连线。
3 设置四个状态机来实现功能:空闲、开始、转换、停止。再定义三个reg形式的寄存器(计数cnt、数据的个数data_num、所有数据data_temp)用以辅助。
状态1空闲:转换至状态2,LATCH为高电平;
状态2开始:将8位地址和16位数据记录到data_temp中,并令data_num=23(一共24位数据),LATCH为高电平,转换至状态3;
状态3转换:按照数据的个数依次将数据从data_temp写入SDin,LATCH为低电平,每写一个数据,将data_num减1,当data_num减到0时,LATCH立刻拉高,进入最后一个状态。
状态4停止:转换至状态1,LATCH为高电平。
4 提前预留CLEAR接口位置。
5 仿真代码,依次步骤为:a. 定义输入输出,输入为reg,输出为wire;b. 初始化系统时钟和复位;c. 与主文件连线;d. 初始化信号。
四、仿真
1 系统时钟频率为50MHz,周期为20ns;芯片时钟频率为30MHz,周期为33.3ns,与预期一致。
2 初始化时输入地址信号为8’b11110000,数据信号为16’b1111111100001111,仿真结果与输入一致,地址信号为f0,数据信号为ff0f。
3 LATCH拉高后,观察SDin结果,从后往前看DB0-DB23为1111_0000_1111_1111_0000_1111,与输入一致。
五、代码
1 顶层代码
`timescale 1ns / 1ps
module AD5420(
input clk, //系统时钟
input reset_n, //系统复位
input [7:0] address, //高8位地址
input [15:0] current, //低16位数据
input FAULT_n, //提前留好FAULT_n接口
output reg CLEAR, //CLEAR异步清零接口
output reg LATCH, //锁存器
output wire SCLK, //芯片时钟
output reg SDIN //芯片输入
);
// 时钟生成器
clk_wiz_0 clk_wiz_0 (
.clk_out1(SCLK),
.reset(~reset_n),
.locked(locked),
.clk_in1(clk)
);
// 状态定义
reg [3:0] state;
parameter idle = 4'b0001,
start = 4'b0010,
shift = 4'b0100,
stop = 4'b1000;
// 数据定义
reg [4:0] cnt;
reg [23:0] data_temp;
reg [4:0] data_num;
// 状态机
always @(posedge SCLK or negedge reset_n) begin
if (!reset_n) begin
state <= idle;
SDIN <= 1'b0;
cnt <= 5'd0;
end else begin
case (state)
idle: begin
state <= start;
LATCH <= 1'b1;
end
start: begin
data_temp <= {address, current};
state <= shift;
data_num <= 5'd23;
LATCH <= 1'b1;
end
shift: begin
SDIN <= data_temp[data_num];
if (data_num == 5'd0) begin
state <= stop;
LATCH <= 1'b1;
end else begin
data_num <= data_num - 1'b1;
state <= shift;
LATCH <= 1'b0;
end
end
stop: begin
state <= idle;
LATCH <= 1'b1;
end
endcase
end
end
// 输出寄存器
always @(posedge SCLK or negedge reset_n) begin
if (!reset_n) begin
CLEAR <= 1'b0;
end else begin
CLEAR <= 1'b1;
end
end
endmodule
2 仿真代码
`timescale 1ns / 1ps
module AD5420_tb( );
reg clk;
reg reset_n;
reg [7:0] address;
reg [15:0] current;
wire FAULT_n;
wire CLEAR;
wire LATCH;
wire SCLK;
wire SDIN;
// wire locked;
always #10 clk = ~clk;
initial begin
clk = 1'b0;
reset_n = 1'b0;
#100
reset_n = 1'b1;
end
AD5420 u_AD5420
(
.clk (clk ),
.reset_n (reset_n ),
.address (address ),
.current (current ),
.FAULT_n (FAULT_n ),
.CLEAR (CLEAR ),
.LATCH (LATCH ),
.SCLK (SCLK ),
.SDIN (SDIN )
);
// 初始化信号
initial begin
address = 8'b11110000;
current = 16'b1111111100001111;
end
endmodule