贏一個雙肩背包 有多難? 戳一下試試看,! →_→ 【主題】:詳細(xì)解析基于FPGA的任意分頻 【作者】:LinCoding 【時間】:2016.11.28 對于FPGA而言,,分頻極其重要,,不多說,,直接看程序,。 (源碼出自CrazyBingo,,尊重版權(quán)) module precise_divider #( //DIVIDER_CNT = 42.94967296(100Mhz) × fo parameter DIVIDER_CNT = 32'd6597070 //9600 × 16 (100Mhz) // parameter DIVIDER_CNT = 32'd79164837 //115200 × 16 (100Mhz) ) ( input clk, //global clock input rst_n, //global reset output divide_clk, output divide_clken ); 第一部分是輸入輸出定義,,要注意的是使用了parameter的用法,,這樣可以在頂層隨意改動參數(shù)以適合所需設(shè)定的頻率,這里的參數(shù)指的是步長,,具體解釋如下: 首先,,如果系統(tǒng)時鐘是100Mhz,且數(shù)據(jù)位寬是32位的話,,用232去量化100Mhz,,100Mhz/232≈0.023283hz,這就意味著,,如果數(shù)據(jù)位寬是32位寬,,以步長為1去計數(shù),,每記1個數(shù)所對應(yīng)的頻率約為0.023283hz,也就意味著,,這樣去分頻的話,,輸出時鐘的精度可以達(dá)到0.023283hz,如果我們要設(shè)定(9600*16)hz,,則計數(shù)的步長就是:(9600*16)hz/0.023283hz=6597088,,當(dāng)然了,由于我在計算0.023283時用了約等,,所以這里所算的數(shù)不準(zhǔn)確,,其實(shí)我們可以直接來算:(9600*16)hz/(100Mhz/232)=(9600*16)hz*42.94967296≈6597070,,這樣就準(zhǔn)確多了,,也就是程序中注釋的公式。(從原理可知,,這個方案所能達(dá)到的精度很高,,但是所能得到的頻率最高為100Mhz/2=50Mhz了,比如你想得到60.25Mhz,,這個方案是不可以的) //----------------------------------- //counter reg [31:0] cnt; always @ ( posedge clk or negedge rst_n ) begin if ( ! rst_n ) cnt <= 32'd0; else cnt <= cnt + DIVIDER_CNT; end 第二部分就是計數(shù)器了,,計數(shù)器位寬為32位寬,步長為以parameter定義的為準(zhǔn),。這樣的話,,每計滿232就自己歸零了。 第三部分是與232/2比較,,以輸出占空比為%50的方波,。32'h7FFF_FFFF就是232/2 第四部分就是輸出分頻后的時鐘和使能時鐘了。這里有一點(diǎn)需要注意,。 既然我們需要的是分頻后的時鐘,,可為什么還需要divide_clken這個使能時鐘呢?答案是FPGA不允許除全局時鐘以外的時鐘作為系統(tǒng)的驅(qū)動信號,,也就是我們常常寫的 always @ ( posedge clk or negedge rst_n ),,這里的clk要么是全局時鐘,要么是PLL生成的時鐘,,最好不要用計數(shù)器生成的時鐘,,那么,計數(shù)器分頻得到的時鐘就需要一個使能時鐘(使能信號)了,,我們可以這樣來用: 這樣就OK了,,因此我們需要在輸出時鐘的時候加一個輸出時鐘使能信號以供其它模塊使用。所以,,上述代碼采用了一級D觸發(fā)器打一拍,,然后捕獲了輸出時鐘的上升沿作為使能時鐘以供其它模塊使用,! 最后輸出divide_clk信號觀察,可見9600hz*16=153600hz=153.6Khz,,與設(shè)定完全一致,,且精度很高!
|
|