新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > FPGA:數(shù)字示波器 1 - 首款設(shè)計(jì)

        FPGA:數(shù)字示波器 1 - 首款設(shè)計(jì)

        作者: 時(shí)間:2024-01-12 來源:EEPW編譯 收藏

        以下是此處構(gòu)建的內(nèi)容:

        本文引用地址:http://www.104case.com/article/202401/454716.htm

        接收兩個時(shí)鐘:

        • 一個緩慢的“系統(tǒng)”時(shí)鐘,固定在25MHz。

        • ADC采樣時(shí)鐘(更快,假設(shè)100MHz),連接到ADC和

        擁有這兩個時(shí)鐘為設(shè)計(jì)提供了靈活性。 但這也意味著我們需要一種方法將信息從一個時(shí)鐘域傳輸?shù)搅硪粋€時(shí)鐘域。 為了驗(yàn)證硬件是否正常工作,讓我們走一條簡單的路線,使用FIFO。 從ADC采集的樣本以全ADC速度(100MHz)存儲在 FIFO中。

        然后,F(xiàn)IFO內(nèi)容被讀回、序列化,并以更慢的速度(115200波特)在串行端口上發(fā)送。 最后,我們將串行輸出連接到接收每個字節(jié)并顯示信號跡線的 PC。

        對于第一次嘗試,沒有跟蹤觸發(fā)機(jī)制。 ADC存儲以隨機(jī)間隔啟動,因此跡線將左右跳轉(zhuǎn),但目前還好。

        設(shè)計(jì)注意事項(xiàng)

        在100MHz頻率下,F(xiàn)IFO在大約10us內(nèi)充滿。 這是相當(dāng)快的。 一旦吃飽了,我們就必須停止喂食。 存儲的內(nèi)容需要完全發(fā)送到 PC,然后才能再次開始饋送 FIFO。

        這里使用的串行通信工作在 115200 波特,因此大約為 10KB/s。 1024 個樣本傳輸大約需要 100 毫秒。 在此期間,示波器是“盲”的,因?yàn)槲覀儊G棄了來自ADC的數(shù)據(jù)。 所以它在 99.99% 的時(shí)間里是盲目的。 這是此類體系結(jié)構(gòu)的典型特征。

        當(dāng)我們稍后添加觸發(fā)機(jī)制時(shí),這可以部分補(bǔ)償,因?yàn)楫?dāng)觸發(fā)器處于布防狀態(tài)時(shí),它會以全ADC速度工作,并且只要觸發(fā)條件發(fā)生,它就可以保持布防狀態(tài)。 稍后會詳細(xì)介紹。

        注冊輸入

        ADC輸出數(shù)據(jù)總線使用8個引腳連接到FPGA,我們稱之為“data_flash[7:0]”。 這些產(chǎn)品的速度高達(dá)100MHz。 由于速度很快,因此最好在它們進(jìn)入 FPGA 時(shí)立即“注冊”它們。

        reg [7:0] data_flash_reg;
        always @(posedge clk_flash) data_flash_reg <= data_flash;

        現(xiàn)在,“data_flash_reg”完全位于FPGA內(nèi)部,可以饋送到FPGA FIFO。

        先進(jìn)先出

        FIFO 為 1024 字深 x 8 位寬。 由于我們每個時(shí)鐘從ADC接收8位,因此我們可以存儲1024個ADC樣本。 在100MHz時(shí),填滿FIFO大約需要10us。

        FIFO使用FPGA內(nèi)部提供的同步靜態(tài)RAM模塊。 每個存儲塊通常可以存儲 512x8 位。因此,F(xiàn)IFO 使用 2 個塊。
        FIFO邏輯本身是使用FPGA供應(yīng)商的“函數(shù)生成器”創(chuàng)建的。 Xilinx 稱其為“coregen”,而 Altera 則稱其

        “Megafunctions wizard”。在這里,讓我們使用 Altera 的 Quartus 來創(chuàng)建這個文件。
        所以現(xiàn)在,使用FIFO只是一個連接問題。

        fifo myfifo(.data(data_flash_reg), .wrreq(wrreq), .wrclk(clk_flash), .wrfull(wrfull), .wrempty(wrempty), .q(q_fifo), .rdreq(rdreq), .rdclk(clk), .rdempty(rdempty));

        使用FIFO很好,因?yàn)樗梢蕴幚聿煌臅r(shí)鐘。 我們將FIFO的寫入側(cè)連接到“clk_flash”(100MHz),將FIFO的讀取側(cè)連接到“clk”(25MHz)。

        FIFO為每個時(shí)鐘域提供完整和空信號。 例如,“wrempty”是可以在寫入時(shí)鐘域(“clk_flash”)中使用的空信號,“rdempty”可以在讀取時(shí)鐘域(“clk”)中使用。

        使用FIFO很簡單:寫入它只需斷言“wrreq”信號(并將數(shù)據(jù)提供給“.data”端口),同時(shí)從中讀取斷言“rdreq”(數(shù)據(jù)來自“.q”端口)。

        寫入 FIFO

        要開始寫入 FIFO,我們等到它為空。 當(dāng)然,在上電時(shí)(配置FPGA之后),這是真的。
        只有當(dāng)它滿了時(shí),我們才會停下來。 然后這個過程又開始了......我們等到它是空的......喂它直到它吃飽為止......停。

        reg fillfifo;
        always @(posedge clk_flash)
        if(~fillfifo)
          fillfifo <= wrempty; // start when empty
        else
          fillfifo <= ~wrfull; // stop when full

        assign wrreq = fillfifo;

        讀取到FIFO

        我們從FIFO讀取,只要它不是空的。每個字節(jié)讀取都發(fā)送到串行輸出。

        wire TxD_start = ~TxD_busy & ~rdempty;
        assign rdreq = TxD_start;

        async_transmitter async_txd(.clk(clk), .TxD(TxD), .TxD_start(TxD_start), .TxD_busy(TxD_busy), .TxD_data(q_fifo));

        我們使用 async_transmitter 模塊對數(shù)據(jù)進(jìn)行序列化,并將其傳輸?shù)揭粋€名為“TxD”的引腳。

        完整的設(shè)計(jì)

        我們的第一個工作示波器設(shè)計(jì),不是很好嗎?

        module oscillo(clk, TxD, clk_flash, data_flash);
        input clk;
        output TxD;

        input clk_flash;
        input [7:0] data_flash;

        reg [7:0] data_flash_reg; always @(posedge clk_flash) data_flash_reg <= data_flash;

        wire [7:0] q_fifo;
        fifo myfifo(.data(data_flash_reg), .wrreq(wrreq), .wrclk(clk_flash), .wrfull(wrfull), .wrempty(wrempty), .q(q_fifo), .rdreq(rdreq), .rdclk(clk), .rdempty(rdempty));

        // The flash ADC side starts filling the fifo only when it is completely empty,
        // and stops when it is full, and then waits until it is completely empty again
        reg fillfifo;
        always @(posedge clk_flash)
        if(~fillfifo)
          fillfifo <= wrempty; // start when empty
        else
          fillfifo <= ~wrfull; // stop when full

        assign wrreq = fillfifo;

        // the manager side sends when the fifo is not empty
        wire TxD_busy;
        wire TxD_start = ~TxD_busy & ~rdempty;
        assign rdreq = TxD_start;

        async_transmitter async_txd(.clk(clk), .TxD(TxD), .TxD_start(TxD_start), .TxD_busy(TxD_busy), .TxD_data(q_fifo));

        endmodule




        關(guān)鍵詞: FPGA 數(shù)字示波器

        評論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 绥滨县| 武邑县| 石狮市| 万州区| 宜兴市| 阿勒泰市| 武强县| 哈尔滨市| 冕宁县| 舞阳县| 冀州市| 宁波市| 平江县| 济源市| 内乡县| 微山县| 牙克石市| 北票市| 阿图什市| 余庆县| 清丰县| 桦南县| 九台市| 拉孜县| 潮安县| 杨浦区| 西乡县| 潜江市| 花垣县| 肃宁县| 许昌县| 甘德县| 黄冈市| 桑日县| 阜宁县| 河南省| 望城县| 南岸区| 东源县| 婺源县| 荣成市|