零基礎(chǔ)學(xué)FPGA (二十六)頻、相可調(diào),任意波形信號(hào)發(fā)生器系統(tǒng)設(shè)計(jì)
最近接了一個(gè)項(xiàng)目吧,是我們學(xué)校物理院院長(zhǎng)帶的研究生搞的,小墨有幸跟他們合作,負(fù)責(zé)FPGA方面的工作,完成后據(jù)說(shuō)還會(huì)申請(qǐng)國(guó)家專利,具體到什么時(shí)候完成,那可能就是猴年馬月了,或者說(shuō)我已經(jīng)不在學(xué)校了。從今天開(kāi)始,小墨將開(kāi)始接觸賽靈思公司的FPGA(老師提供的平臺(tái)),用到的當(dāng)然是SOPC。其實(shí)做做項(xiàng)目也好,讓自己鍛煉一下,我也好久沒(méi)有做大一點(diǎn)的項(xiàng)目了,對(duì)我來(lái)說(shuō)也是一個(gè)機(jī)會(huì)吧。
本文引用地址:http://m.butianyuan.cn/article/284116.htm信號(hào)發(fā)生器這個(gè)東西相信大家都知道,關(guān)于基于DDS信號(hào)發(fā)生器的技術(shù)文檔網(wǎng)上也多的是,但是我還是想寫一下這部分的教學(xué),因?yàn)閺奈易陨淼膶W(xué)習(xí)來(lái)看,這部分內(nèi)容并不是很難,也很容易實(shí)現(xiàn),代碼也就那幾行。但是,我發(fā)現(xiàn)我當(dāng)時(shí)學(xué)這部分的時(shí)候,從網(wǎng)上找資料,大部分都是基于原理的講解,或者說(shuō)只是做到仿真這一步,而且原理的講解太過(guò)書面化,初學(xué)者不怎么好理解。我做了這么一個(gè)教程,全方面的做一個(gè)這樣一個(gè)系統(tǒng)。其中包括信號(hào)發(fā)生器的原理部分,代碼實(shí)現(xiàn),仿真,按鍵控制頻率、相位變換,包括正弦波、方波、鋸齒波、三角波的產(chǎn)生,以及D/A轉(zhuǎn)換芯片的操作,直到能夠在示波器上觀察到我們產(chǎn)生的波形,并通過(guò)按鍵控制為止。
這個(gè)系統(tǒng)的設(shè)計(jì)大概花了我三四天的樣子,寫的也是蠻用心的,工程不是很大,但還是有些細(xì)節(jié)需要注意的,下面我們就一步步的開(kāi)始做。
一、整體框架
關(guān)于原理部分,書上講的很多,但是總是感覺(jué)不盡人意,過(guò)于書面化的語(yǔ)言讓人看著很頭疼,下面就讓小墨來(lái)給大家解釋,希望給讀者帶來(lái)一種眼前一亮的感覺(jué),讓你再回去看書,看代碼的時(shí)候覺(jué)得得心應(yīng)手了。
首先我們應(yīng)該先明確要做什么,我們要做的是一個(gè)頻率,相位可調(diào),任意波形信號(hào)發(fā)生器,也就是我們常見(jiàn)的正弦波,方波,鋸齒波,三角波等。
其次,我們需要知道我們需要哪些參數(shù)。比如,我們要生成一個(gè)正弦波,它的初始頻率是多少,相位是多少,步進(jìn)頻率、相位是多少,怎么計(jì)算這些參數(shù)?
然后我們需要知道如何生成一種波形,怎么樣通過(guò)按鍵實(shí)現(xiàn)波形與波形之間的轉(zhuǎn)換,例如我按下一個(gè)鍵生成正弦波,再按下一個(gè)鍵生成三角波,怎么實(shí)現(xiàn)?
再然后,我們需要把生成的數(shù)字信號(hào)送入D/A轉(zhuǎn)換芯片,D/A轉(zhuǎn)換的接口怎么寫?怎么保證采集的數(shù)字信號(hào)完全正確?
最后,我們可以通過(guò)示波器觀察我們生成的波形信號(hào),驗(yàn)證我們的頻率,相位是否符合我們的設(shè)計(jì)要求
下面是我簡(jiǎn)單的做的一個(gè)框架圖
下面我們先來(lái)解釋一下上面這張框架圖。
首先,我們通過(guò)8位按鍵選擇輸出何種波形,這時(shí)候wave_select信號(hào)被賦予相應(yīng)的值送給DDS模塊,DDS模塊由wave_select信號(hào),從ROM中選擇合適的地址,地址每變化一次,也就是數(shù)據(jù)每變化一次,DDS模塊會(huì)告知DAC模塊數(shù)據(jù)發(fā)生變化了,讓它注意數(shù)據(jù)的采集,不要采錯(cuò)了!同時(shí)可以通過(guò)按鍵控制模塊調(diào)節(jié)輸出信號(hào)的頻率,相位等,DAC模塊將采集到的數(shù)字信號(hào)轉(zhuǎn)化成模擬信號(hào),送到示波器上顯示。注意DAC芯片的采樣頻率,DDS信號(hào)的輸出頻率不能大于采集頻率,否則數(shù)據(jù)就會(huì)出錯(cuò)。
二、DDS信號(hào)發(fā)生器原理詳解
關(guān)于發(fā)生器原理這樣部分有必要好好講講,很多人還是對(duì)某系問(wèn)題不得其解,先來(lái)看這張圖
DDS基本的結(jié)構(gòu)組成,看圖就知道了,包括相位累加器,相位調(diào)制器,波形數(shù)據(jù)表,和DA轉(zhuǎn)換。我們還可以看到有兩個(gè)輸入,即頻率控制字輸入fword 和相位控制字輸入 pword,這兩個(gè)輸入就是我們用來(lái)控制輸出波形頻率和相位的
1、相位累加器
相位累加器的原理,我們先假設(shè)頻率控制字fword 為1。相位累加器的原理就是先將fword的值送到相位累加器,然后每來(lái)一個(gè)時(shí)鐘,相位累加器的輸出值,就跟相位累加器的新輸入值相加,之后再送入相位累加器,再來(lái)一個(gè)時(shí)鐘,再跟輸入值相加送進(jìn)去,如此循環(huán)。例如剛開(kāi)始fword = 1 ,那么第一個(gè)時(shí)鐘周期相位累加器的輸出就是1,第二個(gè)時(shí)鐘周期輸出的就是2,第三個(gè)時(shí)鐘周期輸出的就是3。再例如,我們的頻率控制字fword 剛開(kāi)始等于2,那么相位累加器輸出的就依次是0,2,4.....也就是說(shuō)頻率控制字fword 越大,相位累加器的輸出值間隔也就越大,那么我們假設(shè)相位累加器的輸出是32位的,如果fword越大,那么頻率控制字記完到2^32 的時(shí)間就越短。這樣的話,我們來(lái)算一下
我們使用的是50M的晶振,周期為20ns,假設(shè)fword為1,相位累加器的輸出為N位的,那么每20ns,相位累加器加1,要加到2^N,需要20ns x 2^N 時(shí)間,這個(gè)時(shí)間就是輸出一個(gè)完整信號(hào)的周期,那么我們可以知道,輸出信號(hào)的頻率為 Fout = Fclk /2^N,其中,F(xiàn)clk為我們的晶振頻率,再假如,fword = B 的時(shí)候,相位間隔提高 B 倍,因此計(jì)滿一個(gè)周期的時(shí)間縮小了 B 倍,頻率提高的 B 倍。綜上所述,我們得出了輸出信號(hào)的頻率計(jì)算公式
有了這個(gè)公式,那么,如果我們把2^N看成是一個(gè)周期波形的相位,也就是說(shuō)把一個(gè)波形的相位平均分成2^N個(gè),每一個(gè)相位對(duì)應(yīng)一個(gè)數(shù)字信號(hào),將這些數(shù)字信號(hào)送到DA轉(zhuǎn)換芯片,轉(zhuǎn)化成模擬信號(hào),不就是我們的信號(hào)發(fā)生器了嗎?
好,這里我們假設(shè)N = 32 ,也就是把一個(gè)波形的相位分成了2^32個(gè)點(diǎn),但是位數(shù)越多當(dāng)然占用的資源也就越多,不能取那么多,怎么辦呢,我們只取它的高8位即可
即取fre_add[31:24] ,將這8位數(shù)送給ROM的地址。很多人不明白了,為什么這樣取8位,這樣取8位不是把一個(gè)完整的信號(hào)給截?cái)嗔藛?剛開(kāi)始我也有這么想過(guò),但是仔細(xì)算一下才知道自己是多慮了。用計(jì)算器算一下知道,2^32 = 4.3x 10^9 左右,而2^24 = 16 x 10^6 左右,前后差了幾個(gè)數(shù)量級(jí),所以,我們?nèi)re_add[31:24],相當(dāng)于把一個(gè)波形的相位分成了256個(gè)點(diǎn),每個(gè)點(diǎn)對(duì)應(yīng)一個(gè)數(shù)據(jù)。
二、ROM
上一部分說(shuō)了,我們將一個(gè)波形分成了256個(gè)點(diǎn),每個(gè)點(diǎn)對(duì)應(yīng)一個(gè)數(shù)據(jù),那么我們?cè)趺磳?shí)現(xiàn)呢,這里就要用到我們的只讀存儲(chǔ)器ROM了,我們可以先把波形的數(shù)據(jù)送到ROM里存起來(lái),然后再?gòu)闹腥?,取的地址就是我們的fre_add[31:24]這8位數(shù),由此看來(lái),fword越大,這256個(gè)地址取址的間隔就越大,相應(yīng)的波形頻率也就越大了,當(dāng)然,我們的ROM不光存儲(chǔ)一個(gè)波形,我們可以把ROM設(shè)大一點(diǎn),里面放多種波形,再通過(guò)按鍵進(jìn)行相應(yīng)的選址,從而輸出各種波形
說(shuō)到這里有些人該問(wèn)了,怎么將數(shù)據(jù)送到ROM里去呢?這個(gè)的話就設(shè)計(jì)到mif文件的制作,具體怎么做大家還是自己回去補(bǔ)課了,不一一介紹了,但是我這里有一個(gè)mif文件生成器,網(wǎng)上也有下載,可以生成各種波形,也可以進(jìn)行相關(guān)參數(shù)的修改,注意保存的時(shí)候保存成.mif格式的文件即可,調(diào)用的時(shí)候在IP核 ROM的配置的時(shí)候調(diào)用就好了,但是要注意位寬。
三 、相位調(diào)制器
相位調(diào)制器部分就簡(jiǎn)單了,就是相位累加器取好的的8位ROM地址,我們可以通過(guò)按鍵進(jìn)行加加減減,從而控制ROM取址的不同,從而控制波形的相位
四 、參數(shù)計(jì)算
由上面的公式我們知道了輸出波形的頻率計(jì)算公式,當(dāng)fword =1的時(shí)候我們算一下
輸出頻率 Fout = 50_000000 / 2^32 = 0.01,就是個(gè)大約值了,也就是說(shuō),在fword =1的時(shí)候,我們的輸出波形的頻率為0.01HZ,假設(shè)我們讓波形初始化的時(shí)候輸出的是一個(gè)100HZ的正弦波,那么,我們應(yīng)該設(shè)定fword = 10000,相位的話可以隨便設(shè)置,我們就默認(rèn)為0相位好了。如果要進(jìn)行頻率,相位可調(diào),我們只需要讓fword每次加100,就相當(dāng)于頻率步進(jìn)為1HZ了,當(dāng)然,由于我們的地址是8位的,那么,步進(jìn)的相位就是 360 /256,大概等于1.4度吧。
還有,既然頻率為100HZ,也就是周期為0.01s,ROM要在0.01s內(nèi)要輸出256個(gè)數(shù),那么每輸出一個(gè)數(shù)的時(shí)間為0.01 /256 大概為 39us的樣子,因此,我們的DAC的采集頻率不能比ROM的輸出頻率小了,否則的話采集到的數(shù)據(jù)是不準(zhǔn)確的
綜上所述,我們總結(jié)一下
輸出頻率: 100HZ
輸出相位:0
步進(jìn)頻率:1HZ
步進(jìn)相位:1.4度
DAC采集時(shí)間:小于39us
當(dāng)然在一般情況下 DAC的采集頻率是遠(yuǎn)大于ROM的輸出頻率的,只要信號(hào)輸出頻率不是特別快,采集正確還是有保證的。為了保證采集的正確性,我特別加了一個(gè)數(shù)據(jù)變化檢測(cè)部分,一但數(shù)據(jù)發(fā)生變化,就告知DAC模塊,做相應(yīng)處理
一切準(zhǔn)備就緒,我們可以做一下仿真,具體的仿真調(diào)試過(guò)程不做詳解,還是大家自己動(dòng)手去做的過(guò)程
五、DAC接口電路
DA芯片我用的是TLC5620這塊芯片,這塊芯片是四路輸出,8位的的數(shù)模準(zhǔn)換芯片,芯片的操作不是很難,我們還是先來(lái)看一下芯片的datasheet
DA芯片有這幾個(gè)管腳需要用到,分別是
dac_clk,用于產(chǎn)生DAC的工作時(shí)鐘,說(shuō)明文檔上說(shuō)時(shí)鐘最大為1M,而我們的晶振為50M因此我們需要做個(gè)分頻,我做了個(gè)64分頻,當(dāng)然是為了穩(wěn)定,如果可以大家也可以試試更高的頻率
dac_data , 是串行輸入的接口,用來(lái)接收數(shù)字信號(hào)
dac_load ,將接收來(lái)的數(shù)字信號(hào)開(kāi)始轉(zhuǎn)化成模擬信號(hào)的使能端,低電平有效,要持續(xù)最低250ns
dac_ldac , dac信號(hào)刷新控制端,當(dāng)dac為低電平的時(shí)候一直有模擬信號(hào)輸出,否則不再刷新
上面那個(gè)時(shí)序圖大體解釋一下,就是在load信號(hào)是高電平期間,每來(lái)一個(gè)DAC工作時(shí)鐘的下降沿,就將1位數(shù)據(jù)通過(guò)dac_data端口送到DAC芯片內(nèi)部的移位寄存器中,寄存器是11位的,前兩位為輸出模擬信號(hào)的通道號(hào),第三位是用來(lái)計(jì)算輸出電壓用的一個(gè)參數(shù)吧,低8位是輸入的數(shù)字信號(hào),當(dāng)移位寄存器存滿之后,給一個(gè)load信號(hào),工作時(shí)鐘處于不工作狀態(tài),注意,這一點(diǎn)很重要,我當(dāng)時(shí)就是不知道這一點(diǎn),一直調(diào)不好,就是在轉(zhuǎn)換期間,讓工作時(shí)鐘處于非工作狀態(tài),等待250ns之后,將load拉高,進(jìn)行下一次采集。
關(guān)于代碼的分析這里也不做詳細(xì)分析了,大家還是自行消化,這里只傳一部分,關(guān)于數(shù)據(jù)的發(fā)送部分的代碼
每來(lái)一個(gè)時(shí)鐘,送一位數(shù)據(jù)給dac_data端口,送滿移位寄存器為止,當(dāng)移位寄存器計(jì)滿的時(shí)候,load拉低,同時(shí)時(shí)鐘停止工作,bit_counter 清零,等待下一次采集。當(dāng)然當(dāng)數(shù)據(jù)發(fā)生變化的時(shí)候,也就是data_change 信號(hào)來(lái)的時(shí)候,bit_counter 也清零,重新采集,避免采集錯(cuò)誤
全部模塊編譯完成之后,我們就可以用示波器來(lái)檢測(cè)我們的結(jié)果了
由示波器的結(jié)果我們可以看到,輸出電壓峰值為2.5V,當(dāng)然這是由芯片決定的,輸出頻率為116HZ,大體符合我們的要求,畢竟我們很多參數(shù)做了近似,再通過(guò)按鍵進(jìn)行波形的變換,發(fā)現(xiàn)各波形輸出正常,只有方波和鋸齒波,在電壓下降的時(shí)候變化有點(diǎn)緩慢,當(dāng)然這也得考慮我們芯片的因素,畢竟電壓不能變化的那么快,也屬于正常情況
波形顯示正常,下面通過(guò)按鍵來(lái)調(diào)節(jié)波形的頻率和相位,可是實(shí)現(xiàn)實(shí)時(shí)顯示的功能,發(fā)現(xiàn)頻率,相位都有所改變
當(dāng)然,這個(gè)工程也有做的不好的地方,例如,再進(jìn)行相位調(diào)節(jié)的時(shí)候,由于各種波形的地址在ROM里面是挨在一起的,這樣進(jìn)行相位調(diào)節(jié)會(huì)侵犯其他波形的地址,這一點(diǎn)我當(dāng)時(shí)也考慮過(guò)了,短時(shí)間內(nèi)沒(méi)有想出更好的辦法,可以用多個(gè)ROM,其他的辦法還請(qǐng)大家自己動(dòng)腦子想一下吧,想出來(lái)了可以給我留言,大家一起交流嘛
好了,這一次主要還是講了一下工程的全過(guò)程,沒(méi)有仔細(xì)講代碼編寫的具體過(guò)程,也沒(méi)有講仿真時(shí)候的操作流程,這些部分還是留給讀者慢慢去摸索,畢竟這也是一個(gè)學(xué)習(xí)的過(guò)程,今天就到這里吧,由于小墨手上也有了項(xiàng)目,平時(shí)還要上課,更新速度方面應(yīng)該不是很快!謝謝大家的支持~
評(píng)論