基于iCE40UP5K的DDS信号发生器
基于iCE40UP5K制作的DDS信号发生器,可以产生指定频率的方波,锯齿波,三角波,正弦波
标签
FPGA
显示
DDS
信号发生器
2022寒假在家练
按键控制
Sherlock
更新2022-03-02
山东大学
899

一、项目介绍

iCE40UP5K由于其独特的性能得到海外创客们的热捧,尤其是其支持开源的开发工具链。不少RISC-V软核都是运行在iCE40UP5K上,基于这个大背景我们开发了一款FPGA核心模块,主要特点:

  • 兼容树莓派基金会刚推出的Pico模块的管脚定义,Pico的GPIO性能比较强大,因此玩家可以对比Pico和FPGA IO管脚的使用,另外也可以借助位PICO推出的各种外设模块(本模块没有串行ADC的功能,只能支持数字端口的模块);
  • 板上集成了基于DAPLink下载功能的STEPLINK功能,可以直接通过USB端口对FPGA的串行Flash进行配置,并可以通过同一个USB端口支持UART通信;
  • 有开源的RISC-V可以移植使用,进而学习在FPGA上完成软核+FPGA的异构设计

本设计基于Lattice的ICE40UP5K FPGA,板载LPC11U35下载器,可以通过USB-C接口进行FPGA的配置,支持在ICE40UP5K上对RISC-V软核的移植以及开源的FPGA开发工具链,板上RGB三色LED灯用于简单的调试,总计28个IO用于扩展使用。

扩展板板上有:

  • 2个按键输入

  • 4个单色LED

  • 12个WS2812B RGB三色灯

  • 1个姿态传感器

  • 1个128*64 OLED显示屏

  • 1个蜂鸣器

  • 1个可调电位计(用于电压表)

  • 1路音频信号输入(用于示波器)

  • 8位R-2R电阻网络构成的DAC(用于DDS信号发生器)

所用板卡

项目成果,实现了波形从10Hz到3MHz可调输出(最大可到10MHz但波形出现较大抖动),最小步进10Hz,信号幅值可由电位器进行调整,并同时将当前输出的波形,幅值,波形类型,频率显示在屏幕上。

二、项目使用说明

项目使用了4个按键分别用于系统的控制,由于所使用的板卡上只有3个按键,所以外接了一个按键,四个按键的功能分别是K1用来选择调整频率的位数,K2用来调整频率,RUN用作全局复位按键,外接的按键用于切换波形输出模式。

Fp0ScSjgBWfmKTHIryk5lOgzmXUK

FjiM9vlR-j8h-QyjUw2ERogk9Z2H

用模拟示波器产看输出波形。

三、代码讲解

文件DDS_MAIN.v中,有各模块的例化,是系统的TOP_module

module DDS_MAIN (
           input  wire clk,
           input  wire rstn,
		   //ADC
           input  wire i_analog_cmp,
           output wire o_analog_out,
           output wire o_sample_rdy,

           output wire led,
		   //DAC
           output wire [7:0] dac_data,
		   //KEY
           input  wire K1,
           input  wire K2,
           input  wire K3,
		   //OLED
           output wire oled_spi_RSTn,
           output wire oled_spi_DC,
           output wire oled_spi_CLK,
           output wire oled_spi_MOSI,

           //output wire PWM_Beep

       );

wire clk_120m;
wire clk_12m;
//使用PLL将时钟倍频到120M,用来输出频率幅度更大的波形
pll_120M pll(
             .ref_clk_i(clk),
             .rst_n_i(rstn),
             .outglobal_o(clk_120m)
         );
//由于pll的输入时钟只能用于PLL的输入,不能用于其他模块,同时没找到pll输出两路指定频率的办法,所以使用内置晶振产生一路12m时钟,给除DDS以外的其他模块使用
HSOSC
    #(
        .CLKHF_DIV ("0b10")
    ) HSOSC (
        .CLKHFPU (1'b1),  // I
        .CLKHFEN (1'b1),  // I
        .CLKHF   (clk_12m)   // O
    );


wire [2:0] dds_mode;
wire [2:0] multiple_mode;
wire [3:0] add_num;
reg [23:0] freq_save;
//K3用来切换不同输出波形
key_mode
    #(
        .N(4),
        .bit(3)
    ) u_key_mode_K3 (
        .sclk      (clk_12m)        ,
        .s_rst_n   (rstn)           ,
        .key_in    (K3)             ,
        .mode      (dds_mode)
    );
//K1用来选择频率的位数
key_mode #(
             .N(6),
             .bit(3)
         ) u_key_multiple_K1(
             .sclk      (clk_12m)        ,
             .s_rst_n   (rstn)           ,
             .key_in    (K1)             ,
             .mode      (multiple_mode)
         );
