国产紫光FPGA实现DDS信号发生器

本文详细介绍了如何在紫光FPGA上使用PDS软件实现DDS,包括新建工程、添加源文件、编写DDS程序、配置IP核、编译综合、布局布线、生成bit流并下载到开发板的过程。内容涵盖按键切换波形、频率,以及不同波形(正弦、方波、三角、锯齿)的生成。最后展示了100Hz和3.5kHz四种波形的输出结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要参考https://blog.csdn.net/syyzuiqiang/article/details/118103211?spm=1001.2014.3001.5501一文,在国产的紫光FPGA上实现DDS,使用的EDA软件是紫光PDS,开发板是国产紫光同创PGL22G-6MBG324(软件下载地址PDS Lite软件-紫光同创 (pangomicro.com),该版本为试用版)

一、下载PDS、新建工程添加源文件

(1)首先在紫光的官网上下载PDS,安装完成后打开软件

选择New Project新建工程

设置工程名及保存目录,创建子目录然后点击Next

选择RTL project 点击Next

进入添加设计文件界面,这里我们先不添加,按照上图勾选,然后点击Next

进入添加IP界面,按照上图勾选,然后点击Next

进入添加约束文件界面,按照上图勾选,然后点击Next

根据自己使用的板子选择对应的芯片,这里我使用的是Logos系列的PGL22G-6MBG324,然后点击next,finish工程建立完成。

(2)添加设计文件

右键Design,选择Add Source

选择添加或创建设计文件 Next

选择创建文件 Next

起好名字 OK,到这里就完成了新建工程与设计文件的添加。

二、DDS程序的编写

接下来就是程序的编写,由于我用的这块板子上没有拨码开关,所以使用的是按键切换波形和频率,如果板子上有拨码开关的话建议参考本文开头引用的文章的程序

(1)首先是顶层设计文件

module dds_1
   (clk,
    rst,
    key_1,        //按键1切换频率
    key_2,        //按键2切换波形
    da_clk,       //输出DAC时钟
    data);        //11位数据输出
    input clk;
    input rst;
    input key_1;
    input key_2;
    output da_clk;
    output reg [11:0] data;
    reg [2:0] mode = 2'b0;
    reg key_2_0 = 1;
    reg key_2_1 = 1, key_2_enen = 1;
    wire [11:0] sin_wave_douta;
    wire [11:0] saw_wave_douta;
    wire [11:0] sawtooth_wave_douta;
    wire [11:0] square_wave_douta;
    wire [11:0] addra;
    wire add_mode;
    wire end_mode;
    wire non;
//按键切换波形模式,低电平有效
assign da_clk = clk;
always @(posedge clk or negedge rst)  
begin
    if(!rst) begin
        key_2_0 <= 0;
        key_2_1 <= 0;
    end
    else begin
        key_2_1 <= key_2_enen;
        key_2_0 <= key_2_1;
    end
end
assign key_2_en = key_2_0&&(~key_2_1);//检测到按键按下(下降沿)
//按键消抖,按下延时20ms后检测
    reg [0:21] del_cnt = 0;
    wire add_del;
    wire end_del;
always @(posedge clk or negedge rst)  
begin
    if(!rst) begin      //低电平有效
        del_cnt<=0;
    end    
    else if(add_del) begin
        if(end_del)
            del_cnt<=0;
        else 
            del_cnt<=del_cnt+1;
    end
    else 
        del_cnt<=0;
    
end
assign add_del = ~key_2;
assign end_del = add_del && del_cnt==1000000-1;
always @(posedge clk )  
begin
    if (end_del)
       key_2_enen<=0;
    else if (key_2) 
       key_2_enen<=1;
end
//波形控制
always @(posedge clk or negedge rst)  
begin
    if(!rst) begin      //低电平有效
        mode<=2'b0;
    end    
    else if(add_mode) begin
        if(end_mode)
            mode<=2'b0;
        else
            mode<=mode+1;
    end
end
assign add_mode=key_2_en;     //高电平有效
assign end_mode=add_mode&&mode==3;
//例化IP
assign non = 0;
    sin u_1
    (.addr(addra),
     .clk(clk),
     .rd_data(sin_wave_douta),
     .rst(non)
    );
    saw u_2
    (.addr(addra),
     .clk(clk),
     .rd_data(saw_wave_douta),
     .rst(non)
    );
     sawtooth u_3
    (.addr(addra),
     .clk(clk),
     .rd_data(sawtooth_wave_douta),
     .rst(non)
    );
    square u_4
    (.addr(addra),
     .clk(clk),
     .rd_data(square_wave_douta),
     .rst(non)
    );  
    count u_0
    (.clk_c(clk),
     .rst_c(rst),
     .key_1(key_1),
     .q(addra)
    );
