基于FPGA的AD5753(DAC数模转换器)的控制 II(已上板验证)
语言 :Verilg HDL
EDA工具:Vivado
- 关键词: AD5753 驱动,Verilog HDL,SPI驱动,DAC数模转换器,上板已验证乐成
一、引言
本次分享DAC(AD5753) SPI驱动控制器的FPGA实现,可以借鉴到大部分DAC或者ADC的SPI驱动控制,是上篇基于FPGA的AD5753(DAC数模转换器)的控制 I(SPI驱动)文章的续篇。重要包罗DAC(AD5753) FPGA的工程实现,仿真以及上板调试,实现了对DAC芯片的寄存器读写控制。
二、基于FPGA的AD5753控制驱动实现
1. 顶层模块
顶层模块代码如下所示,重要包罗
(1)AD5753驱动模块:AD5753_driver模块负责与AD5753 DAC通信,发送数据和触发信号。
(2)数据控制模块:AD5753_DATA_Ctrl模块生成要发送给DAC的数据,并控制数据发送。
(3)逻辑分析仪(ILA):ila实例用于监视和记录信号,以便于调试。
(4)假造输入输出(VIO):vio_0实例用于假造探针,可以观察或驱动信号。
clk_wiz_0实例用于生成50MHz的时钟信号clk_50m,而且locked信号表示时钟锁定状态。dac_reset_n输出端口被设置为locked,用于DAC的复位。
- module test_ADC5753(
- input sys_clk,
- input fault_n,
- output sdi, // to ac5753
- output sclk,
- input sdo, // from ad5753
- output dac_reset_n,
- output sync_n,
- output ldac_n,
- output led
- );
-
- wire [32:0] send_data;
- wire send_trig;
- wire [32:0] spi_rx_dat;
- wire spi_rx_int;
- wire send_done ;
- //wire spi_clk_i2;
- wire spi_clk_i;
- wire locked;
- wire clk_50m;
- wire dat_gen_en;
- wire [15:0] data;
-
- clk_wiz_0 clk_wiz_inst
- (
- .clk_out2(clk_50m),
- .clk_out1( ),
- .locked (locked ),
- .clk_in1 (sys_clk ) //50M
-
- );
- assign dac_reset_n = locked;
-
- assign led = 1'b0;
- reg[4:0] cnt;
-
- reg clk_1M;
- always@(posedge clk_50m or negedge locked)
- begin
- if(!locked) begin
- cnt = 5'b0;
- clk_1M = 1'b0;
- end
- else begin
- if(cnt == 5'd24 ) begin
- clk_1M = !clk_1M;
- cnt = 5'd0;
- end
- else begin
- cnt = cnt +5'b1;
- end
- end
- end
-
-
- AD5753_driver AD5753_driver (
- .clk(clk_50m),
- .dac_reset_n(locked),
- .fault_n(fault_n),
- .send_data(send_data),
- .send_trig(send_trig),
- .send_done(send_done),
- .spi_clk_i(clk_1M),
- .spi_rx_dat(spi_rx_dat),
- .spi_rx_int(spi_rx_int),
- .ldac_n(ldac_n),
- .spi_clk(sclk),
- .sync_n(sync_n),
- .spi_mosi(sdi),
- .spi_miso(sdo)
- );
- AD5753_DATA_Ctrl AD5753_DATA_Ctrl (
- .clk(clk_50m),
- .spi_clk_i(clk_1M),
- .locked(locked),
- .data(data),
- .send_done(send_done),
- .send_trig(send_trig),
- .send_data(send_data),
- .dat_gen_en(1'b1),
- .spi_rx_int(spi_rx_int),
- .spi_rx_dat(spi_rx_dat)
- );
- ila ila_inst (
- .clk(clk_50m), // input wire clk
- .probe0(send_data), // input wire [23:0] probe0
- .probe1(send_trig), // input wire [0:0] probe1
- .probe2(spi_rx_dat), // input wire [23:0] probe2
- .probe3(spi_rx_int), // input wire [0:0] probe3
- .probe4(send_done), // input wire [0:0] probe4
- .probe5(locked), // input wire [0:0] probe5
- .probe6(dac_reset_n), // input wire [0:0] probe6
- .probe7(fault_n), // input wire [0:0] probe7
- .probe8(sdi), // input wire [0:0] probe8
- .probe9(sclk), // input wire [0:0] probe9
- .probe10(sync_n), // input wire [0:0] probe10
- .probe11(ldac_n), // input wire [0:0] probe11
- .probe12(sdo) // input wire [0:0] probe12
- );
-
- vio_0 vio_0 (
- .clk(clk_50m), // input wire clk
- .probe_in0( ), // input wire [0 : 0] probe_in0
- .probe_out0(), // output wire [0 : 0] probe_out0
- .probe_out1(data) // output wire [0 : 0] probe_out0
- );
-
- endmodule
复制代码 2. 数据控制模块(AD5753_DATA_Ctrl模块)
AD5753_DATA_Ctrl 模块,筹划用于控制与AD5753数字到模拟转换器(DAC)的数据传输。通过界说一系列的输入输出端口、内部状态、计数器和标记位来实现对数据发送过程的准确控制。
模块内部实现了一个状态机,通过不同的状态(如 DATA_IDLE、DATA_FAULT、DATA_Key 等)来管理数据传输流程。状态机根据当前状态和输入信号(比方 dat_gen_en、send_done)来决定下一个状态,并通过 spi_clk_i 来同步数据的发送。
模块还包罗了CRC校验逻辑,通过 gen_crc8 子模块生成数据的CRC校验码,确保数据传输的可靠性。在不同的状态下,模块会设置相应的发送触发信号 send_trig 和发送数据 send_data,以及实现特定操作的500us延时,从而完成对AD5753 DAC的下令设置和数据更新。
- module AD5753_DATA_Ctrl(
- input clk, //50M
- input spi_clk_i,
- input locked,
- input send_done,
- output reg send_trig,
- output [31:0] send_data,
- input dat_gen_en,
- input spi_rx_int,
- input [15:0] data,
- input [31:0] spi_rx_dat
- );
-
- // device adress
- localparam[2:0] DEVICE_ADRESS=3'b011;
- // register
- localparam[4:0] NOP=5'h00;
- localparam[4:0] Key=5'h00;
-
-
-
- // STATE
- localparam[4:0] DATA_IDLE = 5'd0;
- localparam[4:0] DATA_FAULT = 5'd1;
- localparam[4:0] DATA_Key = 5'd2;
- localparam[4:0] DATA_Key_wait = 5'd3;
- localparam[4:0] DATA_CLEAR = 5'd4;
- localparam[4:0] DATA_REQ = 5'd5;
- localparam[4:0] DATA_DC_SET = 5'd6;
- localparam[4:0] DATA_DC_SET_WAIT = 5'd7;
- localparam[4:0] DATA_DC_MOD = 5'd8;
- localparam[4:0] DATA_DC_MOD_WAIT = 5'd9;
- localparam[4:0] DATA_DAC_SET = 5'd10;
- localparam[4:0] DATA_DAC_SET_WAIT = 5'd11;
- localparam[4:0] DATA_DAC_MOD = 5'd12;
- localparam[4:0] DATA_DAC_MOD_WAIT = 5'd13;
- localparam[4:0] DATA_LDAC = 5'd14;
- localparam[4:0] DATA_OUTPUT = 5'd15;
- localparam[4:0] DATA_REQ_DAC = 5'd16;
- localparam[4:0] DATA_REQ_DAC_WAIT = 5'd17;
- localparam[4:0] DAC_read = 5'd18;
- localparam[4:0] DAC_nop = 5'd19;
-
-
-
- reg [13:0] cnt_500us;
- reg FLAG;
-
- reg [4:0] state;
- reg [4:0] next_state;
- reg send_trig_tem;
- reg [23:0] send_data_tem;
- reg spi_clk_dly;
- wire spi_clk_pos;
- wire spi_clk_neg;
- reg send_done_dly;
- wire send_done_pos;
- reg FLAG2;
-
- wire[7:0] nextCRC8_D24;
- wire crc_out_en;
- reg [15:0] data_reg;
- reg [15:0] data_reg2;
-
-
- always @ ( posedge spi_clk_i ) begin
- if( ~locked ) begin
- data_reg <= 16'b0;
- data_reg2 <= 16'b0;
- end
- else begin
- data_reg <= data;
- data_reg2 <= data_reg;
-
- end
-
- end
-
-
-
- always @ ( posedge spi_clk_i ) begin
- if( ~locked )
- state <= DATA_IDLE;
- else
- state <= next_state;
- end
- always @ (*) begin
- if( ~locked )
- next_state = DATA_IDLE;
- else
- case ( state )
- DATA_IDLE:
- if( dat_gen_en )
- next_state = DATA_FAULT;
- else
- next_state = DATA_IDLE;
- DATA_FAULT:
- if( send_done )
- next_state = DATA_Key;
- else
- next_state = DATA_FAULT;
- DATA_Key:
- if( send_done )
- next_state = DATA_Key_wait;
- else
- next_state = DATA_Key;
- DATA_Key_wait:
- if( FLAG )
- next_state = DATA_CLEAR;
- else
- next_state = DATA_Key_wait;
-
- DATA_CLEAR:
- if( send_done )
- next_state = DATA_REQ;
- else
- next_state = DATA_CLEAR;
- DATA_REQ:
- if( send_done )
- next_state = DATA_DC_SET;
- else
- next_state = DATA_REQ;
- DATA_DC_SET:
- if( send_done )
- next_state = DATA_DC_SET_WAIT;
- else
- next_state = DATA_DC_SET;
- DATA_DC_SET_WAIT:
- if( FLAG )
- next_state = DATA_DC_MOD;
- else
- next_state = DATA_DC_SET_WAIT;
- DATA_DC_MOD:
- if( send_done )
- next_state = DATA_DC_MOD_WAIT;
- else
- next_state = DATA_DC_MOD;
- DATA_DC_MOD_WAIT:
- if( FLAG )
- next_state = DATA_DAC_SET;
- else
- next_state = DATA_DC_MOD_WAIT;
- DATA_DAC_SET:
- if( send_done )
- next_state = DATA_DAC_SET_WAIT;
- else
- next_state = DATA_DAC_SET;
- DATA_DAC_SET_WAIT:
- if( FLAG )
- next_state = DATA_LDAC ;
- else
- next_state = DATA_DAC_SET_WAIT;
- // DATA_DAC_MOD:
- // if( send_done )
- // next_state = DATA_DAC_MOD_WAIT ;
- // else
- // next_state = DATA_DAC_MOD;
- // DATA_DAC_MOD_WAIT:
- // if( FLAG )
- // next_state = DATA_LDAC ;
- // else
- // next_state = DATA_DAC_MOD_WAIT;
- DATA_LDAC:
- if( send_done )
- next_state = DATA_OUTPUT ;
- else
- next_state = DATA_LDAC;
- DATA_OUTPUT:
- if( send_done )
- next_state = DATA_REQ_DAC ;
- else
- next_state = DATA_OUTPUT;
- DATA_REQ_DAC:
- if( send_done)
- next_state = DATA_REQ_DAC_WAIT ;
- else
- next_state = DATA_REQ_DAC;
- DATA_REQ_DAC_WAIT:
- if( FLAG )
- next_state = DATA_LDAC ;
- else
- next_state = DATA_REQ_DAC_WAIT;
- DAC_read:
- if( send_done )
- next_state = DAC_nop;
- else
- next_state = DAC_read;
- DAC_nop:
- if( send_done )
- next_state = DATA_REQ_DAC;
- else
- next_state = DAC_nop;
-
-
- default :
- next_state = DATA_IDLE;
- endcase
- end
- always @ ( posedge clk ) begin
- if(~locked) begin
- spi_clk_dly <= 1'b0;
- send_done_dly <= 1'b0;
- end
- else begin
- spi_clk_dly <=spi_clk_i;
- send_done_dly <= send_done;
- end
- end
- assign spi_clk_neg = spi_clk_dly && ~spi_clk_i;
- assign spi_clk_pos = (~spi_clk_dly )&& spi_clk_i;
- assign send_done_pos =( ~send_done_dly) && send_done;
- reg[7:0] nextCRC8_D24_tem;
- //assign send_trig =crc_out_en;
- assign send_data ={send_data_tem,nextCRC8_D24_tem};
- always@( posedge clk) begin
- if( ~locked ) begin
- send_trig <= 1'b0;
- nextCRC8_D24_tem <=8'b0;
- end
- if(crc_out_en) begin
- send_trig <= 1'b1;
- nextCRC8_D24_tem <= nextCRC8_D24;
-
- end
- else if(send_done)
- send_trig <= 1'b0;
- else
- send_trig <=send_trig;
- end
- always @ ( posedge clk ) begin
- if( ~locked ) begin
- send_trig_tem <= 1'b0;
- send_data_tem <= 24'b0;
- end
- else begin
- if( state == DATA_IDLE && ~send_done ) begin
- send_trig_tem <= 1'b0;
- send_data_tem <= 24'b0;
- end
- else if( state == DATA_FAULT && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h10,16'h005c}; //
- end
- else if( state == DATA_Key && ~send_done) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h08,16'hFCBA};
- end
- else if( state == DATA_CLEAR && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h14,16'h2000}; //
- end
- else if( state == DATA_REQ && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h09,16'h0644};
- end
- else if( state == DATA_DC_SET && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h0C,16'h010E};
- end
- else if( state == DATA_DC_MOD && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h0B,16'h0020};
- end
- else if( state == DATA_DAC_SET && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h06,16'h01a8};
- end
- else if( state == DATA_DAC_MOD && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h01,16'h0000};
- end
-
- else if( state == DATA_LDAC && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h07,16'h1DAC};
- end
- else if( state == DATA_OUTPUT && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h06,16'h01E8}; //D6 = 1
- end
- else if( state == DATA_REQ_DAC && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h01,data_reg2};
- end
-
- else if( state == DAC_read && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,5'h13,16'h02}; //读output寄存器
- end
- else if( state == DAC_nop && ~send_done ) begin
- send_trig_tem <= 1'b1;
- send_data_tem <= {DEVICE_ADRESS,NOP,16'h00};
- end
- else begin
- send_trig_tem <= 1'b0;
- end
- end
- end
-
- // 延时500us
- always@( posedge spi_clk_i or negedge locked)
- begin
- if( ~locked) begin
- cnt_500us <= 14'b0;
- FLAG <= 1'b0;
- end
- else begin
- if(state == DATA_Key_wait ) begin
- if(cnt_500us == 14'd1010 ) begin
- cnt_500us <= 1'b1;
- FLAG <= 1'b1;
- end
- else begin
- cnt_500us <= cnt_500us +14'b1;
- FLAG <= 1'b0;
- end
- end
- else if(state == DATA_DC_SET_WAIT ) begin
- if(cnt_500us == 14'd1010 ) begin
- cnt_500us <= 1'b0;
- FLAG <= 1'b1;
- end
- else begin
- cnt_500us <= cnt_500us +14'b1;
- FLAG <= 1'b0;
- end
- end
- else if(state == DATA_DC_MOD_WAIT ) begin
- if(cnt_500us == 14'd1010 ) begin
- cnt_500us <= 1'b0;
- FLAG <= 1'b1;
- end
- else begin
- cnt_500us <= cnt_500us +14'b1;
- FLAG <= 1'b0;
- end
- end
- else if(state == DATA_REQ_DAC_WAIT ) begin
- if(cnt_500us == 14'd16 ) begin
- cnt_500us <= 1'b0;
- FLAG <= 1'b1;
- end
- else begin
- cnt_500us <= cnt_500us +14'b1;
- FLAG <= 1'b0;
- end
- end
-
- else if(state == DATA_DAC_SET_WAIT ) begin
- if(cnt_500us == 14'd1010 ) begin
- cnt_500us <= 1'b0;
- FLAG <= 1'b1;
- end
- else begin
- cnt_500us <= cnt_500us +14'b1;
- FLAG <= 1'b0;
- end
- end
- else if(state == DATA_DAC_MOD_WAIT ) begin
- if(cnt_500us == 14'd16 ) begin
- cnt_500us <= 1'b0;
- FLAG <= 1'b1;
- end
- else begin
- cnt_500us <= cnt_500us +14'b1;
- FLAG <= 1'b0;
- end
- end
-
-
-
-
- else begin
- FLAG <= 1'b0;
-
- end
-
- end
- end
-
-
- gen_crc8 gen_crc8 (
- .clk(clk),
- .rst_n(locked),
- .crc_in_en(send_trig_tem),
- .Data(send_data_tem),
- .nextCRC8_D24(nextCRC8_D24),
- .crc_out_en(crc_out_en)
- );
-
-
-
- endmodule
复制代码 3、gen_crc8校验模块
gen_crc8 的模块用于生成8位循环冗余校验(CRC)码,模块包含时钟输入 clk,复位信号 rst_n,CRC输入使能 crc_in_en,待处理数据 Data(24位宽),以及CRC校验码输出 nextCRC8_D24 和输出使能 crc_out_en。
模块利用一个寄存器 crc_in_en_d0 来检测 crc_in_en 的边沿,即从0到1的跳变,这通常表示一个新数据块的到来。
在检测到 crc_in_en 的上升沿后,模块根据输入数据 Data 和当前的CRC寄存器值 nextCRC8_D24 来盘算新的CRC校验码。CRC的盘算利用了一系列异或(XOR)操作,这些操作界说了CRC的多项式。
- `timescale 1ns / 1ps
-
- module gen_crc8(
- input clk,
- input rst_n,
- input crc_in_en,
- input [23:0] Data,
- output reg [7:0] nextCRC8_D24,
- output reg crc_out_en
- );
- reg crc_in_en_d0=0;
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)
- crc_in_en_d0 <= 1'b0;
- else
- crc_in_en_d0 <= crc_in_en;
- end
-
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)
- nextCRC8_D24 <= 'd0;
- else if(!crc_in_en_d0 && crc_in_en)begin
- nextCRC8_D24[0] <= Data[23] ^ Data[21] ^ Data[19] ^ Data[18] ^ Data[16] ^ Data[14] ^ Data[12] ^ Data[8] ^ Data[7] ^ Data[6] ^ Data[0] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[3] ^ nextCRC8_D24[5] ^ nextCRC8_D24[7];
- nextCRC8_D24[1] <= Data[23] ^ Data[22] ^ Data[21] ^ Data[20] ^ Data[18] ^ Data[17] ^ Data[16] ^ Data[15] ^ Data[14] ^ Data[13] ^ Data[12] ^ Data[9] ^ Data[6] ^ Data[1] ^ Data[0] ^ nextCRC8_D24[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4] ^ nextCRC8_D24[5] ^ nextCRC8_D24[6] ^ nextCRC8_D24[7];
- nextCRC8_D24[2] <= Data[22] ^ Data[17] ^ Data[15] ^ Data[13] ^ Data[12] ^ Data[10] ^ Data[8] ^ Data[6] ^ Data[2] ^ Data[1] ^ Data[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[6];
- nextCRC8_D24[3] <= Data[23] ^ Data[18] ^ Data[16] ^ Data[14] ^ Data[13] ^ Data[11] ^ Data[9] ^ Data[7] ^ Data[3] ^ Data[2] ^ Data[1] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[7];
- nextCRC8_D24[4] <= Data[19] ^ Data[17] ^ Data[15] ^ Data[14] ^ Data[12] ^ Data[10] ^ Data[8] ^ Data[4] ^ Data[3] ^ Data[2] ^ nextCRC8_D24[1] ^ nextCRC8_D24[3];
- nextCRC8_D24[5] <= Data[20] ^ Data[18] ^ Data[16] ^ Data[15] ^ Data[13] ^ Data[11] ^ Data[9] ^ Data[5] ^ Data[4] ^ Data[3] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4];
- nextCRC8_D24[6] <= Data[21] ^ Data[19] ^ Data[17] ^ Data[16] ^ Data[14] ^ Data[12] ^ Data[10] ^ Data[6] ^ Data[5] ^ Data[4] ^ nextCRC8_D24[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[3] ^ nextCRC8_D24[5];
- nextCRC8_D24[7] <= Data[22] ^ Data[20] ^ Data[18] ^ Data[17] ^ Data[15] ^ Data[13] ^ Data[11] ^ Data[7] ^ Data[6] ^ Data[5] ^ nextCRC8_D24[1] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4] ^ nextCRC8_D24[6];
- end
- end
- always @(posedge clk)begin
- crc_out_en <= !crc_in_en_d0 && crc_in_en;
- end
- endmodule
复制代码 这个模块是数据传输中确保数据完备性的一个重要组件,通过CRC校验可以检测数据在传输过程中是否出现错误。如果CRC校验失败,体系可以接纳相应的步调来纠正或重新发送数据。
三、结尾
本文重要形貌怎样利用FPGA驱动DAC芯片AD5753,已经在开发板上验证乐成。使得设置完成之后,可以正常的控制dac的输出。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |