## DDS+PWM产生任意波形 ### 工作原理 * DDS部分 * PWM部分 * 模拟链路部分 ### 模拟电路功能介绍 {{ :fpga_pwm_awg.png |}} 任意波形发生器模拟电路部分原理图 通过调节PWM的占空比(0.5V/3.3V ~ 3V/3.3V)得到等效幅度为0.5V - 3V之间的模拟信号,幅度变化的范围为2.5V,要得到幅度为5Vpp的模拟信号,则放大器的增益设定为G = 2: 也就是在电路原理图中放大器的增益为:R14/(R6+R7+R2) = 2 取R14 = 4.3KΩ,则R6+R7+R2 = 2.15KΩ PWM波形的中间值为(0.5V+3.0V)/2 = 1.75V,因此: - 在PWM的输出为1.75V的时候,运算放大器的输出应为0V - PWM的输出为0.5V的时候,运算放大器的输出为2.5V - PWM的输出为3V的时候,运算放大器的输出为-2.5V 由此直流偏移的要求可以得到R10 + R13 = 6.5KΩ 同时R6、C6,R7、C7以及R14、C11共同构成低通滤波器。 能够生成模拟信号的最高频率 取决于PWM的主时钟频率,我们目前用的FPGA的输入时钟为12MHz,使用内部PLL以后可以得到12MHz倍数的时钟频率,最高可以到400MHz,我们取比较安全的中间值192MHz(12MHz * 16)作为PWM的主时钟。 假设DDS波表为10位精度(一般DDS信号发生器的精度,作为简易的口袋仪器,对性能指标要求不高,8位也能够满足要求),则对应于一个模拟电压值的PWM周期为192MHz/1024 = 155KHz 如果通过10个点 {{ ::pwm_awg_analog_spred.png |}} 任意波形发生器模拟电路部分的仿真 - 频率响应(100Hz- 10MHz) {{ :pwm_awg_analog_wave.png |}} 任意波形发生器模拟电路部分的仿真 - 波形(100KHz正弦波) ### FPGA代码 #### DDS得到任意波形 相位累加器代码: wire [23:0] next_phase; wire [7:0] phase; reg [23:0] accumulator; assign next_phase = 24'H002222 + accumulator; // set frequency = 24'H002222 / 2^24 * clock, if PLL not used, clock = 12MHz, output frequency = 6.25KHz always @(posedge clk_hs) accumulator <= #1 next_phase; assign phase = accumulator[23:16]; // phase is the high 8 bits as address of the look up table wire [9:0] sine_data; // sine table is 8 bit wide, 10bit resolution. lookup_tables u_lookup_tables(phase, sine_data); 查找表代码: module lookup_tables(phase, sin_out); input [7:0] phase; //sine table is 8bits wide, 10 bits resolution output [9:0] sin_out; wire [9:0] sin_out; reg [5:0] address; wire [1:0] sel; wire [8:0] sine_table_out; reg [9:0] sine_onecycle_amp; //assign sin_out = {1'b0, sine_onecycle_amp[9:1]} + 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 or phase) 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 #### 调用DDS结果通过PWM生成需要的波形 //Generate AWG using 10bit resolution PWM + external RC LPF as DAC, up to 100KHz wire [9:0] PWM_WAV_in; assign PWM_WAV_in = sine_data[9:0]; reg [10:0] PWM_WAV_accumulator; always @(posedge clk_hs) PWM_WAV_accumulator <= PWM_WAV_accumulator[9:0] + PWM_WAV_in; assign pwm_awg = PWM_WAV_accumulator[10];