//按键切换波形
always @(posedge clk)begin
    case(mode)
            1 : data = sin_wave_douta;
            3 : data = saw_wave_douta;
            2 : data = sawtooth_wave_douta;
            0 : data = square_wave_douta;
            default : data = square_wave_douta;
    endcase
end

endmodule

(2)然后是相位累加器模块

module count
    (clk_c,
     rst_c,
     key_1,
     q);
     input clk_c;
     input rst_c;
     input key_1;
     output [9:0] q;
     reg [31:0] fw = 8950;
     reg [31:0] cnt = 32'b0;
     reg key_1_0 = 1;
     reg key_1_1 = 1,key_1_enen = 1;
     reg [0:1] fwcnt = 0;
     wire add_fwcnt;
     wire end_fwcnt;
     wire key_1;
//切换频率
always @(posedge clk_c or negedge rst_c)  
begin
    if(!rst_c) begin
        key_1_0 <= 0;
        key_1_1 <= 0;
    end
    else begin
        key_1_1 <= key_1_enen;
        key_1_0 <= key_1_1;
    end
end
assign key_1_en = key_1_0&&(~key_1_1);//低电平有效

    reg [0:21] del_cnt = 0;
    wire add_del;
    wire end_del;
always @(posedge clk_c or negedge rst_c)  
begin
    if(!rst_c) begin      //低电平有效
        del_cnt<=0;
    end    
    else if(add_del) begin
        if(end_del)
            del_cnt<=0;
        else 
            del_cnt<=del_cnt+1;
    end
    else 
        del_cnt<=0;
    
end
assign add_del = ~key_1;
assign end_del = add_del && del_cnt==1000000-1;
always @(posedge clk_c )  
begin
    if (end_del)
       key_1_enen<=0;
    else if (key_1) 
       key_1_enen<=1;
end

always @(posedge clk_c or negedge rst_c) //高电平有效
begin
    if(!rst_c) begin      //低电平有效
        fwcnt<=0;
    end    
    else if(add_fwcnt) begin
         
         if(end_fwcnt)
            fwcnt<=0;
         else
            fwcnt<=fwcnt+1;
    end
end
assign add_fwcnt=key_1_en;     //高电平有效
assign end_fwcnt=add_fwcnt&&fwcnt==3;

always @(posedge clk_c)
begin
    case(fwcnt)
            0 : fw = 8590; //100HZ
            1 : fw = 42949;//500HZ
            2 : fw = 128849;//1500HZ
            3 : fw = 300647;//3500HZ
            default : fw = 8590;
    endcase
end
     
always @(posedge clk_c or negedge rst_c)
begin
    if(!rst_c) begin      //低电平有效
        cnt<=0;
    end    
    else 
        cnt<=cnt+fw;
end

assign q = cnt[31:22];

endmodule

(3)接下来是导入ROM

在工具栏找到IP或者可以通过右键设计文件添加

选中ROM,起好名字,点击Customize

在这里进行IP核的配置,在这里需要添加IP核的初始化文件sin.dat。PDS的初始化文件支持十六进制和二进制,格式相对比较简单,只要把十六进制或二进制数据写入到.dat文件中即可,这里我用的是matlab生成的初始化文件,具体方法如下:

首先是代码,用matlab生成正弦波(这里的地址深度为10即共有1024个数据,数据宽度是12即正弦波峰处为4095)

x = linspace(0,6.28,1024); %在0和2pi间取1024个点
y2 = sin (x)+1;
y3 = sawtooth (x,0.5)+1;
y4 = sawtooth (x,1)+1;
y5 = square (x)+1;
y2 =round (y2 * 2047);
y3 = round(y3 * 2047);
y4 = round(y4 * 2047);
y5 = round(y5 * 2047);
fid = fopen('c:/sin.txt','wt'); % 生成TXT文件
fprintf(fid,'%x\n',y2);
fclose(fid);
fid = fopen('c:/sawtooth.txt','wt'); % 生成TXT文件
fprintf(fid,'%x\n',y3);
fclose(fid);
fid = fopen('c:/saw.txt','wt'); % 生成TXT文件
fprintf(fid,'%x\n',y4);
fclose(fid);
fid = fopen('c:/square.txt','wt'); % 生成TXT文件
fprintf(fid,'%x\n',y5);
fclose(fid);

运行过后就会在c盘中生成四种波形数据的.txt文件,这时只需要将后缀改成.dat即可,然后导入到初始化文件

点击Generate,生成IP核

三、编译,综合,布局布线及添加约束文件

(1)编译,综合

(2)添加约束文件

PDS的约束文件可以通过手写代码或者图形界面来配置,这里介绍图形界面配置引脚的方法

①首先在工具栏上找到User Constraint Editor

②选中Device,点击I/O

③具体引脚分配情况如下

也可添加代码

