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语言编写相关驱动逻辑。
更复杂的知识和技巧我们将逐步通过后面的课程展现给大家。

课程到此结束,谢谢大家的关注!
页: 1 [2] 3
查看完整版本: FPGA初级课程第二十三讲 DA