当前位置:   article > 正文

ZYNQ学习笔记(二):按键控制DDS信号频率实验+仅有PL端(FPGA)逻辑资源的程序固化到SD卡_verilog dds按键控制

verilog dds按键控制


前言

本文是在:ZYNQ学习笔记(一):基于ZYNQ7020、AN108的DDS实验(VIO可控频率字)的基础上进一步修改。

一、设计需求、

在上一个实验的基础上:
把生成DDS信号的主频由50Mhz改为100Mhz
去掉VIO模块,替换为按键控制频率字
通过按键能够切换不同的输出频率,分别为:1,3,5,10,15,20,25,30Mhz
仅有PL端(FPGA)逻辑资源的程序固化

工程下载地址:KEY_DDS

二、程序设计与IP核配置、

顶层代码:

`timescale 1ns / 1ps
module key_dds(
    input       sys_clk,            
    input       rst_n,
    input       key1, //按键 key1
     //DA芯片接口
    output                da_clk,  
    output    [7:0]       da_data,  //输出给DA的数据
    //AD芯片接口
    input     [7:0]       ad_data,  //AD输入数据
    output                ad_clk            
    );

wire key1_value; //key1 消抖后的按键值
wire key1_flag;  //key1 消抖后的按键值的有效标志

key_debounce u_key1_debounce(
.rst_n (rst_n),
.clk (sys_clk),
.key (key1),
.key_value (key1_value),
.key_flag (key1_flag) 
);

wire     clk_100M;  
clk_wiz_0 pll_inst
   (
    // Clock out ports
    .clk_out1(ad_clk),     // 给ad_clk 25MHz的频率
    .clk_out2(clk_100M),
    // Status and control signals
    .reset(~rst_n), // input reset
   // Clock in ports
    .clk_in1(sys_clk)     // input clk_in1
 );
 
wire [23 : 0]   Fword;         
key_control  key_control_lg(
    .clk(sys_clk), 
    .rst_n(rst_n), 
    .key1_value(key1_value),
    .key1_flag(key1_flag),
    .Fword(Fword)
);

wire [0:0]      fre_ctrl_word_en;    
//output
wire [0 : 0]    m_axis_data_tvalid;
wire [7 : 0]    m_axis_data_tdata;
wire [0 : 0]    m_axis_phase_tvalid;
wire [23 : 0]   m_axis_phase_tdata;
 
assign          fre_ctrl_word_en = 1'b1;
dds_compiler_0 u_dds_compiler_0 (
  .aclk(clk_100M),                                                // input wire aclk

  .s_axis_config_tvalid(fre_ctrl_word_en),           // input wire s_axis_config_tvalid
  .s_axis_config_tdata(Fword),                            // input wire [23 : 0] s_axis_config_tdata
  
  .m_axis_data_tvalid(m_axis_data_tvalid),        // output wire m_axis_data_tvalid
  .m_axis_data_tdata(m_axis_data_tdata),          // output wire [7 : 0] m_axis_data_tdata
  .m_axis_phase_tvalid(m_axis_phase_tvalid),      // output wire m_axis_phase_tvalid
  .m_axis_phase_tdata(m_axis_phase_tdata)         // output wire [23 : 0] m_axis_phase_tdata
);

//DA数据发送
da_wave_send u_da_wave_send(
    .clk         (clk_100M), 
    .rst_n       (rst_n),
    .rd_data     (m_axis_data_tdata),
    .da_clk      (da_clk),  
    .da_data     (da_data)
    );
// ILA
ila_0 u_ila (
	.clk(ad_clk), // input wire clk
	.probe0(Fword), // input wire [23:0]  probe1 
	.probe1(da_data), // input wire [7:0]  probe2
	.probe2(ad_data) // input wire [7:0]  probe3
);
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

相较于实验一,程序做出的改进有:增加了按键消抖模块,它处理来自key1输入的按键信号,并输出消抖后的按键值和有效标志。clk_wiz_0 模块增加了一路100Mhz频率输出,用来给DDS还有DA数据发送模块提供时钟信号,删除了VIO模块,改用按键模块控制频率字。

PLL IP核配置如下:

这里除了保留提供给ADC采样的频率外,还要增加一个提供给DDS IP核的100Mhz时钟频率输出。

ILA IP核配置如下:

分别采集频率字、DA输出以及AD输入信号。

DDS IP核配置:

这里的Parameters选项设置,当用Hardware Parameters选项时,工程并不会报错,但是下载到板子上输出的频率并不是所预设的那些,但是当我更换为System Parameters选项,所设频率输出正常

后面我查找资料发现,System Parameters选项用于配置DDS IP核在整个系统中的全局性质和性能;而Hardware Parameters选项用于配置DDS IP核内部的硬件细节和运算方式,要用于优化DDS核的行为,这些参数通常更低级,与IP核的内部运算和控制有关。

当我使用PLL锁相环将系统时钟进行倍频,然后将倍频后的时钟信号输入到DDS IP核,在这种情况下是希望配置DDS核以适应整个系统的时钟设置和性能要求,关注点是DDS核如何与系统中的时钟倍频器协同工作,以生成正确的输出信号,所以应该是通过System Parameters来确定DDS核的基本工作方式。

此外Spurious Free Dynamic Range(sfdr)是意为无杂散动态范围,SFDR是指基波强度与最大杂波或谐波的强度之比,所以SFDR值越大则说明系统的噪声水平越低,灵敏度越高。SFDR 还决定了输出的数据位宽。

因为ADDA模块的位宽限制,Ootput Width最大只能等于8,所以我们把SDRF设置为48。

Frequency Resolution是意为频率分辨率,它决定了我们可以在频率域中分辨的最小频率间隔,更高的频率分辨率意味着我们可以更精确地分辨不同的频率成分。

频率分辨率与几个参数之间的关系:

这里我们还是同实验一一样,把Phase Width设为20,那么通过公式可以计算出Frequency Resolution的值~

这些也算对实验一DDS IP核知识的补充了。

按键消抖模块的代码:

`timescale 1ns / 1ps
module key_debounce(
    input clk , 
    input rst_n , 
    
    input key ,             //外部输入的按键值 
    output reg key_value ,  //消抖后的按键值 
    output reg key_flag     //消抖后的按键值的效标志
    );