//K2用来调整频率
key_mode #(
             .N(10),
             .bit(4)
         ) u_key_add_K2(
             .sclk      (clk_12m)           ,
             .s_rst_n   (K1)                ,
             .key_in    (K2)                ,
             .mode      (add_num)
         );

always @(negedge K2 or negedge rstn) begin
	if(!rstn) freq_save <= 24'h100;
	else if(!K2)begin
    case (multiple_mode)
        3'd0:freq_save[3 :0 ] <= add_num;
        3'd1:freq_save[7 :4 ] <= add_num;
        3'd2:freq_save[11:8 ] <= add_num;
        3'd3:freq_save[15:12] <= add_num;
        3'd4:freq_save[19:16] <= add_num;
        3'd5:freq_save[23:20] <= add_num;
    endcase
    end
end

//例化adc模块,用来控制dac的输出幅值
wire [7:0] adc_data;
ADC_top ADC(
            .i_clk_in(clk_12m), //comment out to use internal clock
            .i_rst_in(rstn),
            .i_analog_cmp(i_analog_cmp),
            .o_digital_out(adc_data),
            .o_analog_out(o_analog_out),
            .o_sample_rdy(o_sample_rdy)
        );
wire [15:0]	bin_code = adc_data * 16'd129;
wire [19:0]	bcd_code;
bin_to_bcd bin_to_bcd(
               .rst_n          (rstn),
               .bin_code       (bin_code),
               .bcd_code       (bcd_code)
           );
//例化屏幕模块
OLED12864 OLED12864(
              .clk            (clk_12m),
              .rst_n          (rstn),
              .datain         (bcd_code),
              .freq_datain    (freq_save),
			  .multiple_mode  (multiple_mode),
			  .dds_mode		  (dds_mode),
              //.oled_csn       (oled_csn),
              .oled_rst       (oled_spi_RSTn),
              .oled_dcn       (oled_spi_DC),
              .oled_clk       (oled_spi_CLK),
              .oled_dat       (oled_spi_MOSI)
          );
//例化DDS信号发生器模块
dds_top dds_top(
            .clk(clk_120m),
            .rstn(rstn),
            .dds_mode(dds_mode),
			.freq  (freq_save),
            .adc_data(adc_data),
            .dac_data(dac_data)
        );

pwm pwm(
        .clk(clk_12m),
        .duty(dac_data),
        .pwm_out(PWM_Beep)
    );


endmodule //DDS_MAIN

1、pll IP core配置

将输入的12M晶振倍频到120M用来给dds提供时钟,产生更高频率的波形。

FvZ5vVK1eFs7ebWna_Q9RRHQ9-bT

2、按键

按键消抖及控制模块的波形如图所示

FsfbhY4d1QRBv3OBnTAFWJru6rw0

3、波形驱动模块

DDS信号发生器原理(可以直接参考DDS生成任意频率波形原理及示例代码)。

module dds_top (
           input  wire clk,
           input  wire rstn,
           input  wire [3:0] dds_mode,
		   input  wire [23:0] freq,

           input wire [7:0]  adc_data,
           output wire [7:0] dac_data
       );
reg [23:0] cnt;
always @(posedge clk or negedge rstn) begin
    if(rstn == 0) begin
        cnt<=0;
    end
    else begin
        cnt <= cnt + 1'b1;
    end
end

assign led= cnt[22];
wire [7:0] square_data;
wire [7:0] sawtooth_data;
wire [7:0] triangular_data;
wire [7:0] sinusoid_data;
reg  [7:0] dac_data_or;


