lcytms
发表于 2017-2-10 13:41:41
本帖最后由 lcytms 于 2017-2-10 13:53 编辑
先从DA驱动逻辑模块dac.v做起吧!
新建工程文件夹dac。
新建dac.v文件。
`define T0 0
`define T1 `T0+100
`define T2 `T1+100
`define T3 `T2+100
`define T4 `T3+100
`define T5 `T4+100
`define T6 `T5+100
`define T7 `T6+100
`define T8 `T7+100
`define T9 `T8+100
`define T10 `T9+100
`define T11 `T10+100
`define T12 `T11+100
`define TS `T12+100 // 1300
module dac (clk, rst_n, ctrl_word, req, da_clk, da_ldac, da_load, da_data, req_done);
input clk,rst_n;
input req;
input ctrl_word;
output reg da_clk;
output reg da_ldac;
output reg da_load;
output reg da_data;
output reg req_done;
reg cnt;
reg ctrl_word_r;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
cnt <= `TS;
else
begin
if (!req)
cnt <= `TS;
else
begin
if (cnt < `TS)
cnt <= cnt + 11'd1;
else
cnt <= 0;
end
end
end
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
da_clk <= 0;
da_ldac <= 0;
da_load <= 0;
da_data <= 0;
ctrl_word_r <= ctrl_word;
req_done<=0;
end
else
begin
case(cnt)
`T0 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T0+50 : da_clk <= 0;
`T1 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T1+50 : da_clk <= 0;
`T2 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T2+50 : da_clk <= 0;
`T3 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T3+50 : da_clk <= 0;
`T4 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T4+50 : da_clk <= 0;
`T5 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T5+50 : da_clk <= 0;
`T6 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T6+50 : da_clk <= 0;
`T7 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T7+50 : da_clk <= 0;
`T8 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T8+50 : da_clk <= 0;
`T9 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T9+50 : da_clk <= 0;
`T10 : begin da_clk <= 1; da_data <= ctrl_word_r; end
`T10+50 : da_clk <= 0;
`T11 : da_load <= 0;
`T11+50 : da_load <= 1;
`T12 : da_ldac <= 0;
`T12+50 : da_ldac <= 1;
`T12+51 : req_done <= 1;
`T12+52 : req_done <= 0;
`TS : begin
da_clk <= 0;
da_ldac <= 1;
da_load <= 1;
da_data <= 0;
ctrl_word_r <= ctrl_word;
req_done <= 0;
end
default : ;
endcase
end
end
endmodule
lcytms
发表于 2017-2-10 13:55:21
本帖最后由 lcytms 于 2017-2-10 13:57 编辑
向工程文件夹添加第六讲的单独按键消抖模块key_flag.v。
module key_flag (clk, rst_n, key_n, key_out);
input clk, rst_n;
input key_n;
output key_out;
reg click_n;
parameter MASK_TIME = 500_000; // 10ms/20ns=500_000,for checking key hold time
reg cnt;
reg state;
localparam s0 = 1'b0,
s1 = 1'b1;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
cnt <= 0;
click_n <= 1;
state <= s0;
end
else
begin
case (state)
s0 : begin
if (key_n)
begin
cnt <= 0;
click_n <= 1;
state <= s0;
end
else
begin
if (cnt < MASK_TIME - 1)
begin
cnt <= cnt + 19'b1;
state <= s0;
end
else
begin
cnt <= 0;
click_n <= 0;
state <= s1;
end
end
end
s1 : begin
if (!key_n)
begin
cnt <= 0;
click_n <= 0;
state <= s1;
end
else
begin
if (cnt < MASK_TIME - 1)
begin
cnt <= cnt + 19'b1;
state <= s1;
end
else
begin
cnt <= 0;
click_n <= 1;
state <= s0;
end
end
end
default : state <= s0;
endcase
end
end
reg click_r_n;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
click_r_n <= 1;
else
click_r_n <= click_n;
end
assign key_out = click_r_n & ~click_n;
endmodule
lcytms
发表于 2017-2-10 14:02:18
本帖最后由 lcytms 于 2017-2-10 14:06 编辑
新建DAC控制器模块dac_controller.v。
module dac_controller (clk, rst_n, flag, req_done, req, ctrl_word);
input clk, rst_n;
input flag;
input req_done;
output reg req;
output reg ctrl_word;
reg cnt_switch;
reg state;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt_switch <= 0;
req <= 1;
state <= 0;
end
else
begin
case (state)
0 : begin // waiting for 1st key, clear in cycle
if (flag)
begin
cnt_switch <= 0;
state <= 1;
end
else
begin
if (req_done)
cnt_switch <= cnt_switch + 2'b1;
else
req <= 1;
end
end
1 : begin // switch channel if any key pressed
if (flag)
cnt_switch <= cnt_switch + 2'b1;
else
req <= 1;
end
endcase
end
end
always @ (*)
begin
case({state, cnt_switch})
3'b0_00 : ctrl_word = 11'b00_0_0000_0000; // ch0, 0v for clearing
3'b0_01 : ctrl_word = 11'b01_0_0000_0000; // ch1, 0v for clearing
3'b0_10 : ctrl_word = 11'b10_0_0000_0000; // ch2, 0v for clearing
3'b0_11 : ctrl_word = 11'b11_0_0000_0000; // ch3, 0v for clearing
3'b1_00 : ctrl_word = 11'b00_0_0010_0000; // ch0, 0.3125v
3'b1_01 : ctrl_word = 11'b01_1_0010_0000; // ch1, 0.625v
3'b1_10 : ctrl_word = 11'b10_0_1000_0000; // ch2, 1.25v
3'b1_11 : ctrl_word = 11'b11_1_1000_0000; // ch3, 2.5v
endcase
end
endmodule
lcytms
发表于 2017-2-10 14:08:18
本帖最后由 lcytms 于 2017-2-10 14:13 编辑
新建top.v顶层模块,将以上三个模块都加入到top.v顶层模块中进行例化。
将top.v模块设置为顶层模块。
编写top.v模块如下。
module top (clk, rst_n, key_n, da_clk, da_ldac, da_load, da_data);
input clk, rst_n;
input key_n;
output da_clk;
output da_ldac;
output da_load;
output da_data;
wire key_out;
wire req;
wire ctrl_word;
wire req_done;
parameter MASK_TIME = 500_000; // 10ms/20ns=500_000,for checking key hold time
key_flag #(MASK_TIME) key_flag(
.clk(clk),
.rst_n(rst_n),
.key_n(key_n),
.key_out(key_out)
);
dac_controller dac_controller (
.clk(clk),
.rst_n(rst_n),
.flag(key_out),
.req_done(req_done),
.req(req),
.ctrl_word(ctrl_word)
);
dac dac(
.clk(clk),
.rst_n(rst_n),
.ctrl_word(ctrl_word),
.req(req),
.da_clk(da_clk),
.da_ldac(da_ldac),
.da_load(da_load),
.da_data(da_data),
.req_done(req_done)
);
endmodule
lcytms
发表于 2017-2-10 14:15:01
本帖最后由 lcytms 于 2017-2-10 14:22 编辑
进行分析综合检查。
编写Testbench。
新建top_tb.v文件。
`timescale 1ns/1ps
module top_tb;
reg clk, rst_n;
reg key_n;
wire da_clk;
wire da_ldac;
wire da_load;
wire da_data;
top #(.MASK_TIME(5)) dut (
.clk(clk),
.rst_n(rst_n),
.key_n(key_n),
.da_clk(da_clk),
.da_ldac(da_ldac),
.da_load(da_load),
.da_data(da_data)
);
initial
begin
clk = 1;
rst_n = 0;
key_n = 1;
#200.1
rst_n = 1;
#22_000 key_n = 0; #1000 key_n = 1;
#26_000 key_n = 0; #1000 key_n = 1;
#26_000 key_n = 0; #1000 key_n = 1;
#26_000 key_n = 0; #1000 key_n = 1;
#30_000 $stop;
end
always #10 clk = ~clk;
endmodule
lcytms
发表于 2017-2-10 14:21:48
本帖最后由 lcytms 于 2017-2-10 16:42 编辑
进行分析综合检查。
进行仿真设置。
查看仿真结果。
da_clk时钟每次转换依次输出11个脉冲,对应11位的控制字。
转换开始时,da_load、da_ldac信号均为高电平。
da_clk时钟上升沿数据更新,下降沿时采样有效。
11个脉冲输出完毕之后,依次输出da_load、da_ldac的低电平脉冲。
时间间隔满足设计要求。
仿真功能正确。
lcytms
发表于 2017-2-10 14:26:53
本帖最后由 lcytms 于 2017-2-14 11:51 编辑
参照.tcl文件设置好FPGA管脚
参照EP4CE6E22C8N.tcl文件内容,对FPGA芯片管脚进行设置。
EP4CE6E22C8N.tcl文件相关内容如下所示。
FPGA芯片配置结果如图所示。
#set_global_assignment -name FAMILY "Cyclone IV"
#set_global_assignment -name DEVICE ep4ce6e22c8n
set_location_assignment PIN_23 -to clk
# KEY 轻触按键
set_location_assignment PIN_69 -to key
set_location_assignment PIN_70 -to key
# DA
set_location_assignment PIN_86 -toda_data
set_location_assignment PIN_85 -toda_clk
set_location_assignment PIN_84 -toda_ldac
set_location_assignment PIN_83 -toda_load
lcytms
发表于 2017-2-10 14:30:16
.sof文件下载到FPGA
全编译FPGA工程,生成.sof文件,连接至芯ZX_2开发板并上电。
打开Programmer通过Jtag口,将.sof文件下载到FPGA进行在线仿真。
.sof文件下载界面如下图所示。
lcytms
发表于 2017-2-10 14:32:04
本帖最后由 lcytms 于 2017-2-10 14:33 编辑
开发板运行效果
开发板运行效果如下图所示。
经检查,开发板运行效果与设计相符。
程序下载后,我们通过一个按键对四路输出进行切换,使用数字万用表测量对应通道的输出电压,比较设置值与实测值是否一致。
比如,开发板上电重启或按下复位键后,四路输出均为0V;
按下切换按键1次时,通道1电压输出变为0.3125V,其余不变;
按下切换按键2次时,通道2电压输出变为0.625V,其余不变;
按下切换按键3次时,通道3电压输出变为1.25V,其余不变;
按下切换按键4次时,通道4电压输出变为2.5V,其余不变;
以上4次按完之后,四个通道电压应依次为0.3125V、0.625V、1.25V、2.5V。
功能验证正确。
lcytms
发表于 2017-2-10 14:35:39
好了,今天的课程就讲到这里。
通过今天的课程,我们学习了DA转换芯片工作的基本原理,并对DA驱动逻辑电路进行了建模和仿真,结合第六讲的单独按键消抖一起编写了一个完整的演示逻辑,进行了下板检查。
希望大家掌握DA转换芯片工作的基本原理,并熟练运用Verilog语言编写相关驱动逻辑。
更复杂的知识和技巧我们将逐步通过后面的课程展现给大家。
课程到此结束,谢谢大家的关注!