//reg define
reg [19:0] cnt ;
reg key_reg ;

always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt <= 20'd0;
        key_reg <= 1'b1;
    end
    else begin
        key_reg <= key;             //将按键值延迟一拍  
        if(key_reg != key) begin    //检测到按键状态发生变化
            cnt <= 20'd100_0000;    //则将计数器置为20'd100_0000
                                    //即延时100_0000 * 20ns(1s/50MHz) = 20ms
        end
        else begin                  //如果当前按键值和前一个按键值一样,即按键没有发生变化
            if(cnt > 20'd0)         //则计数器递减到0
                cnt <= cnt - 1'b1;
            else
                cnt <= 20'd0;
        end
    end
end

//将消抖后的最终的按键值送出去 
always @ (posedge clk or negedge rst_n) begin 
    if(!rst_n) begin 
        key_value <= 1'b1; 
        key_flag <= 1'b0; 
    end 
    //在计数器递减到1时送出按键值 
    else if(cnt == 20'd1) begin 
        key_value <= key; 
        key_flag <= 1'b1; 
    end 
    else begin 
        key_value <= key_value; 
        key_flag <= 1'b0; 
    end 
end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

代码中的 if(key_reg != key) begin ,即每检测到按键被按下或松开,就让计数器从 100_0000 开始递减,时长 20ms。在这 20ms 期间,每当有抖动产生,计数器就被重置回 100_0000,即重新开始计时 20ms。

代码中的 else if(cnt == 20’d1) begin,只有在计数器递减到 1 时,即此时计数器计时完了 20ms,才会寄存按键的值。这样,每当按键被按下或松开,20ms 内的抖动就被消除了。

频率调节的代码:

`timescale 1ns / 1ps

module key_control(
    input           clk,
    input           rst_n,
    input           key1_value,    // 消抖后的按键值
    input           key1_flag,     // 消抖后的按键值的有效标志
    output reg [23:0] Fword
);

reg [2:0] key_count;      // 用于跟踪按键按下次数

always @(posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        Fword <= 'h28f5;   // 初始频率
        key_count <= 3'b000;  // 初始按键计数
    end else begin
        // 根据按键状态选择不同的频率
        if (key1_flag && key1_value) begin
            key_count <= key_count + 1'b1;
            if (key_count == 3'b111) begin
                key_count <= 3'b000; // 重置计数器
            end
        end
        case (key_count)
            3'b000: Fword <= 'h28f5; // 1MHz
            3'b001: Fword <= 'h7ae1; // 3MHz
            3'b010: Fword <= 'hcccc; // 5MHz
            3'b011: Fword <= 'h19999; //10MHz
            3'b100: Fword <= 'h26666; //15MHz
            3'b101: Fword <= 'h33333;//20MHz
            3'b110: Fword <= 'h40000;//25MHz
            3'b111: Fword <= 'h4cccc;//30MHz
        endcase
    end
end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

因为 key1_value为消抖后的按键值, key1_flag为消抖后的按键值的有效标志 ,只有当key1_flag的值为1时, key1_value的值才为真,所以当两者的值同为1时,代表按键真的被按下,此时记录按键状态加一 ,然后再根据按键状态选择不同的频率字~从而控制输出不同的频率信号。

DA数据发送模块代码同实验一,这里不再细说~

约束代码在原来的基础添加上按键的引脚分配:

########key N15 N16##################
set_property PACKAGE_PIN N15 [get_ports key1]
set_property IOSTANDARD LVCMOS33 [get_ports key1]
  • 1
  • 2
  • 3

最后所生成的RTL原理图:

三、连接测试、

将示波器与开发板相连,在比特文件下载到开发板后,观察示波器输出波形:

按下PL_KEY1,

继续按下观察波形频率~

不再进行一一展示
当我按下第八次,频率回到1Mhz,生成信号的频率虽有误差但基本吻合,至此就完成了设计需求的前三个任务~

四、程序固化、

上面的任务结束后,为避免每次测试都要与电脑连接就挺麻烦的~故尝试着把工程固化到板子上,

先了解一下固化的逻辑:

1.ZYNQ固化必须用到PS块。所以纯PL工程中需要新建一个block块,加入并配置PS。在 ZYNQ 中,PS 作为主器件,PL 可以看作是 PS 的一个外设,因此需要由 PS 来配置 PL。

2.配置完成后系统会新生成一个.v文件,再将自己原本要固化的代码例化进去编译生成新的bit文件。

3.在SDK里生成固化代码及BOOT.bin文件,并把BOOT.bin文件下载到SD卡里。

4.选用的固化启动方式为SD卡启动。现在开始固化的流程~

4.1、配置PS端

创建block块。

可自定义名称,我这里直接默认点“OK”

添加IP核

双击该模块

如图进行设置~,这里QSPI与SD卡启动我都使能了

对DDR3进行配置选择,黑金zynq 7020开发板的DDR3芯片(共计8Gbit),型号为H5TQ4G63AFR-PBC(兼容MT41J256M16RE-125)。

配置完成后,按图所示依次点击。

这里手动把两个clk连在一起,鼠标左键直接拖就行,不连会报错,编译不过去。

Ctrl+S保存,回到左边sources窗口,右击前面新建的design_1.bd块文件,选Generate Output Products

依次点击Generate~OK,完成后还是右击design_1.bd块文件,选第二个

完成后点击OK就可以~

4.2、例化代码

sources窗口点击刚生成的.v文件

把上面工程的顶层代码例化部分加入这个.v文件(源代码不能够动,直接加入就可),我分为了4部分加入

`timescale 1 ps / 1 ps

module design_1_wrapper
   (DDR_addr,
    DDR_ba,
    DDR_cas_n,
    DDR_ck_n,
    DDR_ck_p,
    DDR_cke,
    DDR_cs_n,
    DDR_dm,
    DDR_dq,
    DDR_dqs_n,
    DDR_dqs_p,
    DDR_odt,
    DDR_ras_n,
    DDR_reset_n,
    DDR_we_n,
    FIXED_IO_ddr_vrn,
    FIXED_IO_ddr_vrp,
    FIXED_IO_mio,
    FIXED_IO_ps_clk,
    FIXED_IO_ps_porb,
    FIXED_IO_ps_srstb,

///1///
    sys_clk,
    rst_n,
    key1,
    da_clk,
    da_data,
    ad_data,
    ad_clk
///
    );
    
///2///
    input       sys_clk;            
    input       rst_n;
    input       key1;
    output                da_clk;  
    output    [7:0]       da_data; 
    input     [7:0]       ad_data; 
    output                ad_clk;   
///

///3///
  key_debounce u_key1_debounce(
  .rst_n (rst_n),
  .clk (sys_clk),
  .key (key1),
  .key_value (key1_value),
  .key_flag (key1_flag) 
  );
 
   clk_wiz_0 pll_inst
   (
    .clk_out1(ad_clk),    
    .clk_out2(clk_100M),
    .reset(~rst_n), 

    .clk_in1(sys_clk) 
  );      

   key_control  key_control_lg(
    .clk(sys_clk), 
    .rst_n(rst_n), 
    .key1_value(key1_value),
    .key1_flag(key1_flag),
    .Fword(Fword)
   );
 
   dds_compiler_0 u_dds_compiler_0 (
  .aclk(clk_100M),                                 
  .s_axis_config_tvalid(fre_ctrl_word_en),       
  .s_axis_config_tdata(Fword),                    
  .m_axis_data_tvalid(m_axis_data_tvalid),       
  .m_axis_data_tdata(m_axis_data_tdata),          
  .m_axis_phase_tvalid(m_axis_phase_tvalid),      
  .m_axis_phase_tdata(m_axis_phase_tdata)        
);

   da_wave_send u_da_wave_send(
    .clk         (clk_100M), 
    .rst_n       (rst_n),
    .rd_data     (m_axis_data_tdata),
    .da_clk      (da_clk),  
    .da_data     (da_data)
    );

   ila_0 u_ila (
	.clk(ad_clk), 
	.probe0(Fword),  
	.probe1(da_data), 
	.probe2(ad_data) 
   ); 
///
    
  inout [14:0]DDR_addr;
  inout [2:0]DDR_ba;
  inout DDR_cas_n;
  inout DDR_ck_n;
  inout DDR_ck_p;
  inout DDR_cke;
  inout DDR_cs_n;
  inout [3:0]DDR_dm;
  inout [31:0]DDR_dq;
  inout [3:0]DDR_dqs_n;
  inout [3:0]DDR_dqs_p;
  inout DDR_odt;
  inout DDR_ras_n;
  inout DDR_reset_n;
  inout DDR_we_n;
  inout FIXED_IO_ddr_vrn;
  inout FIXED_IO_ddr_vrp;
  inout [53:0]FIXED_IO_mio;
  inout FIXED_IO_ps_clk;
  inout FIXED_IO_ps_porb;
  inout FIXED_IO_ps_srstb;

///4///
  wire key1_value;
  wire key1_flag;
  wire     clk_100M;
  wire [23 : 0]   Fword; 
  wire [0:0]      fre_ctrl_word_en;    
  wire [0 : 0]    m_axis_data_tvalid;
  wire [7 : 0]    m_axis_data_tdata;
  wire [0 : 0]    m_axis_phase_tvalid;
  wire [23 : 0]   m_axis_phase_tdata;
///

  wire [14:0]DDR_addr;
  wire [2:0]DDR_ba;
  wire DDR_cas_n;
  wire DDR_ck_n;
  wire DDR_ck_p;
  wire DDR_cke;
  wire DDR_cs_n;
  wire [3:0]DDR_dm;
  wire [31:0]DDR_dq;
  wire [3:0]DDR_dqs_n;
  wire [3:0]DDR_dqs_p;
  wire DDR_odt;
  wire DDR_ras_n;
  wire DDR_reset_n;
  wire DDR_we_n;
  wire FIXED_IO_ddr_vrn;
  wire FIXED_IO_ddr_vrp;
  wire [53:0]FIXED_IO_mio;
  wire FIXED_IO_ps_clk;
  wire FIXED_IO_ps_porb;
  wire FIXED_IO_ps_srstb;

  design_1 design_1_i
       (.DDR_addr(DDR_addr),
        .DDR_ba(DDR_ba),
        .DDR_cas_n(DDR_cas_n),
        .DDR_ck_n(DDR_ck_n),
        .DDR_ck_p(DDR_ck_p),
        .DDR_cke(DDR_cke),
        .DDR_cs_n(DDR_cs_n),
        .DDR_dm(DDR_dm),
        .DDR_dq(DDR_dq),
        .DDR_dqs_n(DDR_dqs_n),
        .DDR_dqs_p(DDR_dqs_p),
        .DDR_odt(DDR_odt),
        .DDR_ras_n(DDR_ras_n),
        .DDR_reset_n(DDR_reset_n),
        .DDR_we_n(DDR_we_n),
        .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
        .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
        .FIXED_IO_mio(FIXED_IO_mio),
        .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
        .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
        .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb));
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177

代码保存以后,把该文件置顶~

之后生成比特文件,此时我把生成的比特文件下载到板子上验证了一下,观察正常一切工作~

下面导出硬件~

勾选包含比特文件~

4.3、利用SDK生成BOOT.BIN文件

启动SDK软件 File→Launch SDK,弹出的页面依次点击OK,在SDK页面如图所示:

输入名称为FSBL,之后点击“Next”~

接下来的页面选ZYNQ FSBL,然后点Finish~

下面生成BOOT.BIN启动文件:

选择输出位置:

页面右下方点击Add,添加生成的FSBL.elf文件。

同样的步骤添加比特文件

两个文件都添加后,点击页面底部的Great Image

此时,你可以在之前设置的输出位置找到BOOT.bin文件~

4.4、固化结果测试

拷贝文件到SD卡的boot分区,开发板设置为SD卡启动模式,连接示波器,开发板上电观察:

可以看到已经固化成功~

总结

通过本次实验,我们成功地实现了一个DDS系统,验证了通过按键使DDS信号输出频率在1MHz、3MHz、5MHz、10MHz、15MHz、20MHz、25MHz和30MHz之间切换,并且在每个频率下保持稳定。此外还完成了对这个仅有PL端(FPGA)逻辑资源的DDS工程进行程序固化。这算是在zynq的学习上又前进了小小的一步~

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号