副標(biāo)題:做個(gè)SPI接口的任意波形DDS
我之前用過(guò)的CPLD有Altera公司的MAX和MAX-II系列,主要有兩個(gè)優(yōu)點(diǎn):1、程序存儲(chǔ)在片上Flash,上電即行,保密性高。2、CPLD器件規(guī)模小,成本和功耗低,時(shí)序不收斂情況也不容易出現(xiàn)。缺點(diǎn)也很明顯:1、沒有片上RAM,無(wú)法對(duì)數(shù)據(jù)進(jìn)行高速暫存和處理;2、沒有PLL,使用一個(gè)以上的高頻時(shí)鐘非常不方便;3、沒有小封裝產(chǎn)品,MAX-II最小的EPM240也是LQFP100封裝。近年來(lái),隨著Altera被Intel收購(gòu),對(duì)MAX-II的支持力度不斷降低,當(dāng)前EPM240的價(jià)格也達(dá)到了百元左右。
最近在B站關(guān)注到一種國(guó)產(chǎn)CPLD——AG1280Q48,幾乎滿足了我對(duì)CPLD的一切幻想:1、片上Flash,上電即行。2、有1280個(gè)LUT和觸發(fā)器,資源足以媲美小型FPGA,而工作電流僅為幾個(gè)mA——MAX-II的幾分之一。3、成本低到數(shù)元。3、QFN48小封裝,節(jié)約嵌入式系統(tǒng)空間,焊接又相對(duì)BGA封裝簡(jiǎn)單。4、擁有和FPGA類似(包括PLL和片上RAM塊)的資源,可用于完成以往CPLD無(wú)法完成的任務(wù),如信號(hào)緩沖,高速通信等。
AG1280和STM32、GD32等低成本MCU聯(lián)合使用時(shí),能將只有專用解決方案才能完成的功能帶給通用嵌入式系統(tǒng)。個(gè)人感覺,AG1280的最佳應(yīng)用場(chǎng)景是在低成本應(yīng)用領(lǐng)域和MCU協(xié)同工作, MCU+AG1280能部分替代Xilinx的Zynq方案。(注:AGM公司也有類似Zynq的ARM Cortex-M3 + FPGA方案,但我個(gè)人不看好這些方案,原因在于嵌入式工程師使用這些新MCU的開發(fā)環(huán)境和固件庫(kù)的學(xué)習(xí)成本過(guò)高,沒有學(xué)習(xí)動(dòng)力。)
為驗(yàn)證這一設(shè)計(jì)思路,我自己動(dòng)手做了一個(gè)MCU+AG1280+DAC的DDS(直接頻率合成器)系統(tǒng),跑通了STM32+AG1280的開發(fā)過(guò)程。其中AG1280除了完成DDS算法所需的地址累加、數(shù)據(jù)表格存儲(chǔ)和查詢之外,還實(shí)現(xiàn)了與STM32之間的同步串行數(shù)據(jù)接收和波形表格存入。現(xiàn)將開發(fā)全過(guò)程分享給各位網(wǎng)友,相信會(huì)對(duì)大家有一定的參考價(jià)值,也供大神批評(píng)指正。
有網(wǎng)友可能會(huì)較真質(zhì)疑方案的意義:STM32有片上DAC,且還支持DMA,可以構(gòu)成任意型號(hào)發(fā)生器,為什么還要用附加的可編程邏輯器件和DAC芯片?其原因在于STM32的DMA不支持存儲(chǔ)器的地址遞增值變化,因此不用中斷無(wú)法實(shí)現(xiàn)DDS算法——而這也正好體現(xiàn)了AG1280在系統(tǒng)中的價(jià)值。
一、硬件電路
MCU開發(fā)板很多,這里就不“重復(fù)發(fā)明輪子”了——直接用手頭STM32開發(fā)板上的PMOD接口來(lái)和AG1280子板連接。系統(tǒng)硬件方案框圖如下圖所示。
(注1:PMOD接口是由Xilinx官方定義的一種用于其FPGA開發(fā)板的低速接口,現(xiàn)在很多FPGA和嵌入式處理器開發(fā)板上都有這種接口。PMOD僅使用12芯2.54mm間距的兩排普通連接器,其中含有8個(gè)GPIO以及電源、地。
注2:有PMOD接口的單片機(jī)開發(fā)板可以自行搜索購(gòu)買,我們教研室自己也開發(fā)過(guò)自編教材的配套Innovation-STM32開發(fā)板。)
![pYYBAGMntZ-AWnYIAAGP5SyNXg8475.png](https://file.elecfans.com/web2/M00/6B/3F/pYYBAGMntZ-AWnYIAAGP5SyNXg8475.png)
圖1 系統(tǒng)硬件框圖
用STM32開發(fā)板的PMOD連接一塊自制的,具有一主一從兩個(gè)PMOD接口的AG1280板子,該板子的另一個(gè)PMOD接口用于連接DAC板子。至于DAC我選用了常見的低成本同步串行芯片DAC7512。AG1280板子和DAC板子的電路圖如下所示。
![poYBAGMntcSABHNPAANgZJWKt9w909.png](https://file.elecfans.com/web2/M00/6A/A7/poYBAGMntcSABHNPAANgZJWKt9w909.png)
圖2 兩個(gè)PMOD接口的AG1280電路原理圖
![pYYBAGMntd-AbAGWAAFAd7elYmU938.png](https://file.elecfans.com/web2/M00/6B/3F/pYYBAGMntd-AbAGWAAFAd7elYmU938.png)
圖3 PMOD接口的DAC7512電路原理圖
圖2是AG1280基本電路,值得注意的有幾點(diǎn):
1、IO_GLOBE_S1(位于第9腳)、IO_GLOBE_S2(位于第13腳)、IO_GLOBE_S3(位于第15腳)、IO_GLOBE_S4(位于第19腳);IO_GLOBE_N1(位于第41腳) 、IO_GLOBE_N2(位于第44腳) 、IO_GLOBE_N3(位于第46腳)可以作為全局時(shí)鐘輸入管腳,可用于輸入全局時(shí)鐘。但若要使用PLL,則只能從13、15和19管腳輸入。
2、圖2電路板載一個(gè)20MHz有源晶振,另外還可以通過(guò)PMOD接口從STM32的MCO時(shí)鐘輸出管腳獲得時(shí)鐘,它們被連接到具有PLL輸入功能的管腳13、15上。
3、AG1280的GPIO分為North和South兩組,可以使用不同IO電平,以實(shí)現(xiàn)不同電平邏輯的轉(zhuǎn)換。另外AG1280還需要3.3V電源作為片上Flash電源,且該電源域North組的IO電源共用,因此North組也只能使用3.3V的IO電源電壓。South組卻可以任選電源電壓。
4、AG1280還需要1.2V內(nèi)核電源電壓,且該電源應(yīng)略遲于Flash電源上電,以方便Flash加載程序。我的圖2電路通過(guò)PMOD接口從STM32開發(fā)板獲得3.3V電源,再用LDO芯片XC6206P122MR從3.3V向下穩(wěn)壓到1.2V內(nèi)核電源,LDO后帶有100uF電容,1.2V上電時(shí)間自然要落后于3.3V上電。
二、基于Supera和Quartus II的AG1280開發(fā)流程
AG1280的開發(fā)EDA軟件Supera還不具備分析和綜合電路的能力,但能實(shí)現(xiàn)其特有的PLL和片上RAM的IP核打包、綜合后的布局布線、下載文件打包及下載等功能。我計(jì)劃完成的DDS系統(tǒng),完整的包含了PLL、片上RAM以及全部開發(fā)流程。
1、開發(fā)平臺(tái)搭建
到百度網(wǎng)盤http://pan.baidu.com/s/1eQxc6XG 提取密碼:q59e下載AGM公司EDA開發(fā)軟件Supra(網(wǎng)盤上有多個(gè)版本的Supra,選擇需要的一種即可)。Supra無(wú)需安裝,下載后將其放置在不含中文的路徑下,直接運(yùn)行Bin目錄下的Supra.exe即可。
目前版本的Supra還無(wú)法進(jìn)行硬件描述語(yǔ)言及原理框圖的開發(fā)和電路綜合,用戶只能在Supra下創(chuàng)建工程并完成AGM公司特有IP(包括PLL和RAM)的配置,再通過(guò)Supra創(chuàng)建Quartus-II工程文件,在轉(zhuǎn)到Quartus-II下完成硬件描述語(yǔ)言和原理框圖開發(fā)和電路綜合,最后再回到Supra中完成器件內(nèi)部的布局布線、下載文件的打包和器件燒寫(具體流程在后續(xù)會(huì)詳細(xì)介紹)。
綜上,進(jìn)行AG1280的開發(fā)一定需要安裝一個(gè)順手的Quartus-II。這里特別提醒網(wǎng)友注意,Supra只支持Quartus-II 13.0以上,且不支持Web與Lite版本,必須安裝Full或Standard版本(本人掉到過(guò)坑里,因此特別提醒大家注意)。至于Quartus-II的安裝方法,網(wǎng)上資料較多,這里不再贅述。
AG1280可以使用Intel的USB-Blaster進(jìn)行下載和軟件調(diào)試,但淘寶網(wǎng)上USB-Blaster版本較多,價(jià)格差異較大。據(jù)網(wǎng)傳,有的版本USB-Blaster不支持AG1280的Flash下載,大家可自行注意避坑。
2、開發(fā)流程
1)新建Supra工程
運(yùn)行 Supra,選擇 File - Project - New Project。
![poYBAGMntgmAMTyZAABthnIsl4E763.png](https://file.elecfans.com/web2/M00/6A/A7/poYBAGMntgmAMTyZAABthnIsl4E763.png)
圖4 新建Supra工程
隨后選擇工程存放路徑并填入工程名稱,注意不要使用中文路徑、國(guó)產(chǎn)路徑,也不要在路徑中使用空格。
2)配置AGM自有硬件IP
AGM公司自有的硬件及其相關(guān)電路的IP只能在Supra中配置。先配置PLL:選擇Supra中Tools - CreateIP – Create Pll菜單,在彈出的下列界面中配置PLL。
![pYYBAGMnti-AD8SrAAGdyePk6t0671.png](https://file.elecfans.com/web2/M00/6B/3F/pYYBAGMnti-AD8SrAAGdyePk6t0671.png)
圖5 配置PLL IP
分別配置模塊名稱、輸入頻率、PLL類型、反饋模式、輸出時(shí)鐘路數(shù)、輸出頻率后,單擊Generate按鈕產(chǎn)生IP和頂層封裝HDL文件(模塊名稱.v和模塊名稱.ip)。
其中值得注意的是:AG1280有兩種時(shí)鐘源模式:片內(nèi)RC振蕩器模式和片外有源振蕩器模式。可以在反饋模式(Feedback mode)選項(xiàng)中選擇EXT_FEEDBACK,以選擇外部有源振蕩器模式;選擇NO_REFERENCE,以選擇片上RC振蕩器模式。片上RC振蕩器振蕩頻率不會(huì)太準(zhǔn)確,供不需要精確定時(shí)的系統(tǒng)使用。若選擇片上振蕩器則應(yīng)在輸入頻率(Input frequency)處輸入8MHz,否則真實(shí)輸出頻率將與你輸入的頻率成比例變化。
另外,Supra中AG1280的PLL配置中的PLL類型(PLL type),只能選擇PLLX。而輸出路數(shù)(PLL output count),相位移動(dòng)(Phase shift)等配置參照字面意思理解即可。
繼續(xù)配置AG1280的片上存儲(chǔ)器RAM IP:選擇Supra中Tools - CreateIP – Create memory菜單,在彈出的下列界面中配置片上BRAM。
![poYBAGMntlCAO0o0AAGyvS9DAFQ474.png](https://file.elecfans.com/web2/M00/6A/A8/poYBAGMntlCAO0o0AAGyvS9DAFQ474.png)
圖6 配置片上存儲(chǔ)器IP
根據(jù)我的DDS系統(tǒng)設(shè)計(jì)思路,AG1280實(shí)現(xiàn)的DDS控制器能從MCU接收波形數(shù)據(jù),同時(shí)向DAC輸出實(shí)時(shí)波形數(shù)據(jù),因此,需要實(shí)現(xiàn)一個(gè)雙口RAM。如圖6所示,將存儲(chǔ)器IP配置為2個(gè)端口,每個(gè)端口的數(shù)據(jù)寬度都是12bits(DAC7512的分辨率為12位),存儲(chǔ)器深度為256(DDS算法要求波形表深度為2的整數(shù)次冪)。AG1280片上RAM較多,也可以選擇更大的存儲(chǔ)器深度,以獲得更高信噪比。
另外,我還選擇了復(fù)位后從Flash向雙口RAM內(nèi)部加載初始數(shù)據(jù),因此指定了初始化數(shù)據(jù)文件(Select init file)。根據(jù)DAC7512對(duì)數(shù)據(jù)數(shù)據(jù)格式的要求,這些數(shù)據(jù)是0-4095之間的無(wú)符號(hào)數(shù),你可以通過(guò)MATLAB或Python等工具計(jì)算產(chǎn)生。注意,Supra數(shù)據(jù)文件的格式與Quartus-II的MIF、HEX都不一樣;Supra要求數(shù)據(jù)文件中,每個(gè)數(shù)據(jù)占一行,且采用ASCII碼表示十六進(jìn)制數(shù)。例如下面一樣。
831
862
893
8C4
8F5
925
956
986
9B6
完成IP配置后,單擊Generate按鈕,Supra將自動(dòng)生成可在Quartus-II中調(diào)用的IP文件和Verilog HDL文件。
3)在Quartus-II中完成功能模塊開發(fā)
單擊Supra菜單中Tools – Migrate,將工程移植為Quartus-II工程。在下圖所示的配置窗口中輸入工程名稱、器件、需要使用的之前創(chuàng)建的IP等信息后,單擊Next按鈕。
注:最下面一個(gè)對(duì)話欄中,需要輸入所有需要轉(zhuǎn)換到Quartus-II工程的IP名稱,如果有多余一個(gè)IP需要轉(zhuǎn)換,可以在兩個(gè)路徑之間用半角逗號(hào)分隔開來(lái),也可以點(diǎn)擊Browse按鈕后同時(shí)多選多個(gè)IP文件。
![poYBAGMntnSAWL9AAAB018FVMqY064.png](https://file.elecfans.com/web2/M00/6A/A8/poYBAGMntnSAWL9AAAB018FVMqY064.png)
圖7 移植為Quartus-II工程
Supra彈出如下界面,可轉(zhuǎn)入Quartus-II進(jìn)行開發(fā)和綜合電路。
![pYYBAGMntpaAVnuHAAGB8DWz5o4519.png](https://file.elecfans.com/web2/M00/6B/3F/pYYBAGMntpaAVnuHAAGB8DWz5o4519.png)
圖8 移植為Quartus-II工程
此時(shí)Supra已經(jīng)在工程目錄下建了與其工程同名的Quartus-II工程(xxxxx.qpf),以及頂層Verilog HDL文件,下一步需要在Quartus-II中打工程完成所有電路模塊代碼或原理圖的開發(fā)。下圖是我創(chuàng)建的DDS系統(tǒng)工程——DDS_SPI_dualRAM下的各個(gè)模塊層次關(guān)系。
![pYYBAGMntrKADe20AAG0A0aogmk440.png](https://file.elecfans.com/web2/M00/6B/3F/pYYBAGMntrKADe20AAG0A0aogmk440.png)
圖9 Quartus-II工程
可以看到,在缺省情況下Quartus-II工程使用的器件是Cyclone IV系列的EP4CE75F29C8,我們不需要修改該工程使用的器件。但可以限定Quartus-II通過(guò)增量編譯模式不編譯Supra已經(jīng)生成的IP:右鍵單擊PLL IP和memory IP,并將其設(shè)置為Design Partition(該功能只有Prime和Standard版本的Quartus-II才有)。
![pYYBAGMntsyAZyr_AAMlhcsz2BM032.png](https://file.elecfans.com/web2/M00/6B/3F/pYYBAGMntsyAZyr_AAMlhcsz2BM032.png)
圖10 設(shè)置IP為Design Partition
在Quartus-II中運(yùn)行Supra生成的腳本文件af_quartus.tcl:選擇Quartus-II的Tools菜單下的Tcl scripts,并在彈出的窗口中運(yùn)行工程目錄下的af_quartus.tcl文件。
![poYBAGMntuqAOKGgAABQn_2uVdI301.png](https://file.elecfans.com/web2/M00/6A/A8/poYBAGMntuqAOKGgAABQn_2uVdI301.png)
圖11 Quartus-II運(yùn)行Tcl腳本
Quartus-II將彈出Windows命令行窗口,等待綜合工程中的所有模塊,綜合成功后Quartus-II的任務(wù)就完成了(這里可能需要幾分鐘)。
此時(shí)Supra已經(jīng)自動(dòng)生成了一個(gè)文件名與工程名相同,使用后綴asf的管教約束文件。該文件目前還是空的,可以其中添加約束器件管腳的腳本。asf文件的語(yǔ)法與Quartus-II的tcl腳本管腳約束語(yǔ)法相同,例如:
set_location_assignment -to cs_host1 PIN_43
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to cs_host1
上面的腳本將cs_host1約束到了AG1280的43腳,并將其配置成了弱上拉模式,以防止干擾拉低cs_host1,造成數(shù)據(jù)誤傳輸。
4)在Supra中完成AG1280的布局布線和程序下載燒寫
根據(jù)圖2的硬件電路編輯完asf文件,即可返回Supra的圖8所示界面,單擊Next按鈕。(注:若你已經(jīng)關(guān)閉了Supra也不要緊,再次打開Supra工程后,單擊Migrate按鈕重新進(jìn)入圖8所示界面即可)。在隨后的界面中檢查配置,并單擊Finish按鈕,Supra將完成布局布線。
若一切順利,在Supra下部的Message窗口中間看到編譯成功的提示信息,即可進(jìn)入下載文件打包和USB Blaster下載配置文件階段:選擇Supra中的Tools – Program,連接電腦、USB Blaster以及AG1280板子的JTAG接口,在彈出的窗口中單擊Query Device ID來(lái)查詢Supra是否連接到AG1280。若正確連接了硬件,AG1280的ID應(yīng)該是0x00120010。隨后,可以在Program from file中選擇需要下載的文件,單擊Browse按鈕選擇所需的下載文件。其中xxxxx_sram.prg是直接燒寫到AG1280的SRAM中;xxxxx_hybird.prg是燒寫到Flash中,可以實(shí)現(xiàn)程序掉電不丟程序,上電即行。(文件名中的xxxxx是Supra工程的名稱)。
![poYBAGMntwSANPYSAACwCu1_uYA388.png](https://file.elecfans.com/web2/M00/6A/A8/poYBAGMntwSANPYSAACwCu1_uYA388.png)
圖12 程序下載燒寫界面
單擊Program按鈕,即可燒寫剛才完成的程序。
三、在AG1280上實(shí)現(xiàn)基于DDS算法的任意波形發(fā)生器
1、DDS原理
DDS算法的功能特點(diǎn)是可以獲得非常高的頻率分辨率,以取得近乎連續(xù)的頻率調(diào)節(jié)效果。下面簡(jiǎn)述一下DDS算法的核心思想,幫助讀者理解AG1280上的硬件模塊的原理和相互關(guān)系。一時(shí)無(wú)法理解的初學(xué)者,可以進(jìn)一步閱讀其他介紹DDS原理的書籍和帖子。
假設(shè)存儲(chǔ)器中有個(gè)長(zhǎng)度為N=2^n的波形數(shù)據(jù)表格,這些數(shù)據(jù)為1個(gè)周期的波形。若用頻率fc從該表格中每間隔K個(gè)點(diǎn)取出一個(gè)放入DAC中變?yōu)?a href="http://m.xsypw.cn/analog/" target="_blank">模擬信號(hào),則DAC輸出模擬信號(hào)的頻率將是:
fo = fc * K / N (1)
從(1)式中可以看出輸出模擬信號(hào)的頻率fo和每次在數(shù)據(jù)表格中跳躍的地址數(shù)k成正比:k每增加1,輸出頻率fo就增加fc/N。為獲得足夠搞得頻率分辨率,即使得fo輸出的頻率能夠接近連續(xù)的調(diào)節(jié),N的數(shù)值應(yīng)該越大越好。一些ADI公司的商業(yè)DDS芯片,N甚至達(dá)到了2^40 ≈ 1T,這樣大的表格顯然是無(wú)法直接存儲(chǔ)在AG1280中的。好在用1T個(gè)點(diǎn)來(lái)存儲(chǔ)一個(gè)周期的信號(hào)其實(shí)并沒有多大意義:在表格中相臨的很多點(diǎn)大概率都是相同的內(nèi)容。既然相鄰點(diǎn)的數(shù)據(jù)都差不多,還不如不存儲(chǔ)——在波形表格中每相臨2^p個(gè)點(diǎn),只存儲(chǔ)第一個(gè)點(diǎn)的數(shù)值,如果用到后續(xù)2^p - 1個(gè)點(diǎn),則都用第一個(gè)點(diǎn)的數(shù)值來(lái)代替。則AG1280所需的數(shù)據(jù)表格長(zhǎng)度僅為2^(N-p) = 2^n(其中,設(shè)n = N-p),這樣在AG1280中只需要長(zhǎng)度N位的累加器和頻率控制字,他們?cè)跁r(shí)鐘控制下不斷相加新的表格地址(也是N位),但在讀波形表時(shí),只使用這個(gè)N位地址的高n位,低p位地址則直接舍棄。
我們的系統(tǒng)使用的DAC是DAC7512,其輸出模擬信號(hào)的刷新率fc為100KSPS,精度為12bits,取N為16,n為8。即所需的存儲(chǔ)器為256(2^8)個(gè)12位(具體配置參見圖6所示),地址累加器和頻率控制字為16位。獲得的頻率分辨率為100K / 2^16 ≈ 1.53Hz,理論上頻率調(diào)節(jié)范圍上限為:100K / 2 = 50KHz(奈奎斯特頻率),頻率下限為:100K / 2^16 ≈ 1.53Hz。
2、硬件總體設(shè)計(jì)
AG1280中的整個(gè)電路以雙口RAM為核心,其左側(cè)接口與MCU相連,用于接收MCU下發(fā)的波形數(shù)據(jù)和頻率控制字K的數(shù)值;右側(cè)接口和DAC7512相連,用于依次輸出DDS算法輸出的數(shù)據(jù)。
雙口RAM左側(cè)地址由一個(gè)每次加1的計(jì)數(shù)器產(chǎn)生,以遍歷所有的村春?jiǎn)卧挥覀?cè)地址由一個(gè)每次加K的加法器產(chǎn)生,以實(shí)現(xiàn)DDS算法的頻率控制。由于雙口RAM的深度256剛好是2的整數(shù)次冪,所以無(wú)需特意處理計(jì)數(shù)器和加法器的溢出問題,溢出后自然返回地址開頭即可。
AG1280中還應(yīng)實(shí)現(xiàn)兩個(gè)SPI接口:一個(gè)SPI從機(jī)接口(通過(guò)左側(cè)的PMOD接口)用于接收來(lái)自MCU的數(shù)據(jù);另一個(gè)SPI主機(jī)接口(通過(guò)右側(cè)的PMOD接口)用于向同步串行接口的DAC7512下發(fā)數(shù)據(jù)。
左側(cè)與MCU的接口除了需要接收波形數(shù)據(jù)之外,還需要接收頻率控制字K。我通過(guò)兩個(gè)管腳分別輸出兩個(gè)低電平選通信號(hào)cs1和cs2來(lái)區(qū)分當(dāng)前下發(fā)的數(shù)據(jù)是波形數(shù)據(jù)還是頻率控制字。
3、硬件實(shí)現(xiàn)
3.1雙口RAM右側(cè)與DAC接口的電路部分
1)DAC輸出同步時(shí)鐘生成電路
DAC7512需要使用100KSPS的刷新率,需要25MHz的主時(shí)鐘分配產(chǎn)生輸出同步時(shí)鐘信號(hào)sap_syc_sig,該信號(hào)還將同步雙口RAM右側(cè)的讀取和DDS地址累加器的不斷疊加。
1 module samp_syc_sig(
2 input clk_25m,
3 input nrst,
4 output samp_syc_sig
5 );
6 reg[9:0] time_cnt;
7 wire comp;
8 reg samp_syc_sig_reg;
9 assign samp_syc_sig = samp_syc_sig_reg;
10 always @ (negedge clk_25m or negedge nrst)
11 begin
12 if(!nrst)
13 time_cnt[9:0] <= 10'd0;
14 else
15 if(time_cnt[9:0] < 10'd249)
16 time_cnt[9:0] <= time_cnt[9:0] + 10'd1;
17 else
18 time_cnt[9:0] <= 10'd0;
19 end
20 //以下組合邏輯用于產(chǎn)生start信號(hào)
21 assign comp = (time_cnt[9:0] < 10'd20) ? 1'b1 : 1'b0; ? ?
22 always @ (negedge clk_25m or negedge nrst)
23 begin
24 if(!nrst)
25 samp_syc_sig_reg <= 1'b0;
26 else
27 samp_syc_sig_reg <= comp;
28 end
29 endmodule
同步時(shí)鐘生成電路
2)與DAC7512通信的SPI主機(jī)電路
1 module DAC7512(
2 input clk_25m,//25MHz左右的時(shí)鐘信號(hào)
3 input nrst,//低電平復(fù)位
4 input syc_sig,//外部產(chǎn)生的同步輸出信號(hào),當(dāng)其出現(xiàn)上升沿時(shí)刷新輸出電壓
5 output cs_da,
6 output mosi_da,
7 output sck_da,
8 input [11:0] data_in//待轉(zhuǎn)換的數(shù)據(jù),在每次開始轉(zhuǎn)換之前被鎖存到模塊中,只有低12位有效
9 );
10 reg[7:0] cnt_cs;
11 reg cs_da_reg;
12 reg sck_da_reg;
13 reg[2:0] sck_timer;//用于測(cè)量單個(gè)DAC通信時(shí)鐘長(zhǎng)度的計(jì)數(shù)器
14 /////////以下用25MHz時(shí)鐘,產(chǎn)生片選信號(hào)////////
15 assign cs_da = cs_da_reg;
16 always @ (posedge clk_25m or negedge nrst)
17 begin
18 if(!nrst)
19 begin
20 cnt_cs[7:0] <= 8'd0;
21 cs_da_reg <= 1'b1;
22 end
23 else begin
24 if(syc_sig == 1'b1)//同步信號(hào)高電平時(shí),回復(fù)到計(jì)數(shù)初始狀態(tài)
25 begin
26 cnt_cs[7:0] <= 8'd0;
27 cs_da_reg <= 1'b1; ??
28 end
29 else
30 begin
31 if(cnt_cs[7:0] < 8'd98) //98個(gè)脈沖,少一個(gè)防止競(jìng)爭(zhēng)現(xiàn)象
32 begin
33 cnt_cs[7:0] <= cnt_cs[7:0] + 8'd1;?
34 cs_da_reg <= 1'b0;
35 end
36 else begin
37 cnt_cs[7:0] <= cnt_cs[7:0];
38 cs_da_reg <= 1'b1;
39 end
40 end
41 end
42 end
43 ////////以下產(chǎn)生串行同步輸出時(shí)鐘////////////
44 assign sck_da = sck_da_reg;
45 always @(posedge clk_25m or posedge cs_da)
46 begin
47 if(cs_da)
48 begin
49 sck_timer[2:0] <= 3'd0;
50 sck_da_reg <= 1'b0;
51 end
52 else begin
53 if(sck_timer[2:0] < 3'd2)
54 begin
55 sck_timer[2:0] <= sck_timer[2:0] + 3'd1;
56 sck_da_reg <= sck_da_reg;
57 end
58 else begin
59 sck_timer[2:0] <= 3'd0;
60 sck_da_reg <= !sck_da_reg;
61 end
62 end
63 end
64 ///////////產(chǎn)生串行輸出信號(hào),需要串行輸出的數(shù)據(jù)在CS下降沿在并行輸入口被鎖存/////////
65 reg[16:0] shift_reg;
66 //注意這里多一個(gè)位,是因?yàn)镈AC7512在下降沿讀取數(shù)據(jù),而我們的數(shù)據(jù)在第一個(gè)SCK脈沖上升沿就開始移出,因此會(huì)多移出一個(gè)位(第一位)
67 assign mosi_da = shift_reg[16];
68 always @ (posedge sck_da or posedge cs_da)
69 begin
70 if(cs_da)
71 shift_reg[16:0] <= {5'b00000,data_in[11:0]};//對(duì)于dac7512而言,最高四位為0000,表示輸出使能,且連接1KΩ負(fù)載
72 else
73 shift_reg[16:0] <= shift_reg[16:0]<<1;
74 end
75 endmodule
DAC7512驅(qū)動(dòng)電路
上面的代碼,使用獨(dú)立的計(jì)數(shù)器分別產(chǎn)生SCK和CS信號(hào),避免了由于組合邏輯信號(hào)鏈過(guò)長(zhǎng)可能造成的建立時(shí)間不收斂問題。另外輸入數(shù)據(jù)data_in只有12位,其內(nèi)容就是模擬信號(hào)大小。DAC7512的SPI通信中需要使用16位數(shù)據(jù),其高四位被上面的模塊自動(dòng)補(bǔ)充為控制字4’b0000,需要使用其他控制模式的網(wǎng)友,可以根據(jù)DAC7512手冊(cè)自行修改。
3)DDS地址累加器電路
1 module addr_adder(
2 input clk,
3 input nrst,
4 input[15:0] delta_addr,
5 output[7:0] high_byte_addr
6 );
7 reg[15:0] inc_addr_reg;
8 assign high_byte_addr[7:0] = inc_addr_reg[15:8];
9 always @(posedge clk or negedge nrst)
10 begin
11 if(!nrst)
12 inc_addr_reg[15:0] <= 16'H0;
13 else
14 inc_addr_reg[15:0] <= inc_addr_reg[15:0] + delta_addr[15:0];
15 end
16 endmodule
DDS累加器代碼
注意,根據(jù)DDS算法,16位的累加器每次增加的值也是16位的頻率控制字delta_addr(相當(dāng)于公式(1)中的K),但每次只輸出累加器的高8位作為雙口RAM右側(cè)的地址。
3.2雙口RAM左側(cè)與MCU接口的電路部分。
4)根據(jù)不同片選信號(hào),將MCU的SPI信號(hào)分解為波形數(shù)據(jù)和頻率控制字的數(shù)據(jù)多路器電路
1 module mux_HostSpi(
2 input mosi,
3 input sck,
4 input cs1,
5 input cs2,
6 output mosi_ram,
7 output mosi_DdsDelta,
8 output sck_ram,
9 output sck_DdsDelta
10 );
11 assign mosi_ram = mosi & (!cs1);//輸入CS1為低電平時(shí),spi信號(hào)被送到雙口ram一側(cè)
12 assign mosi_DdsDelta = mosi & (!cs2);//輸入CS2為低電平時(shí),spi信號(hào)被送到DDS頻率控制字
13 assign sck_ram = sck & (!cs1);//輸入CS1為低電平時(shí),spi信號(hào)被送到雙口ram一側(cè)
14 assign sck_DdsDelta = sck & (!cs2);//輸入CS2為低電平時(shí),spi信號(hào)被送到DDS頻率控制字
15 endmodule
主機(jī)SPI信號(hào)多路器電路
上述信號(hào)可以根據(jù)MCU輸出的兩個(gè)不同的片選信號(hào)cs1和cs2將MCU輸出的mosi、sck信號(hào)分解為連接波形數(shù)據(jù)雙口RAM的mosi_ram、sck_ram,以及與頻率控制字向量的mosi_DdsDelta和sck_DdsDelta。
5)SPI從機(jī)接收寄存器電路
1 module shift_reg(
2 input mosi,
3 input sck,
4 input nrst,//低電平復(fù)位
5 input[15:0] ini_data,//復(fù)位后的初始化值
6 output[15:0] data_out
7 );
8 reg[15:0] shft_r;
9 assign data_out[15:0] = shft_r[15:0];
10 always @ ( posedge sck or negedge nrst)
11 begin
12 if(!nrst)//復(fù)位后初始化為初始值
13 shft_r[15:0] <= ini_data[15:0];
14 else
15 shft_r[15:0] <= {shft_r[14:0],mosi};
16 end
17 endmodule
SPI數(shù)據(jù)接收移位寄存器
這個(gè)電路被例化為兩個(gè)實(shí)例,分別用于接收波形數(shù)據(jù)或頻率控制字。讀者也可以只例化一個(gè)SPI從機(jī)移位寄存器,但這樣做數(shù)據(jù)多路器就要放在移位寄存器并行化之后。這一點(diǎn)可以根據(jù)器件資源消耗情況靈活決定。
6)雙口RAM左側(cè)地址生成電路
1 module addr_generator(
2 input clk,
3 input nrst,
4 output[7:0] inc_addr
5 );
6 reg[7:0] inc_addr_reg;
7 assign inc_addr[7:0] = inc_addr_reg[7:0];
8 always @(posedge clk or negedge nrst)
9 begin
10 if(!nrst)
11 inc_addr_reg[7:0] <= 8'd0;
12 else
13 inc_addr_reg[7:0] <= inc_addr_reg[7:0] +1'b1;
14 end
15 endmodule
雙口RAM存儲(chǔ)地址生成電路
這個(gè)地址生成電路用于產(chǎn)生將接收到的波形數(shù)據(jù)依次存入雙口RAM所需的地址,是一個(gè)簡(jiǎn)單的帶異步復(fù)位信號(hào)的加1增計(jì)數(shù)器。
注意:1、該計(jì)數(shù)器的時(shí)鐘應(yīng)使用MCU產(chǎn)生的波形數(shù)據(jù)片選信號(hào)cs1,這樣在每次一個(gè)地址單元的數(shù)據(jù)傳輸后,可以產(chǎn)生下一個(gè)單元的地址。2、該電路需要一個(gè)異步復(fù)位,以實(shí)現(xiàn)雙方地址的同步,MCU可以在每次開始一個(gè)新的波形數(shù)據(jù)傳輸之前,輸出該復(fù)位信號(hào),以實(shí)現(xiàn)MCU和AG1280之間的地址同步。
7)LED閃爍電路
LED閃爍電路并不是必須的,加上該電路是為了監(jiān)測(cè)系統(tǒng)時(shí)鐘是否正常工作。讀者可以根據(jù)實(shí)際情況自信選擇,代碼不再給出。
8)頂層例化文件
頂層例化文件用于連接上述各個(gè)模塊電路
1 module DDS_SPI_dualRAM(
2 input clk,
3 input nrst,
4 output led,
5 output samp_syc_sig,
6 output mosi,
7 output sck,
8 output cs,
9 //以下連接主機(jī)接收波形數(shù)據(jù)的SPI線
10 input sck_host,
11 input mosi_host,
12 input cs_host1,//主機(jī)輸出的第一個(gè)cs,用于選通和數(shù)據(jù)RAM通信
13 input cs_host2,//主機(jī)輸出的第而個(gè)cs,用于選通和DDS累加器增加值寄存器
14 //以下測(cè)試管腳
15 output test_pin
16 );
17 //wire samp_syc_sig;
18 wire[7:0] dds_addr;
19 wire[11:0] tab_data;
20 wire[15:0] delta_addr;
21 wire clk_25m;
22 assign test_pin = inc_addr_host[0];
23 //assign clk_25m = clk;
24 //////////////從板載20MHz有源振蕩通過(guò)PLL產(chǎn)生25MHz時(shí)鐘/////////
25 expll_2_25M i_ex_pll_25M(
26 .clkin(clk),
27 .clkfb(clk_25m),
28 .pllen(1'b1),
29 .resetn(nrst),
30 .clkout0en(1'b1),
31 .clkout1en(1'b0),
32 .clkout2en(1'b0),
33 .clkout3en(1'b0),
34 .clkout0(clk_25m),
35 .clkout1(),
36 .clkout2(),
37 .clkout3(),
38 .lock()
39 );
40 //////////////以下DAC側(cè)的電路描述/////////////
41 samp_syc_sig i_syc_sig(//產(chǎn)生DAC輸出的時(shí)鐘
42 .clk_25m(clk_25m),
43 .nrst(nrst),
44 .samp_syc_sig(samp_syc_sig)
45 );
46
47 run_led i_led(
48 .clk(clk_25m),
49 .nrst(nrst),
50 .led(led)
51 );
52 DAC7512 iDAC7512(
53 .clk_25m(clk_25m),
54 .nrst(nrst),
55 .syc_sig(samp_syc_sig),
56 .cs_da(cs),
57 .mosi_da(mosi),
58 .sck_da(sck),
59 .data_in(tab_data[11:0])
60 );
61 //////////////以下雙口RAM側(cè)的電路描述/////////////
62 wire[15:0] data_host;//從主機(jī)接收的數(shù)據(jù)的并行接口
63 wire[7:0] inc_addr_host;//連接到主機(jī)端存儲(chǔ)器端口的地址線,由計(jì)數(shù)器自動(dòng)產(chǎn)生
64 wire mosi_ram_host,mosi_DdsDelta_host,sck_ram_host,sck_DdsDelta_host;
65 wire[15:0] delta_val;
66 dualRAM_DATA i_dualRAM_DATA(
67 .Clk0(cs_host1),//用接收端串行接收選通信號(hào)作為存儲(chǔ)信號(hào)的時(shí)鐘
68 .Clk1(samp_syc_sig),
69 .ClkEn0(1'b1),
70 .ClkEn1(1'b1),//時(shí)鐘有效信號(hào),可以一直為高
71 .AsyncReset0(1'b0),//復(fù)位信號(hào),高有效,可以一直不復(fù)位
72 .AsyncReset1(1'b0),//復(fù)位信號(hào),高有效,可以一直不復(fù)位
73 .WeRenA(1'b1),//寫數(shù)據(jù)有效信號(hào),高有效
74 .ReB(1'b1 ), //端口1讀數(shù)據(jù)有效信號(hào),高有效
75 .DataInA(data_host[11:0]),//只使用接收數(shù)據(jù)的低12位
76 .AddressA(inc_addr_host[7:0]),
77 .AddressB(dds_addr[7:0]),
78 .DataOutB(tab_data[11:0])
79 );
80 //////////////以下主控MCU側(cè)的電路描述/////////////
81 mux_HostSpi i_mux_HostSpi(//數(shù)據(jù)多路器,用于選擇SPI口初始化的是RAM還是DDS累加地址
82 .mosi(mosi_host),
83 .sck(sck_host),
84 .cs1(cs_host1),
85 .cs2(cs_host2),
86 .mosi_ram(mosi_ram_host),
87 .mosi_DdsDelta(mosi_DdsDelta_host),
88 .sck_ram(sck_ram_host),
89 .sck_DdsDelta(sck_DdsDelta_host)
90 );
91 //以下移位寄存器用于通過(guò)CS1選通后接收主機(jī)發(fā)來(lái)的波形數(shù)據(jù)
92 shift_reg i_ram_shift_reg_host(
93 .mosi(mosi_ram_host),
94 .sck(sck_ram_host),
95 .nrst(nrst),//低電平復(fù)位
96 .ini_data(16'd0),
97 .data_out(data_host[15:0])
98 );
99 addr_generator i_addr_generator_host(//每次加一的方式遍歷所有地址
100 .clk(cs_host1),
101 .nrst(nrst),
102 .inc_addr(inc_addr_host[7:0])
103 );
104 //以下移位寄存器用于通過(guò)CS2選通后接收主機(jī)發(fā)來(lái)的地址累加值
105 shift_reg i_delta_shift_reg_host(
106 .mosi(mosi_DdsDelta_host),
107 .sck(sck_DdsDelta_host),
108 .nrst(nrst),//低電平復(fù)位
109 .ini_data(16'd328),//復(fù)位后的初始化為500Hz輸出
110 .data_out(delta_val[15:0])
111 );
112 addr_adder i_dds_addr_adder(//DDS算法產(chǎn)生下一個(gè)需要DAC數(shù)據(jù)數(shù)據(jù)的地址
113 .clk(samp_syc_sig),
114 .nrst(nrst),
115 .delta_addr(delta_val[15:0]),
116 .high_byte_addr(dds_addr[7:0])
117 );
118 endmodule
頂層例化電路
4、MCU軟件實(shí)現(xiàn)
MCU軟件通過(guò)SPI口完成波形數(shù)據(jù)和頻率控制字的下載。SPI應(yīng)配置為時(shí)鐘空閑時(shí)低電平(CPOL=0),第一個(gè)脈沖邊沿讀取數(shù)據(jù)(CPHA=0)的模式。此處不再給出MCU初始化代碼,僅給出下載波形表格和頻率控制字函數(shù)的代碼。
1 //配置波形函數(shù)
2 void set_wave(unsigned char wave_type)
3 //波形類型0:正弦;1:三角;2:墨西哥草帽
4 {
5 unsigned short i;
6 switch(wave_type)
7 {
8 case 0://選擇正弦波
9 for(i = 0; i<256 ; i++)
10 {
11 CS_wave_reg = 0;
12 SPIx_ReadWrite16bit(sin_tl[i]);
13 CS_wave_reg = 1;
14 delay_us(2);
15 }
16 break;
17 case 1://選擇三角波
18 for(i = 0; i<256 ; i++)
19 {
20 CS_wave_reg = 0;
21 SPIx_ReadWrite16bit(trg_tl[i]);
22 CS_wave_reg = 1;
23 delay_us(2);
24 }
25 break;
26 case 2://選擇墨西哥草帽小波基
27 for(i = 0; i<256 ; i++)
28 {
29 CS_wave_reg = 0;
30 SPIx_ReadWrite16bit(mexhat_tl[i]);
31 CS_wave_reg = 1;
32 delay_us(2);
33 }
34 break;
35 default:
36 break;
37 }
38 }
39
40 //配置頻率控制字函數(shù)
41 #define DAC_CLK 100000 //DAC的輸出頻率對(duì)DAC7512為100K
42 //設(shè)置輸出頻率
43 void set_frq(unsigned short frq)
44 //輸出頻率范圍必須在1-50_000Hz
45 {
46 unsigned short temp_short;
47 temp_short = (float)65536/DAC_CLK * frq + 0.5;//加0.5是為了消除舍棄誤差
48 CS_delta_reg = 0;//選通累加器增加值配置寄存器
49 SPIx_ReadWrite16bit(temp_short);
50 CS_delta_reg = 1;
51 }
MCU主機(jī)配置函數(shù)代碼
三、總結(jié)
1、實(shí)際測(cè)試
1)系統(tǒng)
下圖是本文使用國(guó)產(chǎn)CPLD器件AG1280設(shè)計(jì)的DDS系統(tǒng)。實(shí)驗(yàn)系統(tǒng)看起來(lái)有點(diǎn)丑,請(qǐng)大家海涵。
![pYYBAGMnuGuAeHvhAAIAL3vyjzs029.png](https://file.elecfans.com/web2/M00/6B/40/pYYBAGMnuGuAeHvhAAIAL3vyjzs029.png)
圖13 實(shí)際制作的DDS系統(tǒng)
2)功能實(shí)測(cè)
本文設(shè)計(jì)的DDS系統(tǒng)相比于ADI公司商業(yè)化的DDS芯片,最大的特點(diǎn)在于可以自己下載所需的波形,我測(cè)試了一個(gè)信號(hào)處理領(lǐng)域常用的小波基——墨西哥草帽小波基作。需要使用下面的MATLAB代碼產(chǎn)生所需的數(shù)據(jù)。
1 y = mexihat(-4,4,256);%調(diào)用matlab小波函數(shù)
2 %%%%以下代碼將浮點(diǎn)結(jié)果標(biāo)準(zhǔn)化為12位的DAC7512可以接收的數(shù)據(jù)
3 y = y - min(y);
4 y = y / max(y);
5 y=round(4000*y);
用STM32的SPI1口把上面MATLAB腳本產(chǎn)生的數(shù)據(jù)下發(fā)到AG1280中的DDS系統(tǒng)后得到頻率/周期可以調(diào)節(jié)的墨西哥草帽函數(shù)周期波形,用示波器觀察1.5KHz的波形如下圖所示。
![pYYBAGMnuLeAW8SNAARoT-4BnT0498.png](https://file.elecfans.com/web2/M00/6B/40/pYYBAGMnuLeAW8SNAARoT-4BnT0498.png)
圖14 用本DDS系統(tǒng)產(chǎn)生的頻率可調(diào)墨西哥草帽小波基函數(shù)
可以看到不論是頻率的準(zhǔn)確性,還是波形的完整性均達(dá)到了設(shè)計(jì)預(yù)期。
3)AG1280占用資源、功耗和上電運(yùn)行時(shí)間實(shí)測(cè)
本文設(shè)計(jì)的DDS系統(tǒng)占用AG1280資源如下:
![pYYBAGMnuNWAJhITAAAph_l5amM849.png](https://file.elecfans.com/web2/M00/6B/40/pYYBAGMnuNWAJhITAAAph_l5amM849.png)
圖15 AG1280資源占用情況
可以看到邏輯資源僅使用了10-20%,而存儲(chǔ)器資源僅使用了10%左右(當(dāng)然有可能隨著DDS波形表格增長(zhǎng)而變大)。可以想見AG1280的資源能夠滿足一般的MCU+FPGA的嵌入式系統(tǒng)需要。
另外,據(jù)實(shí)測(cè)本系統(tǒng)中的AG1280在25MHz工作頻率,PLL打開的情況下,功耗約為5mA左右。
本次測(cè)試中唯一讓我覺得意外的是AG1280的上電配置時(shí)間——可達(dá)100ms-300ms。仔細(xì)想來(lái)也可以理解:AG1280需要從其片上Flash中讀取程序,在配置到內(nèi)部的查找表中方能正常使用,肯定要比STM32一類直接在Flash中運(yùn)行程序的器件要慢。但在使用中就需要如果與STM32等MCU配合,在MCU上電后延時(shí)一段時(shí)間再和AG1280通信。
2、AG1280和Supra使用感慨
國(guó)產(chǎn)PLD器件一路走來(lái)不容易,雖然存在套用國(guó)外大廠EDA軟件,支持文檔不足,工具不夠?qū)I(yè)等等問題——但瑕不掩瑜,AG1280已經(jīng)具有相當(dāng)?shù)目捎眯院褪袌?chǎng)競(jìng)爭(zhēng)能力。
-
FPGA
+關(guān)注
關(guān)注
1630文章
21802瀏覽量
606412 -
mcu
+關(guān)注
關(guān)注
146文章
17358瀏覽量
352821 -
cpld
+關(guān)注
關(guān)注
32文章
1257瀏覽量
169666 -
SPI
+關(guān)注
關(guān)注
17文章
1724瀏覽量
92195
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
AGM Micro推出STM32兼容MCU產(chǎn)品系列
AGM Micro發(fā)布兼容STM32的MCU產(chǎn)品系列
國(guó)產(chǎn)FPGA開發(fā)經(jīng)驗(yàn)分享之初識(shí)AGM
國(guó)產(chǎn)FPGA,最新資料,推出的最新產(chǎn)品會(huì)及時(shí)更新,希望大家關(guān)注下,支持國(guó)產(chǎn)!
國(guó)產(chǎn)FPGA傲格芯AGM,分享大家的AGM FPGA的技術(shù)資料
學(xué)習(xí) AGM 與FPGA快速入門
AGM FPGA 快速入門手冊(cè)
什么是AGM電池?
AGM國(guó)產(chǎn)高端FPGA系列產(chǎn)品線發(fā)布,國(guó)產(chǎn)FPGA芯片市場(chǎng)再進(jìn)一步
國(guó)產(chǎn)AGM FPGA設(shè)計(jì)流程的詳細(xì)介紹
![<b class='flag-5'>國(guó)產(chǎn)</b><b class='flag-5'>AGM</b> FPGA設(shè)計(jì)流程的詳細(xì)介紹](https://file.elecfans.com/web2/M00/03/23/poYBAGDUjpeAZoMNAAA4TBhi4K0901.jpg)
AGM CPLD數(shù)據(jù)手冊(cè)
國(guó)產(chǎn)CPLD:AG1280Q48 替代Altera EPM1270
![<b class='flag-5'>國(guó)產(chǎn)</b><b class='flag-5'>CPLD</b>:AG<b class='flag-5'>1280</b>Q48 替代Altera EPM1270](https://file.elecfans.com/web2/M00/18/F6/pYYBAGFyVuSAMzSMAAFjwzg_URo256.png)
AGM32 MCU規(guī)格書-國(guó)產(chǎn)AGM MCU直接替換 STMcu、GDMcu
AGM CPLD 應(yīng)用指南
![<b class='flag-5'>AGM</b> <b class='flag-5'>CPLD</b> 應(yīng)用指南](https://file1.elecfans.com/web2/M00/BB/CF/wKgZomWd8j2AE9QeAACLVev3upk582.png)
評(píng)論