reg [31:0] 	phase_acc;
always @(posedge clk) phase_acc <= phase_acc 
	+ (26'd358)		*freq[3 :0 ]
	+ (26'd3579)	*freq[7 :4 ]
	+ (26'd35791)	*freq[11:8 ]
	+ (26'd357915)	*freq[15:12]
	+ (26'd3579151)	*freq[19:16]
	+ (26'd35791519)*freq[23:20]
	;
	
//方波数据
assign square_data = {8{phase_acc[31]}};
//锯齿波数据
assign sawtooth_data = phase_acc[31:24];
//三角波数据
assign triangular_data = phase_acc[31] ? ~phase_acc[30:23] : phase_acc[30:23];
//正弦波数据
lookup_tables u_lookup_tables(.phase(phase_acc[31:24]), .sin_out(sinusoid_data));
//DDS输出
always @(posedge clk or negedge rstn) begin
    case (dds_mode[1:0])
        // 产生方波
        2'b00: begin
            dac_data_or <= square_data;
        end
        // 产生锯齿波
        2'b01: begin
            dac_data_or <= sawtooth_data;
        end
        // 产生三角波
        2'b10: begin
            dac_data_or <= triangular_data;
        end
        // 产生正弦波
        2'b11: begin
            dac_data_or <= sinusoid_data;
        end

    endcase
end

reg [13:0] amp_dat; //调幅后的波形数据
always @(posedge clk) amp_dat = dac_data_or * (adc_data[7-:6]);  //波形数据乘以调幅因数
assign dac_data = amp_dat[13-:8]; //取高8位输出

endmodule //dds_top


4、OLED模块

这里直接参考了示例代码OLED驱动说明及Verilog代码实例

5、上电复位模块

通过上电自动拉低rstn,实现上电后自动复位系统。

module    rst#(
              parameter CNT = 'd12_000_0
          )(

              input        wire clk,
              input        wire rst_in,

              output wire rst_n
          );
wire buf_rst_n;
reg                [26:0]         cnt = 27'd0;
assign    buf_rst_n = (cnt == CNT - 1'b1) ? 1'b1 : 1'b0;
assign    rst_n = buf_rst_n && rst_in;

always @ (posedge clk) begin
    if (cnt < CNT - 1'b1)
        cnt <= cnt + 1'b1;
    else
        cnt <= cnt;
end
endmodule

四、效果展示

1、10Hz 1V 四种波形

FhZi0fHBwFwwVVeYVGQuQTnsE9nPFq76bW0zE3yDkxKQFz2GAvFvIXXXFu1c_cqo2_UVmw7Ut80Z8irh1qIi

2、1kHz 1V 四种波形

FiKezp_KKh0bvXR-JfQA--hAGZUfFrzSqkE2on42juckCr8nePYIiD0HFoW14keIvNl-wHlNv9YX1RI46acTFjiM9vlR-j8h-QyjUw2ERogk9Z2H

3、1MHz 1V 四种波形

FiVBOzIoEROtOiuFad36POgMz6cWFitTfVmXk0WSPn-Cj-mjeOznFv1_FpkCIemBTgiJklN6JknZ0P3810rLFgXf26nBFUL_3qA0dRtpK2gkH4AA

4、1kHz 0.5V 四种波形

FlprlN0bOtmdC3H16jj2XLk4ug0TFiLDmrYzVlqQjuslivT25W1m2LefFvV60arSZhV0OUcHUy4ETuB_XLg4FgsZ07vmw3x7mhfoTGAKNH2dsare

4、1kHz 3V 四种波形(含输出正弦波时的频谱图)

FtdlaWQe0ALFbVnCzJnMnxrLrgHW

FkSY9NKMFu-9LgkXpHXV2mkOFcEY

FoPR03BZeyrGj9qp-ok_rc6Ie7VEFvAYDGKIX2xStjmYqdS0Tam8WzHAFtF1OvqMQK41d2mZ1ScVRbEmHDIC

五、总结

 

所使用的FPGA资源如图:

Fh8ttR_158b7O90yoZreaQtcJBXm

由于工作主要放在了DDS工作上,没有对oled模块进行优化,导致显示部分成为占用资源最多的部分(663+149)/1076。

硬件描述存在约束错误,但经过上板实测,可以正常使用。通过本次活动收获颇丰,学习了Verilog语言基础,并实现了一些基础的功能。感到了FPGA与单片机的区别。不过本次设计也有一些小遗憾,受限于家里的仪器条件,不能进一步精细调整,希望以后能够有时间做的更加完善。

附件下载
led_impl_1.rbt
可以直接上传的文件
dds.rar
项目工程
团队介绍
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号