差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
steptrainingboardddsacode [2020/03/23 18:28] gongyu 创建 |
steptrainingboardddsacode [2021/02/02 12:38] (当前版本) gongyusu |
||
---|---|---|---|
行 1: | 行 1: | ||
+ | ##用于小脚丫FPGA综合技能训练板的DDS代码 | ||
+ | |||
+ | ### DDS主程序 | ||
<code verilog> | <code verilog> | ||
module dds_main(clk_in,led,dac_data,pwm_out); | module dds_main(clk_in,led,dac_data,pwm_out); | ||
- | input clk_in; //12MHz | + | input clk_in; // 小脚丫FPGA的外部时钟频率位12MHz |
- | output led; | + | // 内部可以通过PLL产生12MHz整数倍的高速时钟 |
- | output [9:0] dac_data; | + | // 比如96MHz、108MHz、120MHz...216MHz |
- | output pwm_out; | + | output led; // 用以指示状态或帮助调试的LED |
+ | // 小脚丫模块上有8个单色LED和2个三色LED,可选择其一 | ||
+ | output [9:0] dac_data; // 10位数据输出送给外部的R-2R节点 | ||
+ | output pwm_out; // 用以产生PWM波形,进而可以产生直流或任意波形,取决于外接的低通滤波器的参数 | ||
- | reg [23:0] cnt; //??????? | + | reg [23:0] cnt; // 自由运行的计数器,共计24位,最低频率为cnt[23]的12MHz/2^24= 0.7Hz |
- | always@(posedge clk_in) cnt <= cnt +1'b1; | + | always@(posedge clk_in) cnt <= cnt + 1'b1; |
- | assign led= cnt[22]; //12MHz/2^21 ~ 6Hz | + | assign led= cnt[22]; //12MHz/2^23 ~ 1.5Hz, 接近心跳频率 |
- | wire clk_96m; | + | //通过同时改变所有的数据位从0-->1--0来产生方波 |
- | CLK_96M u5(.CLKI(clk_in), .CLKOP(clk_96m)); | + | //wire cnt_tap = cnt[2]; // 从计数器中取出其中的一位(这的bit7 = 第8位) |
+ | //assign dac_data = {10{cnt_tap}}; // 复制10次,给每一位赋同样的值,产生一个10-bits DAC值 | ||
+ | //assign dac_data = cnt[9:0]; //锯齿波, 频率 = Fclk/2^10 | ||
+ | //assign dac_data = cnt[10] ? ~cnt[9:0] : cnt[9:0]; // 三角波形,频率 = Fclk/2^11 | ||
- | //square wave generated by toggling all data bits from 0-->1--0 | + | reg [23:0] phase_acc; |
- | //wire cnt_tap = cnt[2]; // we take one bit out of the counter (here bit 7 = the 8th bit) | + | always @(posedge clk_in) phase_acc <= phase_acc + 24'd27962; //主时钟为12MHz,产生20KHz的正弦波信号 |
- | //assign dac_data = {10{cnt_tap}}; // and we duplicate it 10 times to create the 10-bits DAC value | + | lookup_tables u_lookup_tables(.phase(phase_acc[23:16]), .sine_data(dac_data)); |
- | //assign dac_data = cnt[9:0]; //Sawtooth waveform, frenquency = Fclk/2^10 | + | wire [9:0] PWM_in; |
+ | //assign PWM_in = 8'd38; // 产生直流电压 | ||
+ | assign PWM_in = dac_data[9:0]; // 变化的数据产生变化的PWM占空比,从而产生变化的输出波形 | ||
- | // Triangle waveform, frequency = Fclk/2^11 | + | reg [10:0] PWM_DDS_accumulator; |
- | //assign dac_data = cnt[10] ? ~cnt[9:0] : cnt[9:0]; // Triangle waveform, frenquency = Fclk/2^11 | + | |
- | wire [23:0] next_phase; | + | always @(posedge clk_in) PWM_DDS_accumulator <= PWM_DDS_accumulator[9:0] + PWM_in; |
- | wire [7:0] phase; | + | |
- | reg [23:0] accumulator; | + | |
- | assign next_phase = 24'H0DA7 + accumulator; | + | assign pwm_out = PWM_DDS_accumulator[10]; |
- | always @(posedge clk_96m) | + | // 可以通过内部PLL产生更高频率的时钟信号,比如120MHz,如下面的例子,只需要将上述代码中的clk_in都改为PLL产生的时钟,比如clk_120m就可以了 |
- | accumulator <= #1 next_phase; | + | //wire clk_120m; // 内部高倍时钟的名字 |
+ | //CLK_PLL u5(.CLKI(clk_in), .CLKOP(clk_120m)); // 以Lattice的IPCore为例产生高速内部时钟 | ||
+ | // 从12MHz产生120MHz,用以内部的逻辑以及DAC转换 | ||
- | assign phase = accumulator[23:16]; // phase is the high 8 bits | ||
- | wire [9:0] sine_data; | + | endmodule |
- | //lookup_tables u_lookup_tables(clk_96m, phase, sine_data); | + | </code> |
- | LUT_sine_table U_lut_sine_table(.Clock(~clk_96m), .ClkEn(1'b1), .Reset(1'b0), .Theta(phase), .Sine(sine_data)); | + | ### 波表部分的代码 |
- | assign dac_data = sine_data[9:0] + 10'h1ff ; | + | <code verilog> |
+ | /* lookup_tables.v */ | ||
- | wire [9:0] PWM_in; | + | module lookup_tables(phase, sin_out); |
- | //assign PWM_in = 8'd38; | + | input [7:0] phase; |
- | assign PWM_in = dac_data[9:0]; | + | output [9:0] sin_out; |
- | reg [10:0] PWM_DDS_accumulator; | + | wire [9:0] sin_out; |
- | always @(posedge clk_96m) PWM_DDS_accumulator <= PWM_DDS_accumulator[9:0] + PWM_in; | + | reg [5:0] address; |
+ | wire [1:0] sel; | ||
+ | wire [8:0] sine_table_out; | ||
- | assign pwm_out = PWM_DDS_accumulator[10]; | + | reg [9:0] sine_onecycle_amp; |
+ | |||
+ | //assign sin_out = {4'b0, sine_onecycle_amp[9:4]} + 9'hff; // 可以调节输出信号的幅度 | ||
+ | assign sin_out = sine_onecycle_amp[9:0]; | ||
+ | |||
+ | assign sel = phase[7:6]; | ||
+ | |||
+ | sin_table u_sin_table(address,sine_table_out); | ||
+ | |||
+ | always @(sel or sine_table_out) | ||
+ | begin | ||
+ | case(sel) | ||
+ | 2'b00: begin | ||
+ | sine_onecycle_amp = 9'h1ff + sine_table_out[8:0]; | ||
+ | address = phase[5:0]; | ||
+ | end | ||
+ | 2'b01: begin | ||
+ | sine_onecycle_amp = 9'h1ff + sine_table_out[8:0]; | ||
+ | address = ~phase[5:0]; | ||
+ | end | ||
+ | 2'b10: begin | ||
+ | sine_onecycle_amp = 9'h1ff - sine_table_out[8:0]; | ||
+ | address = phase[5:0]; | ||
+ | end | ||
+ | 2'b11: begin | ||
+ | sine_onecycle_amp = 9'h1ff - sine_table_out[8:0]; | ||
+ | address = ~ phase[5:0]; | ||
+ | end | ||
+ | endcase | ||
+ | end | ||
+ | |||
+ | endmodule | ||
+ | |||
+ | module sin_table(address,sin); | ||
+ | output [8:0] sin; | ||
+ | input [5:0] address; | ||
+ | reg [8:0] sin; | ||
+ | always @(address) | ||
+ | begin | ||
+ | case(address) | ||
+ | 6'h0: sin=9'h0; | ||
+ | 6'h1: sin=9'hC; | ||
+ | 6'h2: sin=9'h19; | ||
+ | 6'h3: sin=9'h25; | ||
+ | 6'h4: sin=9'h32; | ||
+ | 6'h5: sin=9'h3E; | ||
+ | 6'h6: sin=9'h4B; | ||
+ | 6'h7: sin=9'h57; | ||
+ | 6'h8: sin=9'h63; | ||
+ | 6'h9: sin=9'h70; | ||
+ | 6'ha: sin=9'h7C; | ||
+ | 6'hb: sin=9'h88; | ||
+ | 6'hc: sin=9'h94; | ||
+ | 6'hd: sin=9'hA0; | ||
+ | 6'he: sin=9'hAC; | ||
+ | 6'hf: sin=9'hB8; | ||
+ | 6'h10: sin=9'hC3; | ||
+ | 6'h11: sin=9'hCF; | ||
+ | 6'h12: sin=9'hDA; | ||
+ | 6'h13: sin=9'hE6; | ||
+ | 6'h14: sin=9'hF1; | ||
+ | 6'h15: sin=9'hFC; | ||
+ | 6'h16: sin=9'h107; | ||
+ | 6'h17: sin=9'h111; | ||
+ | 6'h18: sin=9'h11C; | ||
+ | 6'h19: sin=9'h126; | ||
+ | 6'h1a: sin=9'h130; | ||
+ | 6'h1b: sin=9'h13A; | ||
+ | 6'h1c: sin=9'h144; | ||
+ | 6'h1d: sin=9'h14E; | ||
+ | 6'h1e: sin=9'h157; | ||
+ | 6'h1f: sin=9'h161; | ||
+ | 6'h20: sin=9'h16A; | ||
+ | 6'h21: sin=9'h172; | ||
+ | 6'h22: sin=9'h17B; | ||
+ | 6'h23: sin=9'h183; | ||
+ | 6'h24: sin=9'h18B; | ||
+ | 6'h25: sin=9'h193; | ||
+ | 6'h26: sin=9'h19B; | ||
+ | 6'h27: sin=9'h1A2; | ||
+ | 6'h28: sin=9'h1A9; | ||
+ | 6'h29: sin=9'h1B0; | ||
+ | 6'h2a: sin=9'h1B7; | ||
+ | 6'h2b: sin=9'h1BD; | ||
+ | 6'h2c: sin=9'h1C3; | ||
+ | 6'h2d: sin=9'h1C9; | ||
+ | 6'h2e: sin=9'h1CE; | ||
+ | 6'h2f: sin=9'h1D4; | ||
+ | 6'h30: sin=9'h1D9; | ||
+ | 6'h31: sin=9'h1DD; | ||
+ | 6'h32: sin=9'h1E2; | ||
+ | 6'h33: sin=9'h1E6; | ||
+ | 6'h34: sin=9'h1E9; | ||
+ | 6'h35: sin=9'h1ED; | ||
+ | 6'h36: sin=9'h1F0; | ||
+ | 6'h37: sin=9'h1F3; | ||
+ | 6'h38: sin=9'h1F6; | ||
+ | 6'h39: sin=9'h1F8; | ||
+ | 6'h3a: sin=9'h1FA; | ||
+ | 6'h3b: sin=9'h1FC; | ||
+ | 6'h3c: sin=9'h1FD; | ||
+ | 6'h3d: sin=9'h1FE; | ||
+ | 6'h3e: sin=9'h1FF; | ||
+ | 6'h3f: sin=9'h1FF; | ||
+ | endcase | ||
+ | end | ||
endmodule | endmodule | ||
</code> | </code> | ||
+ | ### 10位地址、12位分辨率的正弦波表数据参考 | ||
+ | * [[sine_tables|10位地址、12位分辨率的正弦波表Verilog代码]] | ||
+ | * {{:sinetable.xlsx|10位地址、14位分辨率/10位地址、12位分辨率/10位地址、10位分辨率/8位地址、10位分辨率的正弦波表xls格式的文件}} |