define_attribute {p:data[11]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[11]} {PAP_IO_LOC} {P11}
define_attribute {p:data[11]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[11]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[11]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[11]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[10]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[10]} {PAP_IO_LOC} {T13}
define_attribute {p:data[10]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[10]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[10]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[10]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[9]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[9]} {PAP_IO_LOC} {R13}
define_attribute {p:data[9]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[9]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[9]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[9]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[8]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[8]} {PAP_IO_LOC} {P13}
define_attribute {p:data[8]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[8]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[8]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[8]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[7]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[7]} {PAP_IO_LOC} {P14}
define_attribute {p:data[7]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[7]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[7]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[7]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[6]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[6]} {PAP_IO_LOC} {R15}
define_attribute {p:data[6]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[6]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[6]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[6]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[5]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[5]} {PAP_IO_LOC} {R14}
define_attribute {p:data[5]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[5]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[5]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[5]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[4]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[4]} {PAP_IO_LOC} {T16}
define_attribute {p:data[4]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[4]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[4]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[4]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[3]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[3]} {PAP_IO_LOC} {R16}
define_attribute {p:data[3]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[3]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[3]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[3]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[2]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[2]} {PAP_IO_LOC} {U16}
define_attribute {p:data[2]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[2]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[2]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[2]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[1]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[1]} {PAP_IO_LOC} {V16}
define_attribute {p:data[1]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[1]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[1]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[1]} {PAP_IO_SLEW} {FAST}
define_attribute {p:data[0]} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:data[0]} {PAP_IO_LOC} {V18}
define_attribute {p:data[0]} {PAP_IO_VCCIO} {3.3}
define_attribute {p:data[0]} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:data[0]} {PAP_IO_DRIVE} {4}
define_attribute {p:data[0]} {PAP_IO_SLEW} {FAST}
define_attribute {p:da_clk} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:da_clk} {PAP_IO_LOC} {P12}
define_attribute {p:da_clk} {PAP_IO_VCCIO} {3.3}
define_attribute {p:da_clk} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:da_clk} {PAP_IO_DRIVE} {4}
define_attribute {p:da_clk} {PAP_IO_SLEW} {FAST}
define_attribute {p:clk} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:clk} {PAP_IO_LOC} {B5}
define_attribute {p:clk} {PAP_IO_VCCIO} {3.3}
define_attribute {p:clk} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:key_1} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:key_1} {PAP_IO_LOC} {V12}
define_attribute {p:key_1} {PAP_IO_VCCIO} {3.3}
define_attribute {p:key_1} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:key_2} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:key_2} {PAP_IO_LOC} {P17}
define_attribute {p:key_2} {PAP_IO_VCCIO} {3.3}
define_attribute {p:key_2} {PAP_IO_STANDARD} {LVCMOS33}
define_attribute {p:rst} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:rst} {PAP_IO_LOC} {U12}
define_attribute {p:rst} {PAP_IO_VCCIO} {3.3}
define_attribute {p:rst} {PAP_IO_STANDARD} {LVCMOS33}
#define_attribute {p:data[11]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[10]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[9]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[8]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[7]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[6]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[5]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[4]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[3]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[2]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[1]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[0]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:da_clk} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:clk} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:key_1} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:key_2} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:rst} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[11]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[10]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[9]} {PAP_IO_REGISTER} {TRUE}
#define_attribute {p:data[8]} {PAP_IO_REGISTER} {TRUE}
define_attribute {p:key_1} {PAP_IO_PULLUP} {TRUE}
define_attribute {p:key_1} {PAP_IO_HYS_DRIVE_MODE} {NOHYS}
define_attribute {p:key_2} {PAP_IO_PULLUP} {TRUE}
define_attribute {p:key_2} {PAP_IO_HYS_DRIVE_MODE} {NOHYS}

(3)布局布线

四、生成bit流并下载到板子中

点击Generate Bitstream,生成bit流文件

接下来将bit流文件下载到板子中

(1)首先将板子接好,点击Configuration

(2)点击scan device,连接开发板

(3)选择bit流文件,点击open

(4)右键选择program,进行程序的下载

以上下载bit流文件的方式掉电之后会消失,如果要将程序固化到flash中还需进行以下操作

1. 首先,需要 sbit 文件转换成能下载的 flash 的 sfc 文件。在完成下载和调试后,选择菜 单"Operations"下"Convert File"进行文件转换。

2.然后弹出如下界面,这里要根据硬件的 flash 型号来选择 flash 的厂家和设备型号,开发板用到的是 WINBOND 的 W25Q128Q。Flash Read Mode 选择 SPI X4 然后选择要转换的 sbit 文件, 点击 OK 即可转换

3.右键,选择Scan Outer Flash,选中刚刚生成的.sfc文件open

4.右键Outer Flash,program下载完成

五、结果展示

(1)100Hz正弦波

(2)100Hz方波

(3)100Hz三角波

(4)100Hz锯齿波

(5)3.5kHz正弦波

(6)3.5kHz方波

(7)3.5kHz三角波

(8)3.5kHz锯齿波

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值