基于DDS的任意波形、信號(hào)發(fā)生器設(shè)計(jì)
實(shí)驗(yàn)任務(wù)
實(shí)驗(yàn)?zāi)康?/h4>前面章節(jié)我們學(xué)習(xí)了旋轉(zhuǎn)編碼器的工作原理及驅(qū)動(dòng)方法,本實(shí)驗(yàn)主要學(xué)習(xí)DDS技術(shù)的原理及實(shí)現(xiàn),IP核rom模塊的例化使用,串行DAC芯片DAC081S101的驅(qū)動(dòng)設(shè)計(jì)。
本文引用地址:http://butianyuan.cn/article/202312/453884.htm設(shè)計(jì)框圖
根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)總體可以拆分成如下功能模塊實(shí)現(xiàn),
實(shí)驗(yàn)原理
DAC及DDS介紹
上一節(jié)我們學(xué)習(xí)了ADC的相關(guān)知識(shí),DAC與ADC功能相反,DAC是數(shù)字模擬轉(zhuǎn)換器(英語(yǔ):Digital to analog converter,英文縮寫(xiě):DAC)是一種將數(shù)字信號(hào)轉(zhuǎn)換為模擬信號(hào)(以電流、電壓或電荷的形式)的設(shè)備。在很多數(shù)字系統(tǒng)中(例如計(jì)算機(jī)),信號(hào)以數(shù)字方式存儲(chǔ)和傳輸,而數(shù)字模擬轉(zhuǎn)換器可以將這樣的信號(hào)轉(zhuǎn)換為模擬信號(hào),從而使得它們能夠被外界(人或其他非數(shù)字系統(tǒng))識(shí)別。
上圖兩個(gè)都是8位DAC模型,轉(zhuǎn)換精度為 2的8次方等于256,即將Vref分成256份,DAC轉(zhuǎn)換輸出模擬電壓最小步進(jìn)為Vref / 256,模擬電壓 Vout = N * Vref / 256 。
DDS是直接數(shù)字式頻率合成器(Direct Digital Synthesizer)的英文縮寫(xiě)。與傳統(tǒng)的頻率合成器相比,DDS具有低成本、低功耗、高分辨率和快速轉(zhuǎn)換時(shí)間等優(yōu)點(diǎn),廣泛使用在電信與電子儀器領(lǐng)域,是實(shí)現(xiàn)設(shè)備全數(shù)字化的一個(gè)關(guān)鍵技術(shù)。DDS是一種全數(shù)字化的頻率合成器,由相位累加器、波形ROM、D/A轉(zhuǎn)換器和低通濾波器構(gòu)成。時(shí)鐘頻率給定后,輸出信號(hào)的頻率取決于頻率控制字,頻率分辨率取決于累加器位數(shù),相位分辨率取決于ROM的地址線位數(shù),幅度量化噪聲取決于ROM的數(shù)據(jù)位字長(zhǎng)和D/A轉(zhuǎn)換器位數(shù)。
DAC模塊電路連接
這里我們以STEP BaseBoard V3.0底板上的DAC模塊電路,其電路圖如下:
如DAC模塊電路所示,FPGA直接連接DAC081S101芯片的控制端,ADC有6個(gè)管腳,2腳VCC為VCC和Vref功能復(fù)用,即VCC = Vref。DAC后端是運(yùn)放電路LMV721,運(yùn)放模塊為電壓跟隨電路,再往后端射頻端子輸出。
DAC模塊驅(qū)動(dòng)設(shè)計(jì)
前面我們了解DAC081S101芯片和FPGA之間連接有三根線(sync、clk、din),兼容三線SPI總線,關(guān)于SPI串行總線上節(jié)已詳細(xì)介紹,這里我們直接查看DAC081S101的芯片手冊(cè)。
DAC081S101管腳說(shuō)明表:
注:Din信號(hào)在SCLK的節(jié)拍下傳輸數(shù)據(jù),當(dāng)SCLK下降沿時(shí)Din數(shù)據(jù)被鎖存到移位寄存器,所以FPGA控制在上升沿更新Din數(shù)據(jù)。
DAC081S101串行通信時(shí)序如下圖:
注:SCLK空閑時(shí)為低電平,CPOL = 0,上升沿(第二個(gè)邊沿)采樣,CPHA = 1,如果例化通用SPI核完成設(shè)計(jì),需要采用SPI的第二種工作模式。
注: 16個(gè)時(shí)鐘完成一次DAC轉(zhuǎn)換,傳輸?shù)?6位數(shù)據(jù),最高2位為無(wú)效數(shù)據(jù),次2位為模式口控制數(shù)據(jù),再次8位為DAC有效數(shù)據(jù)(DB7~DB0),最低4位為無(wú)效數(shù)據(jù)。
針對(duì)DAC081S101時(shí)序,我們用Verilog設(shè)計(jì)一個(gè)計(jì)數(shù)器,當(dāng)計(jì)數(shù)器值不同時(shí)完成不同操作,實(shí)現(xiàn)一次DAC轉(zhuǎn)換,程序?qū)崿F(xiàn)如下:
reg [7:0] cnt;always @(posedge clk or negedge rst_n)
if(!rst_n) cnt <= 1'b0;
else if(cnt >= 8'd34) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
reg [7:0] data;
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
dac_sync <= HIGH; dac_clk <= LOW; dac_dat <= LOW;
end else case(cnt)
8'd0 : begin dac_sync <= HIGH;
dac_clk <= LOW;
data <= dac_data; end
8'd1,8'd3,8'd5,8'd7,8'd9,8'd11,8'd13,8'd15,
8'd17,8'd19,8'd21,8'd23,8'd25,8'd27,8'd29,8'd31,
8'd33: begin dac_sync <= LOW;
dac_clk <= LOW;
end
8'd2 : begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= LOW;
end //15
8'd4 : begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= LOW;
end //14
8'd6 : begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= LOW;
end //13
8'd8 : begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= LOW;
end //12
8'd10: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[7];
end //11
8'd12: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[6];
end //10
8'd14: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[5];
end //9
8'd16: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[4];
end //8
8'd18: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[3];
end //7
8'd20: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[2];
end //6
8'd22: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[1];
end //5
8'd24: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= data[0];
end //4
8'd26: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_dat <= LOW;
end //3
8'd28: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_done <= HIGH;
end //2
8'd30: begin dac_sync <= LOW;
dac_clk <= HIGH;
dac_done <= LOW;
end //1
8'd32: begin dac_sync <= LOW;
dac_clk <= HIGH;
end //0
8'd34: begin dac_sync <= HIGH;
dac_clk <= LOW;
end
default : begin dac_sync <= HIGH;
dac_clk <= LOW;
end
endcase
到這我們就完成了串行DAC芯片DAC081S101的驅(qū)動(dòng)設(shè)計(jì),整個(gè)采樣周期用了35個(gè)系統(tǒng)時(shí)鐘,如果我們采用12MHz時(shí)鐘作為該模塊系統(tǒng)時(shí)鐘,轉(zhuǎn)換率Fs = 12M / 35 = 342.86 Ksps,DAC主頻Fsclk = 12 MHz / 2 = 6MHz,DAC081S101芯片手冊(cè)Fsclk最高頻率為30MHz,所以想要更高的轉(zhuǎn)換率,可以將系統(tǒng)時(shí)鐘的頻率從12 MHz倍頻到60 MHz。
模塊接口如下:clk和rstn為系統(tǒng)時(shí)鐘及復(fù)位,dacsync,dacclk和dacdat為DAC控制管腳,dacdata為DAC轉(zhuǎn)換數(shù)據(jù),dacdone脈沖對(duì)應(yīng)一次DAC轉(zhuǎn)換的完成
module DAC081S101_driver
(
input clk, //系統(tǒng)時(shí)鐘
input rst_n, //系統(tǒng)復(fù)位,低有效
output reg dac_done, //DAC采樣完成標(biāo)志
input [7:0] dac_data, //DAC采樣數(shù)據(jù)
output reg dac_sync, //SPI總線CS
output reg dac_clk, //SPI總線SCLK
output reg dac_dat //SPI總線MOSI
);
DDS設(shè)計(jì)實(shí)現(xiàn)
如上圖所示,以8位DAC為例,將一個(gè)周期的正弦波分割成256份,得到256個(gè)相位波形量化數(shù)據(jù),設(shè)計(jì)一個(gè)存儲(chǔ)器,寬度為8,深度為256,將256個(gè)相位波形量化數(shù)據(jù)放入存儲(chǔ)器中,我們就得到了一個(gè)正弦波波表。我們可以通過(guò)例化rom的IP核實(shí)現(xiàn)波表的設(shè)計(jì),具體的操作如下:
第一步我們需要有波表數(shù)據(jù)初始化文件(.mif文件),方便再例化rom核時(shí)配置需要的初始化數(shù)據(jù),得到波表數(shù)據(jù)初始化文件的方法很多,簡(jiǎn)單介紹兩種:
1.在Quartus軟件中,選擇File → New → Memory Files → Memory Initialization File,配置存儲(chǔ)深度和位寬,然后將Matlab或Excel等計(jì)算的波表數(shù)據(jù)填入,如下:
2.安裝正弦波數(shù)據(jù)生成器(網(wǎng)上搜索下載)工具軟件,配置相應(yīng)的參數(shù),直接導(dǎo)出生成初始化.mif文件。
第二步例化rom核,打開(kāi)Tools菜單下的IP Catalog工具,依次找到Libraty → Basic Functions → On Chip Memory → ROM:1-PORT,配置存儲(chǔ)器寬度和深度,選擇剛剛生成的初始化文件,其他選項(xiàng)默認(rèn)即可,點(diǎn)擊Finish完成rom的IP核例化。
第三步更改配置模式,因?yàn)槔藃om的IP核,需要初始化數(shù)據(jù),所以需要更改配置模式。打開(kāi)Assignments菜單下的Device選項(xiàng),點(diǎn)擊Device and Pin Opetions,找到Configuration → Configuration mode,下拉列表中選擇最后一項(xiàng),點(diǎn)擊OK保存。
打開(kāi)rom核中的Verilog文件,端口聲明如下:
input [7:0] address;
input clock;
output [7:0] q;
其中clock為存儲(chǔ)器時(shí)鐘,address為存儲(chǔ)器地址,q對(duì)應(yīng)address地址中的數(shù)據(jù)輸出,到這里我們的正弦波表就創(chuàng)建好了。
如果我們有上圖電路的硬件,當(dāng)FPGA按照時(shí)鐘的節(jié)拍產(chǎn)生波形數(shù)據(jù),就可以得到對(duì)應(yīng)的模擬輸出了,我們來(lái)看一個(gè)簡(jiǎn)單的DDS產(chǎn)生鋸齒波例子:
module SimpleDDS(clk, dac_dat);
input clk;
output [7:0] dac_dat;//24位相位累加器
reg [23:0] phase_acc;
always @(posedge clk) phase_acc <= phase_acc + 24'b1;//相位地址
wire [23:0] phase = phase_acc;
assign dac_dat = phase[23:16]; //鋸齒波
endmodule
程序中可以看到DDS模塊在每個(gè)clk周期都會(huì)產(chǎn)生一個(gè)8位數(shù)據(jù),并行DAC每個(gè)clk進(jìn)行一次DAC轉(zhuǎn)換,主頻等于轉(zhuǎn)換率,程序是成立的。對(duì)串行DAC(以DAC081S101為例),需要16個(gè)clk才能將DDS模塊1次產(chǎn)生的8位數(shù)據(jù)轉(zhuǎn)換,所以邏輯上,DDS模塊中的clk端口信號(hào)應(yīng)該跟DAC驅(qū)動(dòng)模塊的轉(zhuǎn)換率同步,而不是和系統(tǒng)時(shí)鐘或主頻同步。
波形選擇
上面程序中累加器phase_acc隨時(shí)鐘clk自加1,傳輸給并行DAC的數(shù)據(jù)同樣自加,最后得到鋸齒波輸出,當(dāng)clk為100MHz時(shí),鋸齒波頻率為100MHz / 2^24 = 5.96Hz。
鋸齒波輸出:
想要輸出三角波,只需要把DAC數(shù)據(jù)輸出賦值的語(yǔ)句改為:
assign dac_dat = phase[23]? ~phase[22:15]:phase[22:15]; //三角波
三角波輸出:
想要輸出方波,只需要把DAC數(shù)據(jù)輸出賦值的語(yǔ)句改為:
assign dac_dat = phase[23]? 8'hff : 8'h00; //方波
方波輸出:
想要輸出正弦波,只需要把DAC數(shù)據(jù)輸出賦值的語(yǔ)句改為波表存儲(chǔ)器的例化:
rom u1
(
.clock (clk ),
.address (phase[23:16] ),
.q (sin_dat )
);
我們知道了各種波形的產(chǎn)生方法,我們可以同時(shí)產(chǎn)生多種波形信號(hào),然后根據(jù)波形選擇端口變量wave的值選擇輸出的波形數(shù)據(jù),程序?qū)崿F(xiàn)如下:
wire [7:0] sin_dat; //正弦波
wire [7:0] saw_dat = phase[23:16]; //鋸齒波
wire [7:0] tri_dat = phase[23]? (~phase[22:15]) : phase[22:15]; //三角波
wire [7:0] squ_dat = phase[23]? 8'hff : 8'h00; //方波
always @(*) begin
case(wave)
2'b00: dac_dat = sin_dat; //正弦波
2'b01: dac_dat = saw_dat; //鋸齒波
2'b10: dac_dat = tri_dat; //三角波
2'b11: dac_dat = squ_dat; //方波
default: dac_dat = sin_dat; //正弦波
endcaseend
rom u1(.clock (clk ),
.address (phase[23:16] ),
.q (sin_dat )
);
頻率調(diào)節(jié)
上面簡(jiǎn)單的DDS設(shè)計(jì)中, 將相位累加器的控制改為:
always @(posedge clk) phase_acc <= phase_acc + 24'd2;
這樣原來(lái)需要2^24個(gè)clk周期完成的相位增量,現(xiàn)在只需要2^23個(gè)clk周期,同樣的相位增量花費(fèi)時(shí)間減少一半,即模擬輸出信號(hào)頻率是原來(lái)的2倍,改變被加數(shù)就會(huì)改變頻率,如果我們定義一個(gè)端口變量finc作為被加數(shù),使用邏輯調(diào)節(jié)finc的值就可以調(diào)節(jié)頻率,f_inc被稱為頻率控制字
always @(posedge clk) phase_acc <= phase_acc + f_inc;
相位調(diào)節(jié)
上面簡(jiǎn)單的DDS設(shè)計(jì)中, 將相位地址的控制改為:
wire [23:0] phase = phase_acc + 24'b1;
相位累加器每次加一個(gè)固定的偏移得到全新的相位地址,使波形數(shù)據(jù)整體上產(chǎn)生相位偏移,不改變輸出的頻率,如果我們定義一個(gè)端口變量pinc作為被加數(shù),使用邏輯調(diào)節(jié)pinc的值就可以調(diào)節(jié)相位,pinc被稱為相位控制字 <code verilog> wire [23:0] phase = phaseacc + p_inc; </code>
系統(tǒng)總體實(shí)現(xiàn)
底板上旋轉(zhuǎn)編碼器帶有按鍵功能,我們使用按鍵消抖模塊完成按鍵信號(hào)的消抖處理,前面章節(jié)我們還學(xué)習(xí)了旋轉(zhuǎn)編碼器旋轉(zhuǎn)功能的驅(qū)動(dòng),剛剛講到控制波形信號(hào)發(fā)生器的波形選擇和頻率輸出其實(shí)就是控制兩個(gè)端口參數(shù)wave和f_inc,所以從旋轉(zhuǎn)編碼器的驅(qū)動(dòng)輸出到DDS端口參數(shù)的控制,我們還需要一個(gè)邏輯模塊。
按動(dòng)旋轉(zhuǎn)編碼器的按鍵切換信號(hào)發(fā)生器的波形輸出,依次為正弦波、鋸齒波、三角波、方波,波形選擇功能程序?qū)崿F(xiàn)如下:
localparam SIN = 2'b00, SAW = 2'b01, TRI = 2'b10, SQU = 2'b11;//波形輸出選擇
always @(posedge clk or negedge rst_n) begin
if(!rst_n) wave <= SIN;
else if(O_pulse)begin
case(wave)
SIN: wave <= SAW;
SAW: wave <= TRI;
TRI: wave <= SQU;
SQU: wave <= SIN;
default: wave <= SIN;
endcase
end else wave <= wave;
end
轉(zhuǎn)動(dòng)旋轉(zhuǎn)編碼器調(diào)節(jié)信號(hào)發(fā)生器的輸出頻率,左旋(逆時(shí)針)頻率減小,左旋(逆時(shí)針)頻率增加,頻率控制功能程序?qū)崿F(xiàn)如下:
//頻率控制
always@(posedge clk or negedge rst_n) begin
if(!rst_n) f_inc <= 24'ha0000;
else if(L_pulse) begin
if(f_inc <= 24'h10000) f_inc <= f_inc;
else f_inc <= f_inc - 24'h10000;
end else if(R_pulse) begin
if(f_inc >= 24'h140000) f_inc <= f_inc;
else f_inc <= f_inc + 24'h10000;
end else f_inc <= f_inc;
end
上電默認(rèn)情況下,頻率控制字f_inc的值為24’ha0000,那么在模擬信號(hào)周期內(nèi)采樣點(diǎn)n = 2^24 / 10 / 2^16 = 25.6。我們?cè)O(shè)計(jì)的DAC驅(qū)動(dòng)轉(zhuǎn)換率為342.86 Ksps,那么對(duì)應(yīng)模擬信號(hào)頻率 f = 342.86K / 25.6 = 13393Hz = 13.4KHz左右。
旋轉(zhuǎn)編碼器調(diào)節(jié)頻率控制字的步進(jìn)及頻率控制字最小值都為24’h10000,對(duì)應(yīng)頻率步進(jìn)值及輸出模擬信號(hào)最小頻率都等于1.34KHz(運(yùn)算方法同上)。
將設(shè)計(jì)中所有模塊例化連線,完成整體設(shè)計(jì),再次強(qiáng)調(diào):DDS模塊的時(shí)鐘信號(hào)與DAC模塊中的轉(zhuǎn)換率信號(hào)同步,所以DDS模塊中的clk要和DAC081S101driver模塊中的dacdone信號(hào)連接。
綜合后的設(shè)計(jì)框圖如下:
實(shí)驗(yàn)步驟
實(shí)驗(yàn)現(xiàn)象
將設(shè)計(jì)加載到FPGA中,使用示波器觀察底板DAC射頻端子信號(hào)輸出,按動(dòng)旋轉(zhuǎn)編碼器觀察不同的波形輸出,轉(zhuǎn)動(dòng)旋轉(zhuǎn)編碼器觀察頻率的變化。
前面章節(jié)我們學(xué)習(xí)了旋轉(zhuǎn)編碼器的工作原理及驅(qū)動(dòng)方法,本實(shí)驗(yàn)主要學(xué)習(xí)DDS技術(shù)的原理及實(shí)現(xiàn),IP核rom模塊的例化使用,串行DAC芯片DAC081S101的驅(qū)動(dòng)設(shè)計(jì)。
本文引用地址:http://butianyuan.cn/article/202312/453884.htm根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)總體可以拆分成如下功能模塊實(shí)現(xiàn),
上一節(jié)我們學(xué)習(xí)了ADC的相關(guān)知識(shí),DAC與ADC功能相反,DAC是數(shù)字模擬轉(zhuǎn)換器(英語(yǔ):Digital to analog converter,英文縮寫(xiě):DAC)是一種將數(shù)字信號(hào)轉(zhuǎn)換為模擬信號(hào)(以電流、電壓或電荷的形式)的設(shè)備。在很多數(shù)字系統(tǒng)中(例如計(jì)算機(jī)),信號(hào)以數(shù)字方式存儲(chǔ)和傳輸,而數(shù)字模擬轉(zhuǎn)換器可以將這樣的信號(hào)轉(zhuǎn)換為模擬信號(hào),從而使得它們能夠被外界(人或其他非數(shù)字系統(tǒng))識(shí)別。
上圖兩個(gè)都是8位DAC模型,轉(zhuǎn)換精度為 2的8次方等于256,即將Vref分成256份,DAC轉(zhuǎn)換輸出模擬電壓最小步進(jìn)為Vref / 256,模擬電壓 Vout = N * Vref / 256 。
DDS是直接數(shù)字式頻率合成器(Direct Digital Synthesizer)的英文縮寫(xiě)。與傳統(tǒng)的頻率合成器相比,DDS具有低成本、低功耗、高分辨率和快速轉(zhuǎn)換時(shí)間等優(yōu)點(diǎn),廣泛使用在電信與電子儀器領(lǐng)域,是實(shí)現(xiàn)設(shè)備全數(shù)字化的一個(gè)關(guān)鍵技術(shù)。DDS是一種全數(shù)字化的頻率合成器,由相位累加器、波形ROM、D/A轉(zhuǎn)換器和低通濾波器構(gòu)成。時(shí)鐘頻率給定后,輸出信號(hào)的頻率取決于頻率控制字,頻率分辨率取決于累加器位數(shù),相位分辨率取決于ROM的地址線位數(shù),幅度量化噪聲取決于ROM的數(shù)據(jù)位字長(zhǎng)和D/A轉(zhuǎn)換器位數(shù)。
這里我們以STEP BaseBoard V3.0底板上的DAC模塊電路,其電路圖如下:
如DAC模塊電路所示,FPGA直接連接DAC081S101芯片的控制端,ADC有6個(gè)管腳,2腳VCC為VCC和Vref功能復(fù)用,即VCC = Vref。DAC后端是運(yùn)放電路LMV721,運(yùn)放模塊為電壓跟隨電路,再往后端射頻端子輸出。
前面我們了解DAC081S101芯片和FPGA之間連接有三根線(sync、clk、din),兼容三線SPI總線,關(guān)于SPI串行總線上節(jié)已詳細(xì)介紹,這里我們直接查看DAC081S101的芯片手冊(cè)。
DAC081S101管腳說(shuō)明表:
注:Din信號(hào)在SCLK的節(jié)拍下傳輸數(shù)據(jù),當(dāng)SCLK下降沿時(shí)Din數(shù)據(jù)被鎖存到移位寄存器,所以FPGA控制在上升沿更新Din數(shù)據(jù)。
DAC081S101串行通信時(shí)序如下圖:
注:SCLK空閑時(shí)為低電平,CPOL = 0,上升沿(第二個(gè)邊沿)采樣,CPHA = 1,如果例化通用SPI核完成設(shè)計(jì),需要采用SPI的第二種工作模式。
注: 16個(gè)時(shí)鐘完成一次DAC轉(zhuǎn)換,傳輸?shù)?6位數(shù)據(jù),最高2位為無(wú)效數(shù)據(jù),次2位為模式口控制數(shù)據(jù),再次8位為DAC有效數(shù)據(jù)(DB7~DB0),最低4位為無(wú)效數(shù)據(jù)。
針對(duì)DAC081S101時(shí)序,我們用Verilog設(shè)計(jì)一個(gè)計(jì)數(shù)器,當(dāng)計(jì)數(shù)器值不同時(shí)完成不同操作,實(shí)現(xiàn)一次DAC轉(zhuǎn)換,程序?qū)崿F(xiàn)如下:
reg [7:0] cnt;always @(posedge clk or negedge rst_n) if(!rst_n) cnt <= 1'b0; else if(cnt >= 8'd34) cnt <= 1'b0; else cnt <= cnt + 1'b1; reg [7:0] data; always @(posedge clk or negedge rst_n) if(!rst_n) begin dac_sync <= HIGH; dac_clk <= LOW; dac_dat <= LOW; end else case(cnt) 8'd0 : begin dac_sync <= HIGH; dac_clk <= LOW; data <= dac_data; end 8'd1,8'd3,8'd5,8'd7,8'd9,8'd11,8'd13,8'd15, 8'd17,8'd19,8'd21,8'd23,8'd25,8'd27,8'd29,8'd31, 8'd33: begin dac_sync <= LOW; dac_clk <= LOW; end 8'd2 : begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= LOW; end //15 8'd4 : begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= LOW; end //14 8'd6 : begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= LOW; end //13 8'd8 : begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= LOW; end //12 8'd10: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[7]; end //11 8'd12: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[6]; end //10 8'd14: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[5]; end //9 8'd16: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[4]; end //8 8'd18: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[3]; end //7 8'd20: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[2]; end //6 8'd22: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[1]; end //5 8'd24: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= data[0]; end //4 8'd26: begin dac_sync <= LOW; dac_clk <= HIGH; dac_dat <= LOW; end //3 8'd28: begin dac_sync <= LOW; dac_clk <= HIGH; dac_done <= HIGH; end //2 8'd30: begin dac_sync <= LOW; dac_clk <= HIGH; dac_done <= LOW; end //1 8'd32: begin dac_sync <= LOW; dac_clk <= HIGH; end //0 8'd34: begin dac_sync <= HIGH; dac_clk <= LOW; end default : begin dac_sync <= HIGH; dac_clk <= LOW; end endcase
到這我們就完成了串行DAC芯片DAC081S101的驅(qū)動(dòng)設(shè)計(jì),整個(gè)采樣周期用了35個(gè)系統(tǒng)時(shí)鐘,如果我們采用12MHz時(shí)鐘作為該模塊系統(tǒng)時(shí)鐘,轉(zhuǎn)換率Fs = 12M / 35 = 342.86 Ksps,DAC主頻Fsclk = 12 MHz / 2 = 6MHz,DAC081S101芯片手冊(cè)Fsclk最高頻率為30MHz,所以想要更高的轉(zhuǎn)換率,可以將系統(tǒng)時(shí)鐘的頻率從12 MHz倍頻到60 MHz。
模塊接口如下:clk和rstn為系統(tǒng)時(shí)鐘及復(fù)位,dacsync,dacclk和dacdat為DAC控制管腳,dacdata為DAC轉(zhuǎn)換數(shù)據(jù),dacdone脈沖對(duì)應(yīng)一次DAC轉(zhuǎn)換的完成
module DAC081S101_driver ( input clk, //系統(tǒng)時(shí)鐘 input rst_n, //系統(tǒng)復(fù)位,低有效 output reg dac_done, //DAC采樣完成標(biāo)志 input [7:0] dac_data, //DAC采樣數(shù)據(jù) output reg dac_sync, //SPI總線CS output reg dac_clk, //SPI總線SCLK output reg dac_dat //SPI總線MOSI );
如上圖所示,以8位DAC為例,將一個(gè)周期的正弦波分割成256份,得到256個(gè)相位波形量化數(shù)據(jù),設(shè)計(jì)一個(gè)存儲(chǔ)器,寬度為8,深度為256,將256個(gè)相位波形量化數(shù)據(jù)放入存儲(chǔ)器中,我們就得到了一個(gè)正弦波波表。我們可以通過(guò)例化rom的IP核實(shí)現(xiàn)波表的設(shè)計(jì),具體的操作如下:
第一步我們需要有波表數(shù)據(jù)初始化文件(.mif文件),方便再例化rom核時(shí)配置需要的初始化數(shù)據(jù),得到波表數(shù)據(jù)初始化文件的方法很多,簡(jiǎn)單介紹兩種:
1.在Quartus軟件中,選擇File → New → Memory Files → Memory Initialization File,配置存儲(chǔ)深度和位寬,然后將Matlab或Excel等計(jì)算的波表數(shù)據(jù)填入,如下:
2.安裝正弦波數(shù)據(jù)生成器(網(wǎng)上搜索下載)工具軟件,配置相應(yīng)的參數(shù),直接導(dǎo)出生成初始化.mif文件。
第二步例化rom核,打開(kāi)Tools菜單下的IP Catalog工具,依次找到Libraty → Basic Functions → On Chip Memory → ROM:1-PORT,配置存儲(chǔ)器寬度和深度,選擇剛剛生成的初始化文件,其他選項(xiàng)默認(rèn)即可,點(diǎn)擊Finish完成rom的IP核例化。
第三步更改配置模式,因?yàn)槔藃om的IP核,需要初始化數(shù)據(jù),所以需要更改配置模式。打開(kāi)Assignments菜單下的Device選項(xiàng),點(diǎn)擊Device and Pin Opetions,找到Configuration → Configuration mode,下拉列表中選擇最后一項(xiàng),點(diǎn)擊OK保存。
打開(kāi)rom核中的Verilog文件,端口聲明如下:
input [7:0] address; input clock; output [7:0] q;
其中clock為存儲(chǔ)器時(shí)鐘,address為存儲(chǔ)器地址,q對(duì)應(yīng)address地址中的數(shù)據(jù)輸出,到這里我們的正弦波表就創(chuàng)建好了。
如果我們有上圖電路的硬件,當(dāng)FPGA按照時(shí)鐘的節(jié)拍產(chǎn)生波形數(shù)據(jù),就可以得到對(duì)應(yīng)的模擬輸出了,我們來(lái)看一個(gè)簡(jiǎn)單的DDS產(chǎn)生鋸齒波例子:
module SimpleDDS(clk, dac_dat); input clk; output [7:0] dac_dat;//24位相位累加器 reg [23:0] phase_acc; always @(posedge clk) phase_acc <= phase_acc + 24'b1;//相位地址 wire [23:0] phase = phase_acc; assign dac_dat = phase[23:16]; //鋸齒波 endmodule
程序中可以看到DDS模塊在每個(gè)clk周期都會(huì)產(chǎn)生一個(gè)8位數(shù)據(jù),并行DAC每個(gè)clk進(jìn)行一次DAC轉(zhuǎn)換,主頻等于轉(zhuǎn)換率,程序是成立的。對(duì)串行DAC(以DAC081S101為例),需要16個(gè)clk才能將DDS模塊1次產(chǎn)生的8位數(shù)據(jù)轉(zhuǎn)換,所以邏輯上,DDS模塊中的clk端口信號(hào)應(yīng)該跟DAC驅(qū)動(dòng)模塊的轉(zhuǎn)換率同步,而不是和系統(tǒng)時(shí)鐘或主頻同步。
波形選擇
上面程序中累加器phase_acc隨時(shí)鐘clk自加1,傳輸給并行DAC的數(shù)據(jù)同樣自加,最后得到鋸齒波輸出,當(dāng)clk為100MHz時(shí),鋸齒波頻率為100MHz / 2^24 = 5.96Hz。
鋸齒波輸出:
想要輸出三角波,只需要把DAC數(shù)據(jù)輸出賦值的語(yǔ)句改為:
assign dac_dat = phase[23]? ~phase[22:15]:phase[22:15]; //三角波
三角波輸出:
想要輸出方波,只需要把DAC數(shù)據(jù)輸出賦值的語(yǔ)句改為:
assign dac_dat = phase[23]? 8'hff : 8'h00; //方波
方波輸出:
想要輸出正弦波,只需要把DAC數(shù)據(jù)輸出賦值的語(yǔ)句改為波表存儲(chǔ)器的例化:
rom u1 ( .clock (clk ), .address (phase[23:16] ), .q (sin_dat ) );
我們知道了各種波形的產(chǎn)生方法,我們可以同時(shí)產(chǎn)生多種波形信號(hào),然后根據(jù)波形選擇端口變量wave的值選擇輸出的波形數(shù)據(jù),程序?qū)崿F(xiàn)如下:
wire [7:0] sin_dat; //正弦波 wire [7:0] saw_dat = phase[23:16]; //鋸齒波 wire [7:0] tri_dat = phase[23]? (~phase[22:15]) : phase[22:15]; //三角波 wire [7:0] squ_dat = phase[23]? 8'hff : 8'h00; //方波 always @(*) begin case(wave) 2'b00: dac_dat = sin_dat; //正弦波 2'b01: dac_dat = saw_dat; //鋸齒波 2'b10: dac_dat = tri_dat; //三角波 2'b11: dac_dat = squ_dat; //方波 default: dac_dat = sin_dat; //正弦波 endcaseend rom u1(.clock (clk ), .address (phase[23:16] ), .q (sin_dat ) );
頻率調(diào)節(jié)
上面簡(jiǎn)單的DDS設(shè)計(jì)中, 將相位累加器的控制改為:
always @(posedge clk) phase_acc <= phase_acc + 24'd2;
這樣原來(lái)需要2^24個(gè)clk周期完成的相位增量,現(xiàn)在只需要2^23個(gè)clk周期,同樣的相位增量花費(fèi)時(shí)間減少一半,即模擬輸出信號(hào)頻率是原來(lái)的2倍,改變被加數(shù)就會(huì)改變頻率,如果我們定義一個(gè)端口變量finc作為被加數(shù),使用邏輯調(diào)節(jié)finc的值就可以調(diào)節(jié)頻率,f_inc被稱為頻率控制字
always @(posedge clk) phase_acc <= phase_acc + f_inc;
相位調(diào)節(jié)
上面簡(jiǎn)單的DDS設(shè)計(jì)中, 將相位地址的控制改為:
wire [23:0] phase = phase_acc + 24'b1;
相位累加器每次加一個(gè)固定的偏移得到全新的相位地址,使波形數(shù)據(jù)整體上產(chǎn)生相位偏移,不改變輸出的頻率,如果我們定義一個(gè)端口變量pinc作為被加數(shù),使用邏輯調(diào)節(jié)pinc的值就可以調(diào)節(jié)相位,pinc被稱為相位控制字 <code verilog> wire [23:0] phase = phaseacc + p_inc; </code>
底板上旋轉(zhuǎn)編碼器帶有按鍵功能,我們使用按鍵消抖模塊完成按鍵信號(hào)的消抖處理,前面章節(jié)我們還學(xué)習(xí)了旋轉(zhuǎn)編碼器旋轉(zhuǎn)功能的驅(qū)動(dòng),剛剛講到控制波形信號(hào)發(fā)生器的波形選擇和頻率輸出其實(shí)就是控制兩個(gè)端口參數(shù)wave和f_inc,所以從旋轉(zhuǎn)編碼器的驅(qū)動(dòng)輸出到DDS端口參數(shù)的控制,我們還需要一個(gè)邏輯模塊。
按動(dòng)旋轉(zhuǎn)編碼器的按鍵切換信號(hào)發(fā)生器的波形輸出,依次為正弦波、鋸齒波、三角波、方波,波形選擇功能程序?qū)崿F(xiàn)如下:
localparam SIN = 2'b00, SAW = 2'b01, TRI = 2'b10, SQU = 2'b11;//波形輸出選擇 always @(posedge clk or negedge rst_n) begin if(!rst_n) wave <= SIN; else if(O_pulse)begin case(wave) SIN: wave <= SAW; SAW: wave <= TRI; TRI: wave <= SQU; SQU: wave <= SIN; default: wave <= SIN; endcase end else wave <= wave; end
轉(zhuǎn)動(dòng)旋轉(zhuǎn)編碼器調(diào)節(jié)信號(hào)發(fā)生器的輸出頻率,左旋(逆時(shí)針)頻率減小,左旋(逆時(shí)針)頻率增加,頻率控制功能程序?qū)崿F(xiàn)如下:
//頻率控制 always@(posedge clk or negedge rst_n) begin if(!rst_n) f_inc <= 24'ha0000; else if(L_pulse) begin if(f_inc <= 24'h10000) f_inc <= f_inc; else f_inc <= f_inc - 24'h10000; end else if(R_pulse) begin if(f_inc >= 24'h140000) f_inc <= f_inc; else f_inc <= f_inc + 24'h10000; end else f_inc <= f_inc; end
上電默認(rèn)情況下,頻率控制字f_inc的值為24’ha0000,那么在模擬信號(hào)周期內(nèi)采樣點(diǎn)n = 2^24 / 10 / 2^16 = 25.6。我們?cè)O(shè)計(jì)的DAC驅(qū)動(dòng)轉(zhuǎn)換率為342.86 Ksps,那么對(duì)應(yīng)模擬信號(hào)頻率 f = 342.86K / 25.6 = 13393Hz = 13.4KHz左右。
旋轉(zhuǎn)編碼器調(diào)節(jié)頻率控制字的步進(jìn)及頻率控制字最小值都為24’h10000,對(duì)應(yīng)頻率步進(jìn)值及輸出模擬信號(hào)最小頻率都等于1.34KHz(運(yùn)算方法同上)。
將設(shè)計(jì)中所有模塊例化連線,完成整體設(shè)計(jì),再次強(qiáng)調(diào):DDS模塊的時(shí)鐘信號(hào)與DAC模塊中的轉(zhuǎn)換率信號(hào)同步,所以DDS模塊中的clk要和DAC081S101driver模塊中的dacdone信號(hào)連接。
綜合后的設(shè)計(jì)框圖如下:
將設(shè)計(jì)加載到FPGA中,使用示波器觀察底板DAC射頻端子信號(hào)輸出,按動(dòng)旋轉(zhuǎn)編碼器觀察不同的波形輸出,轉(zhuǎn)動(dòng)旋轉(zhuǎn)編碼器觀察頻率的變化。
評(píng)論