計(jì)實(shí)戰(zhàn):FPGA IP核配置與仿真全解析)
寫多通道FIR濾波器很多人一開始就被“多通道”三個(gè)字嚇住了。其實(shí)說穿了就是把好幾路信號(hào)同時(shí)丟進(jìn)同一個(gè)濾波器讓它們?cè)谕粋€(gè)FPGA工程里各自完成濾波任務(wù)。我在剛開始用Xilinx FIR IP核的時(shí)候也是抱著數(shù)據(jù)手冊(cè)啃了三天最后發(fā)現(xiàn)真正難的不是IP核本身而是對(duì)通道、時(shí)鐘、數(shù)據(jù)排列的理解。這篇文章就按我自己的上手路徑來(lái)寫從需求分析講到參數(shù)配置再到仿真驗(yàn)證和常見坑位排查盡量讓一個(gè)之前完全沒碰過FIR IP核的讀者也能把多通道濾波器跑起來(lái)。1. 動(dòng)手之前先把多通道FIR的賬算清楚1.1 多通道FIR要解決什么問題FIR濾波器就是有限脈沖響應(yīng)濾波器它對(duì)輸入信號(hào)做加權(quán)求和每個(gè)輸出點(diǎn)等于最近N個(gè)輸入點(diǎn)與N個(gè)濾波器系數(shù)的乘積之和。這個(gè)N就是抽頭數(shù)也叫Taps。FIR因?yàn)榫€性相位特性好、結(jié)構(gòu)穩(wěn)定在通信、音頻、雷達(dá)、生物電信號(hào)處理里幾乎是繞不開的基礎(chǔ)模塊。那“多通道”是什么場(chǎng)景呢。最典型的是多通道音頻比如一個(gè)48kHz采樣率的音頻系統(tǒng)同時(shí)處理8路甚至32路聲道每路都要過均衡或分頻濾波器。還有多通道振動(dòng)監(jiān)測(cè)幾十個(gè)加速度傳感器同時(shí)采數(shù)據(jù)每個(gè)通道要實(shí)時(shí)濾除工頻干擾。雷達(dá)和聲吶里更常見幾十上百個(gè)陣元通道每個(gè)通道都要做匹配濾波或波束形成的預(yù)處理。這些場(chǎng)景下如果你給每個(gè)通道都例化一個(gè)獨(dú)立的FIR模塊資源很快就爆了。正確做法是復(fù)用一個(gè)濾波計(jì)算單元通過時(shí)分復(fù)用的方式挨個(gè)處理每個(gè)通道的數(shù)據(jù)這正是Xilinx FIR Compiler IP核多通道模式的核心思想。1.2 三種實(shí)現(xiàn)路線對(duì)比與選型實(shí)現(xiàn)多通道FIR大致有三條路純手寫Verilog、用FIR Compiler IP核、用Vitis HLS做高層次綜合。純手寫Verilog的優(yōu)點(diǎn)是可控性最強(qiáng)想怎么優(yōu)化就怎么優(yōu)化但缺點(diǎn)也明顯FIR涉及到延遲線、系數(shù)存儲(chǔ)、乘法累加器、多通道狀態(tài)管理寫起來(lái)繁瑣不說時(shí)序優(yōu)化全靠經(jīng)驗(yàn)。多通道模式下還要自己設(shè)計(jì)通道輪詢邏輯忙活一個(gè)星期寫出來(lái)的代碼性能和穩(wěn)定性還不一定比得上IP核。用Vitis HLS的優(yōu)點(diǎn)是開發(fā)效率高用C/C描述濾波器算法并且很容易做定點(diǎn)化仿真。但HLS生成的RTL代碼在資源利用率和時(shí)序收斂上有時(shí)不如手工優(yōu)化的IP核而且多通道高吞吐場(chǎng)景下HLS默認(rèn)生成的流水線結(jié)構(gòu)也需要反復(fù)調(diào)pragma才能達(dá)到預(yù)期性能。FIR Compiler IP核則是Xilinx專門針對(duì)FIR濾波優(yōu)化過的硬核IP它內(nèi)部使用DSP48硬核資源做乘加運(yùn)算支持靈活的通道數(shù)、多相結(jié)構(gòu)、可配置的系數(shù)重載還能自動(dòng)處理飽和與舍入。對(duì)絕大多數(shù)量產(chǎn)項(xiàng)目來(lái)說這是性價(jià)比最高的選擇。我自己的項(xiàng)目基本都選IP核只有做ASIC驗(yàn)證的原型RTL才會(huì)考慮手寫FIR因?yàn)槟翘状a后續(xù)要移植到其他工藝庫(kù)IP核的RTL沒法直接用。1.3 核心公式與參數(shù)預(yù)算多通道FIR設(shè)計(jì)里最關(guān)鍵的一個(gè)公式是數(shù)據(jù)率預(yù)算。假設(shè)單通道采樣率為Fs通道數(shù)為Nch那么IP核輸入端的數(shù)據(jù)率就是Nch × Fs。以48kHz采樣、32通道為例輸入數(shù)據(jù)率就是1.536MHz也就是每秒鐘要送入153.6萬(wàn)個(gè)采樣點(diǎn)。如果你的主時(shí)鐘是100MHz那每個(gè)采樣點(diǎn)對(duì)應(yīng)大約65個(gè)時(shí)鐘周期這個(gè)余量非常充足IP核內(nèi)部的乘加單元完全忙得過來(lái)。但如果你處理的是高速ADC數(shù)據(jù)比如250MSPS采樣率、8通道并行采集那輸入數(shù)據(jù)率就高達(dá)2GSPS100MHz主時(shí)鐘根本扛不住這時(shí)必須讓多通道數(shù)據(jù)在更高時(shí)鐘域下并行輸入。FIR Compiler里有一個(gè)概念叫硬件過采樣率Hardware Oversampling Ratio簡(jiǎn)稱HIL公式是HIL Fclk / (Nch × Fs)它表示每處理一個(gè)通道采樣點(diǎn)有多少個(gè)時(shí)鐘周期可用。IP核會(huì)依據(jù)這個(gè)數(shù)值自動(dòng)決定內(nèi)部是單MAC串行結(jié)構(gòu)還是多MAC并行結(jié)構(gòu)。HIL越大需要的DSP48越少HIL小于抽頭數(shù)時(shí)IP核會(huì)復(fù)制乘法器來(lái)保證每個(gè)周期能完成足夠的乘加運(yùn)算。所以在配置IP核之前先把這個(gè)賬算清楚主時(shí)鐘、采樣率、通道數(shù)、抽頭數(shù)四個(gè)數(shù)一擺資源量級(jí)和時(shí)鐘可行性大概就有數(shù)了。這也決定了后面IP核配置界面里幾個(gè)關(guān)鍵參數(shù)該填什么。2. FIR Compiler IP核參數(shù)配置詳解2.1 濾波器類型與系數(shù)加載在Vivado里打開IP Catalog搜索“FIR Compiler”雙擊進(jìn)入配置界面。第一步是選擇濾波器類型最常見的是Single Rate也就是輸入輸出速率相同適合大多數(shù)普通濾波場(chǎng)景。如果你的系統(tǒng)里需要改變采樣率比如先把信號(hào)從48kHz插值到96kHz那就選Interpolation如果要從96kHz抽取到48kHz選Decimation。選抽取或插值之后IP核會(huì)自動(dòng)把濾波器按多相結(jié)構(gòu)展開這并不需要你自己手寫任何多相分解邏輯。我記得第一次看到這個(gè)功能時(shí)還挺意外后來(lái)仔細(xì)看文檔才發(fā)現(xiàn)多相濾波在硬件上就是原型濾波器系數(shù)按相位重新分組FIR Compiler把這個(gè)工作完全自動(dòng)化了。接下來(lái)是濾波器系數(shù)。配置界面里有兩種加載方式一種是直接在Coefficient Vector表格里手動(dòng)填數(shù)值適合調(diào)試時(shí)隨便填幾個(gè)系數(shù)驗(yàn)證通路另一種是加載外部coe文件適合從MATLAB或Python算好系數(shù)后導(dǎo)進(jìn)來(lái)。我強(qiáng)烈建議用coe文件因?yàn)槭痔钕禂?shù)很容易填錯(cuò)位而且后期修改濾波器指標(biāo)時(shí)直接改文件重新生成IP核就行。coe文件的格式有嚴(yán)格要求我再三提醒身邊同事文件第一行通常是注釋用分號(hào)開頭然后指定radix和coefficient_width最后是coefdata后面跟一串系數(shù)系數(shù)之間用逗號(hào)分隔整個(gè)文件以分號(hào)結(jié)尾。radix支持2、10、16比如radix16就是十六進(jìn)制radix10就是十進(jìn)制。很多人第一次寫coe文件忘記末尾分號(hào)導(dǎo)致IP核加載失敗這個(gè)錯(cuò)誤很低級(jí)但真的一搜一大把。2.2 多通道數(shù)據(jù)接口與時(shí)序解析多通道配置的核心參數(shù)是Number of Channels和Input Sample Frequency。你填了通道數(shù)之后IP核會(huì)自動(dòng)計(jì)算輸出數(shù)據(jù)率并顯示在Summary里。很多新手看到數(shù)據(jù)接口只有一組AXI4-Stream輸入輸出就會(huì)疑惑多通道的數(shù)據(jù)怎么塞進(jìn)一根總線答案就是時(shí)分復(fù)用。在相鄰兩個(gè)采樣周期之間tvalid拉高的那一段時(shí)間里每個(gè)時(shí)鐘周期送一個(gè)通道的數(shù)據(jù)按通道0、通道1、通道2……順序依次排隊(duì)進(jìn)入IP核。假設(shè)配置了4通道、每通道數(shù)據(jù)位寬16bit那么tdata總線位寬就是16bit不是64bit。輸入側(cè)需要用計(jì)數(shù)器控制多路選擇器在每個(gè)采樣周期內(nèi)把4個(gè)通道的數(shù)據(jù)按順序送上總線。輸出側(cè)同理tvalid有效后會(huì)按順序依次吐出通道0到通道3的濾波結(jié)果。有的Vivado版本里Data Interface可以選Independent Bus模式那時(shí)tdata位寬會(huì)變成Nch×16bit總線上不同位段對(duì)應(yīng)不同通道數(shù)據(jù)并行送入這個(gè)模式適合輸入數(shù)據(jù)率很高、要求并行輸入的場(chǎng)合。具體選哪種看你系統(tǒng)架構(gòu)是并行還是串行采樣。時(shí)序上最容易出問題的點(diǎn)在于tready。AXI4-Stream協(xié)議有握手機(jī)制只有當(dāng)tvalid和tready同時(shí)為高時(shí)數(shù)據(jù)才算真正被接受。FIR Compiler在內(nèi)部處理不過來(lái)時(shí)會(huì)拉低tready進(jìn)行反壓如果你的上游邏輯無(wú)視tready硬往里面塞數(shù)據(jù)那就會(huì)丟數(shù)據(jù)。多通道模式下丟一個(gè)數(shù)據(jù)后果是整個(gè)通道序列從此錯(cuò)位濾波結(jié)果一塌糊涂而且非常難查。所以寫外部邏輯時(shí)務(wù)必把tready納入使能條件。2.3 多相濾波與抽取插值實(shí)現(xiàn)既然聊到多相濾波就稍微展開一點(diǎn)。FIR濾波器每輸出一個(gè)點(diǎn)要做N次乘加如果先濾波再抽取M點(diǎn)意味著有M-1個(gè)計(jì)算結(jié)果本來(lái)就該丟掉白白浪費(fèi)了計(jì)算量。多相分解的思路是把長(zhǎng)度為N的原型濾波器系數(shù)重新排列成M個(gè)子濾波器每個(gè)子濾波器只保留每隔M個(gè)取一個(gè)的系數(shù)。濾波時(shí)輸入信號(hào)按M倍抽取分別進(jìn)入對(duì)應(yīng)子濾波器每個(gè)子濾波器的計(jì)算結(jié)果直接就是抽取后的輸出計(jì)算量從N次乘加降為N/M次乘加省了整整數(shù)倍。FIR Compiler在處理Decimation和Interpolation配置時(shí)內(nèi)部就是按照多相結(jié)構(gòu)來(lái)例化資源。你在配置界面上看到的選項(xiàng)只是抽取倍數(shù)或插值倍數(shù)背后的系數(shù)重排和相位選擇全被IP核吞掉了。所以如果你在工程里看到別人說“用Vivado FIR核做多相濾波”他大概率說的就是用這種抽取/插值模式而不是自己去寫多相分解代碼。有一點(diǎn)要留意抽取模式下輸出數(shù)據(jù)的速率是Fs/M下游模塊的時(shí)鐘和有效信號(hào)要按這個(gè)速率來(lái)設(shè)計(jì)否則會(huì)出現(xiàn)數(shù)據(jù)斷續(xù)。2.4 數(shù)據(jù)位寬、量化與飽和機(jī)制位寬是另一個(gè)決定成敗的細(xì)節(jié)。FIR IP核有兩個(gè)輸入端位寬要設(shè)置輸入數(shù)據(jù)位寬和系數(shù)位寬。常見的配置是輸入16bit、系數(shù)16bit輸出位寬則可以自己選。理想的輸出位寬應(yīng)該等于輸入位寬加系數(shù)位寬再加log2(Nch×Taps)這么一位余量這樣才不會(huì)有溢出的風(fēng)險(xiǎn)。但工程上輸出位寬往往不能無(wú)限大后面還有模塊要用這個(gè)數(shù)據(jù)。于是IP核提供了多種量化模式Full Precision、Truncate LSBs、Non Convergent Rounding、Convergent Rounding等以及飽和模式Saturate和Wraparound。Full Precision最安全輸出位寬很寬不會(huì)丟失信息但位寬會(huì)大到下游難以接受。Truncate LSBs最簡(jiǎn)單粗暴直接砍掉低位會(huì)引入直流偏置和量化噪聲。Convergent Rounding是四舍五入到偶數(shù)統(tǒng)計(jì)特性比單純截?cái)嗪迷诟呔葓?chǎng)景里更推薦。飽和模式則決定數(shù)據(jù)超出范圍時(shí)是鉗位到最大值還是按二進(jìn)制自然回繞。對(duì)音頻信號(hào)回繞會(huì)產(chǎn)生刺耳的爆音所以一般選Saturate對(duì)通信基帶信號(hào)有時(shí)為了算法分析方便反而選Wraparound避免飽和引入非線性。這些參數(shù)沒有絕對(duì)的對(duì)錯(cuò)完全取決于后續(xù)模塊想看到什么樣的數(shù)據(jù)。我的建議是先用Full Precision摸清真實(shí)動(dòng)態(tài)范圍再根據(jù)實(shí)測(cè)波形決定是否截?cái)嗪惋柡筒灰簧蟻?lái)就憑感覺設(shè)。3. 完整實(shí)操?gòu)膭?chuàng)建工程到仿真波形全綠3.1 用Python生成系數(shù)并導(dǎo)出coe文件系數(shù)設(shè)計(jì)推薦用Python的scipy或MATLAB。我用Python比較多就以Python為例。假設(shè)需求是48kHz采樣、128階低通、截止頻率8kHz、Hamming窗那代碼大致長(zhǎng)這樣from scipy.signal import firwin import numpy as np fs 48000.0 cutoff 8000.0 numtaps 128 b firwin(numtaps, cutoff, fsfs, windowhamming) # 歸一化到16bit有符號(hào)定點(diǎn)數(shù) Q 15 b_scaled np.round(b * (2**Q - 1)) b_int b_scaled.astype(np.int16) # 導(dǎo)出Xilinx coe文件十六進(jìn)制補(bǔ)碼格式 with open(fir_lpf.coe, w) as f: f.write(; Xilinx FIR Compiler coefficient file\n) f.write(radix16;\n) f.write(coefficient_width16;\n) f.write(coefdata\n) for i, c in enumerate(b_int): if c 0: hex_str format(c 0xFFFF, 04X) else: hex_str format(c, 04X) if i len(b_int) - 1: f.write(hex_str ,\n) else: f.write(hex_str ;\n)注意負(fù)數(shù)要按補(bǔ)碼格式寫入也就是c與0xFFFF做按位與。生成完成后可以用一個(gè)簡(jiǎn)單的正弦疊加信號(hào)去驗(yàn)證系數(shù)設(shè)計(jì)是否滿足指標(biāo)直接在Python里調(diào)用np.convolve對(duì)比濾波前后的頻譜即可。3.2 Vivado中配置并例化FIR Compiler在Vivado IP Catalog里搜索FIR Compiler打開后按以下步驟配置Filter Options頁(yè)里把Filter Type選為Single RateNumber of Channels填實(shí)際通道數(shù)比如4。Sample Rate填每通道的采樣頻率比如48000Hz。在Coefficient File里加載剛才生成的fir_lpf.coe確認(rèn)一下抽頭數(shù)自動(dòng)識(shí)別為128。如果系數(shù)文件格式有問題這里會(huì)報(bào)錯(cuò)或者顯示0個(gè)系數(shù)看到這種情況先回頭檢查文件末尾分號(hào)和小數(shù)點(diǎn)格式。Implementation Details頁(yè)里設(shè)置輸入數(shù)據(jù)位寬16bit、有符號(hào)數(shù)系數(shù)位寬16bit量化模式選Convergent Rounding飽和模式選Saturate。輸出位寬可以暫時(shí)保持自動(dòng)計(jì)算的結(jié)果。時(shí)鐘頻率默認(rèn)按Vivado工程的約束自動(dòng)推斷也可以手動(dòng)填一個(gè)期望值比如100MHz。配置完成后點(diǎn)擊OK在IP Sources里選中這個(gè)IP核右鍵選擇Generate Output Products等綜合生成完成后再打開Instantiation Template就能看到標(biāo)準(zhǔn)的例化模板。多通道模式下例化代碼并不復(fù)雜我用的最多的是AXI4-Stream接口fir_compiler_0 u_fir ( .aclk (clk), .s_axis_data_tvalid (s_axis_tvalid), .s_axis_data_tready (s_axis_tready), .s_axis_data_tdata (s_axis_tdata), .m_axis_data_tvalid (m_axis_tvalid), .m_axis_data_tdata (m_axis_tdata) );如果你的IP核版本支持獨(dú)立總線模式的輸入接口接口信號(hào)會(huì)根據(jù)配置生成多組數(shù)據(jù)位段這時(shí)候例化模板的位寬定義會(huì)差很多所以每次生成完IP核之后務(wù)必先看例化模板再連線。3.3 Testbench設(shè)計(jì)與多通道激勵(lì)生成Testbench的要點(diǎn)是嚴(yán)格按照AXI4-Stream握手時(shí)序產(chǎn)生多通道數(shù)據(jù)。采樣周期用周期信號(hào)表示每個(gè)采樣周期內(nèi)產(chǎn)生Nch個(gè)通道數(shù)據(jù)。下面是一個(gè)4通道16bit數(shù)據(jù)的Testbench片段timescale 1ns / 1ps module tb_fir; reg clk; reg rst_n; reg [15:0] ch_data [0:3]; reg [3:0] ch_index; reg sample_pulse; wire s_axis_tvalid; wire s_axis_tready; wire [15:0] s_axis_tdata; wire m_axis_tvalid; wire [15:0] m_axis_tdata; // 采樣脈沖每100個(gè)時(shí)鐘產(chǎn)生一次 always (posedge clk) begin if (sample_counter 99) begin sample_pulse 1b1; sample_counter 0; end else begin sample_pulse 1b0; sample_counter sample_counter 1; end end // 在每個(gè)采樣脈沖后的4個(gè)時(shí)鐘依次送4個(gè)通道數(shù)據(jù) always (posedge clk or negedge rst_n) begin if (!rst_n) begin ch_index 0; end else if (sample_pulse) begin ch_index 0; end else if (s_axis_tvalid s_axis_tready) begin if (ch_index 3) ch_index 0; else ch_index ch_index 1; end end assign s_axis_tvalid (sample_pulse || ch_index ! 0) !ch_done; assign s_axis_tdata ch_data[ch_index]; endmodule這里我把每個(gè)通道的激勵(lì)預(yù)存到一個(gè)數(shù)組里實(shí)際工程中可以從ROM讀取數(shù)據(jù)文件也可以直接生成正弦波掃頻信號(hào)。仿真的第一個(gè)目標(biāo)不是看頻譜而是看通路是否打通。首選驗(yàn)證方法是沖激響應(yīng)法給通道0送一個(gè)單位沖激其余通道送0觀察輸出波形是否和coe文件中的系數(shù)完全一致。如果輸出序列和系數(shù)一一對(duì)應(yīng)說明通路沒問題。然后再給每個(gè)通道分別送沖激就能確認(rèn)通道之間沒有串?dāng)_。3.4 結(jié)果對(duì)比與延遲校準(zhǔn)FIR濾波器是有固定群延遲的。對(duì)一個(gè)N階線性相位FIR群延遲是(N-1)/2個(gè)采樣周期。用128抽頭系數(shù)時(shí)輸出相對(duì)輸入延遲63.5個(gè)采樣點(diǎn)這就是為什么仿真里拿輸入正弦和輸出正弦直接對(duì)比相位會(huì)對(duì)不上。多通道模式下這個(gè)延遲對(duì)每個(gè)通道都是一樣的所以通道間相對(duì)延遲是0。驗(yàn)證濾波結(jié)果是否正確的標(biāo)準(zhǔn)做法是把輸入激勵(lì)數(shù)據(jù)存成txt文件在Python或MATLAB里用相同系數(shù)做一次定點(diǎn)仿真然后把Vivado仿真導(dǎo)出的輸出數(shù)據(jù)與軟件仿真的結(jié)果做逐點(diǎn)對(duì)比。允許的誤差只有舍入造成的1到2個(gè)LSB。如果誤差偏大先檢查IP核的量化模式是否與軟件模型一致再看看輸入數(shù)據(jù)是否無(wú)意中經(jīng)過了符號(hào)位擴(kuò)展。實(shí)測(cè)中我發(fā)現(xiàn)很多對(duì)不上的情況都出在Testbench里數(shù)據(jù)位寬沒有擴(kuò)展到16bit符號(hào)位就接到了tdata總線上。4. 高頻問題排查與優(yōu)化實(shí)錄4.1 多通道FIR常見問題速查表我把實(shí)際項(xiàng)目中踩過的坑和同行常問的問題整理成一張表方便直接按圖索驥。現(xiàn)象可能原因排查方式處理建議輸出一直是0系數(shù)文件沒有正確加載或tvalid從未拉高檢查IP核Summary里的Taps數(shù)量仿真里看s_axis_tvalid是否按采樣周期脈沖確認(rèn)coe文件路徑和格式改用手動(dòng)填系數(shù)驗(yàn)證通路輸出波形放大或縮小系數(shù)量化后增益偏移或截?cái)嗄J揭胫绷鲗?duì)比coe文件系數(shù)和設(shè)計(jì)系數(shù)的增益系數(shù)歸一化時(shí)留足余量輸出端做增益補(bǔ)償通道間數(shù)據(jù)錯(cuò)位輸入數(shù)據(jù)沒有嚴(yán)格按通道順序排列用通道0單位沖激檢查輸出對(duì)應(yīng)關(guān)系重寫輸入側(cè)通道輪詢邏輯重點(diǎn)檢查tready握手高電平飽和削波輸出位寬不夠或飽和模式選擇不當(dāng)觀察輸出是否被鉗位在最大值加寬輸出位寬或改用Wraparound模式數(shù)據(jù)率上不去時(shí)鐘頻率不夠通道數(shù)太多計(jì)算HIL和抽頭數(shù)看DSP資源利用率提高主時(shí)鐘或用獨(dú)立總線模式并行輸入時(shí)序收斂失敗IP核內(nèi)部乘法器級(jí)數(shù)太長(zhǎng)查看時(shí)序報(bào)告定位關(guān)鍵路徑在IP核配置里提高多相并行度或增加輸出流水級(jí)4.2 三個(gè)典型案例復(fù)盤第一個(gè)案例輸出全0。那次是同事誤把coe文件只寫了注釋和radix行系數(shù)數(shù)據(jù)全丟了IP核顯示Taps數(shù)量為0但配置頁(yè)面不報(bào)錯(cuò)。排查了一天才發(fā)現(xiàn)是coe文件末尾分號(hào)被中文輸入法打成了全角符號(hào)。從那以后我寫了個(gè)腳本加載coe文件后立即打印系數(shù)個(gè)數(shù)和第一個(gè)系數(shù)值確認(rèn)無(wú)誤再繼續(xù)。第二個(gè)案例通道錯(cuò)位?,F(xiàn)象是4通道輸入正弦波通道0的頻譜出現(xiàn)在通道2的輸出上。查到最后是上游邏輯在tready為低時(shí)仍然推進(jìn)了通道計(jì)數(shù)器導(dǎo)致后續(xù)所有通道的數(shù)據(jù)整體前移。修復(fù)方法很簡(jiǎn)單只有tvalid和tready同時(shí)有效才遞增通道計(jì)數(shù)。但這個(gè)bug隱蔽在仿真波形里很難發(fā)現(xiàn)因?yàn)椴ㄐ慰雌饋?lái)始終有數(shù)據(jù)只是對(duì)應(yīng)關(guān)系不對(duì)。第三個(gè)案例時(shí)序違例。設(shè)計(jì)是64通道、128抽頭、采樣率48kHz主時(shí)鐘100MHz按計(jì)算HIL約32.5理論上一個(gè)MAC足夠。但實(shí)際綜合后DSP使用量非常大查了IP核配置才發(fā)現(xiàn)時(shí)鐘頻率誤填成500MHzIP核按照HIL6.5自動(dòng)復(fù)制了大量MAC單元浪費(fèi)了資源。把時(shí)鐘頻率改成真實(shí)的100MHz并重新生成IP核后DSP使用量下降接近5倍。4.3 性能優(yōu)化與資源權(quán)衡多通道FIR的性能優(yōu)化歸根結(jié)底是HIL和DSP資源之間的權(quán)衡。如果HIL遠(yuǎn)大于抽頭數(shù)IP核會(huì)串行復(fù)用乘加器資源開銷小如果HIL小于等于抽頭數(shù)IP核必須并行展開乘加器DSP開銷直線上升。設(shè)計(jì)階段我會(huì)先用公式粗算一遍再在IP核配置頁(yè)面里看Resource Utilization預(yù)估兩者交叉驗(yàn)證。對(duì)超多通道場(chǎng)景還有幾個(gè)進(jìn)階優(yōu)化思路。一是把多通道數(shù)據(jù)拆成兩路并行分別送兩個(gè)FIR Compiler實(shí)例每個(gè)實(shí)例處理一半通道相當(dāng)于用面積換吞吐。二是利用多相抽取結(jié)構(gòu)降低有效數(shù)據(jù)率在濾波前先做CIC抽取把帶寬降下來(lái)再進(jìn)FIR精濾這在通信中頻信號(hào)處理里很常見。三是在FPGA里用多個(gè)時(shí)鐘域ADC采集端用高速率時(shí)鐘域FIR核心用中速率時(shí)鐘域中間用異步FIFO橋接這樣能把通道數(shù)和數(shù)據(jù)率解耦。另外提醒一句Vivado的IP核在不同版本之間的接口時(shí)序和配置界面偶爾有細(xì)微差異。網(wǎng)上經(jīng)常搜到xilinx sdk 2015.4之類的老版本教程很多配置路徑在現(xiàn)在的新版本里已經(jīng)變了。遇到界面對(duì)不上的情況直接用當(dāng)前版本的IP核數(shù)據(jù)手冊(cè)和例化模板為準(zhǔn)不要硬套老界面截圖。老版本工程遷移到新版Vivado時(shí)FIR Compiler IP核一般會(huì)自動(dòng)升級(jí)但升級(jí)后務(wù)必重新跑一遍仿真對(duì)比輸出比特流確認(rèn)系數(shù)加載和時(shí)序沒有變化。5. 最后再聊一點(diǎn)個(gè)人經(jīng)驗(yàn)多通道FIR設(shè)計(jì)做到最后真正的難點(diǎn)已經(jīng)不在FIR本身了。IP核把算法細(xì)節(jié)封得嚴(yán)嚴(yán)實(shí)實(shí)你需要擔(dān)心的反而是數(shù)據(jù)怎么按時(shí)鐘編排、握手怎么處理、位寬怎么截?cái)?。我個(gè)人最大的體會(huì)是上手FIR Compiler的第一步不是打開Vivado而是先在紙上把通道數(shù)、采樣率、主時(shí)鐘、抽頭數(shù)這四個(gè)數(shù)寫清楚然后算HIL看資源預(yù)估。這一步省下的調(diào)試時(shí)間遠(yuǎn)比想象中多。調(diào)試時(shí)也建議先做最簡(jiǎn)單的單通道沖激響應(yīng)驗(yàn)證再逐步擴(kuò)展到多通道。很多人一上來(lái)就填滿所有通道跑復(fù)雜信號(hào)波形一旦不對(duì)根本無(wú)從定位。把主機(jī)邏輯和IP核解耦測(cè)試確保每一步通路都對(duì)了再接起來(lái)這個(gè)習(xí)慣能幫你少走很多彎路。如果你現(xiàn)在正被某個(gè)多通道FIR的問題折磨回過頭去檢查通道輪詢邏輯和tready握手大概率問題就出在那里。