戰(zhàn)指南)
前段時間接了個多通道信號采集的項目8路ADC同時采樣每路50kHz后端要做128階低通濾波。剛開始我沒多想直接在工程里拉了兩個單通道FIR II濾波核并行跑結(jié)果在Cyclone V上折騰了半天DSP資源吃緊時序收斂也費(fèi)勁。后來換成單個多通道FIR II濾波核8路全塞進(jìn)去資源開銷降了不止一半問題一下子解決了。這篇就把Altera現(xiàn)在叫Intel多通道FIR II濾波器從選型、IP核配置、系數(shù)文件生成到仿真調(diào)試的完整流程梳理一遍重點(diǎn)講講那些手冊里寫得不明顯、但實(shí)際工程里一定會踩的坑。適合對FIR有一定了解、但還沒系統(tǒng)用過IP核的FPGA工程師也適合正在被多通道濾波資源問題搞到頭大的同學(xué)參考。1. 為什么選它多通道FIR II能替你解決的三個現(xiàn)實(shí)問題1.1 場景多路ADC數(shù)據(jù)流的實(shí)時濾波做信號處理的FPGA項目八成以上會遇到同一個需求多路ADC同時采樣每一路都要做實(shí)時濾波。常見的例子包括多路加速度計振動監(jiān)測、多通道生理信號處理、電力系統(tǒng)諧波分析、相控陣的波束數(shù)據(jù)預(yù)處理以及很多嵌入式工程師熟悉的STM32多通道ADC DMA采集方案的升級版——當(dāng)通道數(shù)增多、采樣率提高、實(shí)時性要求變強(qiáng)之后單純靠MCU輪詢或DMA搬運(yùn)就頂不住了數(shù)據(jù)會被送到FPGA里做前端處理。在這個場景里如果每一路數(shù)據(jù)都用獨(dú)立的FIR濾波器實(shí)現(xiàn)資源開銷是成倍上漲的。8路用8個單通道FIR32路就要32個DSP乘法器數(shù)量、邏輯單元、存儲器占用全部跟著線性增長。而多通道FIR II核的設(shè)計初衷就是解決這個問題它在一個IP核內(nèi)部通過時分復(fù)用方式處理多路數(shù)據(jù)共享大部分運(yùn)算與存儲資源通道數(shù)增加帶來的額外開銷遠(yuǎn)小于多個獨(dú)立濾波器的總和。1.2 用IP核 vs 手寫Verilog的賬有些朋友習(xí)慣自己寫FIR RTL覺得不就一個乘累加循環(huán)嗎沒什么難度。單通道確實(shí)還行但多通道場景下手寫和用IP核的差距就拉開了。手寫多通道FIR首先要自己管理每一路獨(dú)立的延遲線存儲也就是每個通道都需要N個歷史樣點(diǎn)多通道意味著要維護(hù)一個二維存儲陣列。其次乘累加運(yùn)算的調(diào)度需要手工做狀態(tài)機(jī)通道切換時要保證每個通道的累積器干凈、互不污染。再加上系數(shù)更新、有效信號對齊、飽和/截位策略這些細(xì)節(jié)一套寫下來至少幾百行代碼Debug周期相當(dāng)可觀。更關(guān)鍵的是綜合之后的時序和資源未必比IP核好因?yàn)镮P核是Altera針對器件結(jié)構(gòu)專門優(yōu)化的乘法器映射、流水級插入、DSP塊布局都比通用RTL靠譜。我遇到過不止一次工程師用自研FIR跑仿真沒問題一上板時序收斂不了或者和Avalon-ST總線對接時valid/ready握手漏了周期數(shù)據(jù)全亂。用IP核至少能把這些基礎(chǔ)問題擋在門外。1.3 和其他濾波方案的選型對比關(guān)于濾波器選型網(wǎng)上相關(guān)的討論非常多比如四階巴特沃斯濾波器、高斯濾波器、滑動窗口濾波器、RC濾波器、Sallen-Key濾波器等關(guān)鍵詞經(jīng)常被放在一起比較。它們之間不是替代關(guān)系而是適用場景不同。FIR和IIR巴特沃斯、切比雪夫等的區(qū)別IIR階數(shù)低、計算量小但相位非線性FIR可以用線性相位保證信號波形不失真代價是需要更多抽頭。Altera的FIR II IP核只做FIR不涉及IIR。FIR和滑動窗口濾波器移動平均的區(qū)別滑動窗口本質(zhì)上是一種系數(shù)全為1的簡易FIR計算量極小頻率響應(yīng)是sinc形狀旁瓣抑制差阻帶衰減只有約-13dB。如果你只是做平滑看趨勢滑動窗口夠用但要做真正意義上的抗混疊、濾除帶外干擾還是需要正經(jīng)設(shè)計系數(shù)的FIR。我給一個實(shí)際選型對比表方便做方案評審時直接用方案線性相位阻帶衰減資源開銷多通道復(fù)用適用場景FIR II IP核是可設(shè)計能達(dá)到-60dB以上可控多通道復(fù)用優(yōu)勢明顯原生支持多路信號實(shí)時濾波、抗混疊、正交解調(diào)手寫FIR是取決于系數(shù)如果優(yōu)化不好很容易超標(biāo)需要自己設(shè)計調(diào)度學(xué)習(xí)驗(yàn)證、特定定制需求IIR巴特沃斯等否相同階數(shù)下優(yōu)于FIR運(yùn)算量小需要自己設(shè)計對相位不敏感的控制環(huán)路、簡單預(yù)處理滑動窗口濾波是約-13dB極小容易實(shí)現(xiàn)純平滑、快速預(yù)覽、傳感器去毛刺從表格可以看出多通道FIR II的核心競爭力在于“線性相位 強(qiáng)阻帶抑制 原生多通道資源復(fù)用”。這也是為什么它在多路數(shù)據(jù)采集前端的地位很難被替代。2. 上手前要搞懂的關(guān)鍵概念抽頭、通道、時鐘與系數(shù)的關(guān)系2.1 濾波器階數(shù)與抽頭多一個抽頭意味著什么FIR濾波器的抽頭數(shù)N決定了濾波器的階數(shù)N-1階也直接決定了頻率響應(yīng)的陡峭程度。需要明確一點(diǎn)FIR的“階數(shù)”和巴特沃斯濾波器的“階數(shù)”不是一回事。巴特沃斯的四階指的是系統(tǒng)函數(shù)的極點(diǎn)個數(shù)粗算下來阻帶每十倍頻程衰減約80dBFIR的階數(shù)則直接對應(yīng)抽頭數(shù)和延遲量階數(shù)越高過渡帶越窄但計算量和延遲也越大。一個128抽頭的FIR信號延遲是固定的N-1/2個采樣周期也就是63.5個周期。這一點(diǎn)在設(shè)計實(shí)時控制系統(tǒng)時特別關(guān)鍵很多人討論滑動窗口濾波器延遲大、FIR延遲大其實(shí)只要采樣率確定延遲就是可精確計算的關(guān)鍵看系統(tǒng)預(yù)算允不允許。比如采樣率50kHz下128抽頭FIR的純?yōu)V波延遲約1.27ms對大多數(shù)采集系統(tǒng)可以接受如果做閉環(huán)控制就要重新評估。2.2 多通道是時分復(fù)用不是并行復(fù)制理解多通道FIR II最重要的是抓住“時分復(fù)用”這四個字。正常情況下一個FIR濾波器每個時鐘周期只能處理一個樣點(diǎn)。多通道FIR II并沒有把一個濾波器變成多個而是讓一個濾波器在時間軸上輪轉(zhuǎn)處理不同通道的數(shù)據(jù)。比如16通道配置下第1個時鐘周期進(jìn)來的是通道0的樣點(diǎn)第2個周期是通道1的樣點(diǎn)依此類推每16個時鐘周期完成一輪所有通道的濾波運(yùn)算。這個設(shè)計帶來的好處是乘法器、加法器等運(yùn)算資源是共享的不需要為每個通道復(fù)制一份。128抽頭單通道FIR假設(shè)需要128個乘法器理論上16通道也只需要這128個乘法器只是每個乘法器要從頭到尾處理16份數(shù)據(jù)。當(dāng)然實(shí)際實(shí)現(xiàn)中IP核為了滿足時序要求可能會引入部分并行流水但總的資源量級遠(yuǎn)低于“16個濾波器各自獨(dú)立”。理解這個機(jī)制對后面的時鐘頻率計算、數(shù)據(jù)對齊、系數(shù)映射都非常重要。2.3 fMAX、通道數(shù)與采樣率的三角關(guān)系這里有一個多通道FIR II項目失敗的經(jīng)典原因內(nèi)部工作時鐘算錯。由于濾波器是時分復(fù)用的假設(shè)IP核工作的時鐘頻率是f_CLK通道數(shù)是N_CH那么每個通道能夠獲得的最高有效采樣率就是f_CLK / N_CH。反過來說如果你要求每個通道的采樣率是f_S通道數(shù)N_CH那么IP核時鐘頻率至少應(yīng)該取f_CLK ≥ f_S × N_CH。舉個例子16通道、每通道50kHz采樣那么IP核工作時鐘必須達(dá)到50kHz × 16 800kHz以上。這個頻率本身不高但如果你把采樣率提高到2MHz要跑16通道時鐘就要32MHz這時候?yàn)V波器的乘法器、流水級、布線長度都會開始成為瓶頸。如果采樣率是50MHz、通道數(shù)是8時鐘就要400MHz在Cyclone V這類中端器件上基本不可能收斂這時候就要考慮減少通道數(shù)、降低抽頭數(shù)或換更高端的器件。這個公式看起來簡單但我在實(shí)際項目里遇到的時序失敗有一半以上是源于對“通道數(shù) × 采樣率 實(shí)際處理速率”沒有清晰認(rèn)知。設(shè)計初期務(wù)必先算這筆賬再決定濾波架構(gòu)是選全串行、半串行還是全并行。2.4 多通道與系數(shù)集Banks的映射規(guī)則FIR II IP核允許一個多通道濾波器對應(yīng)一組或幾組系數(shù)。常見使用方式是“所有通道共享一組系數(shù)”也就是16通道都用同一個128階低通系數(shù)。這種情況下只需一個系數(shù)文件就夠了IP核內(nèi)部會自動把這份系數(shù)用于每個通道。另一種方式是“不同通道用不同系數(shù)集”比如8路信號里4路做低通、4路做帶通或者每個通道的截止頻率不同。這種場景需要在MegaWizard里配置多個系數(shù)Bank并通過額外的端口coefficient address、coefficient write等在運(yùn)行時切換系數(shù)。需要注意多通道模式下的系數(shù)Bank數(shù)量和通道數(shù)之間是有限制的一個常見約束是Bank數(shù)必須整除通道數(shù)具體約束在IP核的用戶手冊里寫得很明確配置時如果填錯了MegaWizard會直接報錯。我個人的建議是如果只是各通道截止頻率有差異但結(jié)構(gòu)相同優(yōu)先把設(shè)計拆成兩個獨(dú)立的多通道FIR核各自管各自的系數(shù)這樣接口更清晰比在一個核里做系數(shù)切換更省心。3. MegaWizard配置逐項講解從建立工程到生成IP3.1 Quartus環(huán)境準(zhǔn)備與IP核位置Altera FPGA的軟件開發(fā)環(huán)境老版本叫Quartus II新版本叫Quartus Prime。FIR II這個IP核在兩代環(huán)境里都存在位置也基本一致Tools → MegaWizard Plug-In Manager或者新建IP時在IP Catalog的DSP → Filters里找到FIR II。版本選擇上如果你是維護(hù)老項目可能還在用Quartus II 13.0或更早的版本如果是新項目建議直接用Quartus Prime18.0以后的版本都支持Cyclone V/10代以后的器件。有一個環(huán)境層面的經(jīng)典問題需要提一下Windows系統(tǒng)更新后USB-Blaster在設(shè)備管理器里可能出現(xiàn)代碼39錯誤即“Windows無法加載此設(shè)備的驅(qū)動程序”。這套故障通常不是板子壞了而是驅(qū)動被系統(tǒng)更新覆蓋或反復(fù)裝過多個版本產(chǎn)生了沖突。處理辦法是在設(shè)備管理器里把USB-Blaster設(shè)備卸載并勾選“刪除此設(shè)備的驅(qū)動程序軟件”然后重新安裝Quartus安裝目錄下drivers/usb-blaster中的驅(qū)動如果還不行多半是老版本驅(qū)動在新系統(tǒng)上有簽名問題需要臨時禁用驅(qū)動程序強(qiáng)制簽名后再安裝一次。這個問題雖然和濾波器本身無關(guān)但它會卡住后續(xù)所有在線調(diào)試先鋪個路。3.2 濾波器規(guī)格頁參數(shù)怎么填打開MegaWizard之后FIR II的配置頁一般分為幾個部分濾波器規(guī)格、系數(shù)規(guī)格、接口與架構(gòu)、輸出控制。以我們這次的目標(biāo)——16通道、128階、每通道50kHz采樣、低通截止5kHz為例關(guān)鍵參數(shù)如下參數(shù)建議值說明Filter TypeLow Pass濾波器類型Number of Taps128抽頭數(shù)128階準(zhǔn)確說是127階Coefficient Filelp_5k.mif后續(xù)生成的系數(shù)文件Coefficient RepresentationSigned, 16-bit單極性還是雙極性Data RepresentationSigned, 16-bitADC數(shù)據(jù)一般是有符號數(shù)Number of Channels16多通道核心參數(shù)Coefficient Banks1所有通道共享一組系數(shù)Filter ArchitectureSemi-Parallel資源與性能折中Pipeline LevelAuto讓工具自動優(yōu)化Data FlowSingle Data Stream數(shù)據(jù)以一個交織總線輸入這里特別提醒兩個容易被忽略的選項一是“Coefficient Representation”與“Data Representation”。如果輸入數(shù)據(jù)來自ADC通常是二進(jìn)制補(bǔ)碼有符號數(shù)如果系數(shù)文件里算出負(fù)系數(shù)系數(shù)也必須是有符號數(shù)。這個選錯輸出結(jié)果會完全不對。二是“Filter Architecture”。全并行Fully Parallel每個時鐘周期同時計算所有抽頭吞吐率最高但DSP塊消耗巨大多通道場景下通常不必選它除非處理時鐘實(shí)在提不上去。全串行Fully Serial最省資源但每個采樣點(diǎn)需要N個時鐘周期完成計算對時鐘頻率要求高。半串行Semi-Parallel在兩者之間實(shí)際工程里最常用。多通道模式下強(qiáng)烈建議選半串行默認(rèn)的并行設(shè)置很容易讓資源爆炸。3.3 Avalon-ST接口與時序valid和ready的握手FIR II IP核對外采用Avalon-ST接口本質(zhì)就是一組簡單的流控握手信號。核心有四個ast_sink_data輸入數(shù)據(jù)總線ast_sink_valid輸入數(shù)據(jù)有效標(biāo)志拉高代表當(dāng)前時鐘周期有有效數(shù)據(jù)ast_sink_ready輸出方向給回的“可接收”標(biāo)志ast_source_data / ast_source_valid濾波結(jié)果輸出這里最關(guān)鍵的是理解valid/ready握手規(guī)則只有當(dāng)valid和ready同時為高時數(shù)據(jù)才算真正被接收并向前流動了一拍。IP核可能在ready拉低的時候暫停接收也能夠在valid拉低時停等數(shù)據(jù)。所以在自己寫的上游模塊里必須實(shí)現(xiàn)標(biāo)準(zhǔn)的Avalon-ST適配邏輯不能盲目假設(shè)“我只要持續(xù)送數(shù)它就能持續(xù)收”。用文本簡單表示一下時序關(guān)系clk __/ ̄ ̄\__/ ̄ ̄\__/ ̄ ̄\__/ ̄ ̄\__/ ̄ ̄\__/ ̄ ̄\__ sink_valid ____/ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ sink_ready  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ sink_data ____/ D0 / D1 / D2 / D3 / D4 / D5 /D0到D5可以理解為通道0到通道15的輪轉(zhuǎn)輸入。重點(diǎn)在于每個時鐘周期都要有數(shù)據(jù)才能維持每個通道的采樣率。3.4 一個16通道、128階低通IP的完整配置示例生成IP核之后Quartus會產(chǎn)出一個帶固定名字的Verilog/VHDL實(shí)體。下面是一個簡化的頂層連接示例將外部ADC多通道交織數(shù)據(jù)接入FIRmodule fir_16ch_top #( parameter DATA_WIDTH 16, parameter CHANNELS 16 )( input wire clk, input wire reset_n, input wire [DATA_WIDTH-1:0] adc_data, input wire adc_valid, output wire adc_ready, output wire [DATA_WIDTH*2-1:0] fir_out, output wire fir_valid ); fir_16ch_lp u_fir_16ch_lp ( .clk (clk), .reset_n (reset_n), .ast_sink_data (adc_data), .ast_sink_valid (adc_valid), .ast_sink_error (2b00), .ast_sink_ready (adc_ready), .ast_source_data (fir_out), .ast_source_valid (fir_valid), .ast_source_error () ); // 作為頂層這里可以把輸出結(jié)果接一個FIFO或直接轉(zhuǎn)Avalon-MM endmodule注意ast_sink_error在不需要錯誤檢測時固定接2’b00這個信號往往被忽略但端口是存在的不接仿真會報錯。還有輸出位寬FIR II的輸出位寬通常是輸入位寬與系數(shù)位寬之和再加若干保護(hù)位不要拿輸入位寬去截取結(jié)果否則會丟掉高位有效數(shù)據(jù)。4. 系數(shù)文件生成MATLAB造.mif的完整工程化流程4.1 用fir1計算系數(shù)與歸一化現(xiàn)在濾波器系數(shù)幾乎沒人手算MATLAB是首選。以我們16通道項目里用到的5kHz低通、50kHz采樣率、128抽頭為例fs 50000; % 采樣率 50kHz fc 5000; % 截止頻率 5kHz ntaps 128; % 抽頭數(shù) 128 coeff fir1(ntaps - 1, fc / (fs / 2), low); % 歸一化保證直流增益為1 coeff coeff / sum(coeff); figure; freqz(coeff, 1, 1024, fs); title(Designed FIR Lowpass);這里有一點(diǎn)特別重要fir1的第一個參數(shù)是階數(shù)不是抽頭數(shù)。128抽頭對應(yīng)階數(shù)是127所以上面代碼里寫的是ntaps - 1。畫freqz圖的時候重點(diǎn)看一眼-3dB點(diǎn)是否落在5kHz附近阻帶衰減是否符合要求。如果阻帶衰減不夠不要盲目加抽頭先確認(rèn)窗函數(shù)類型、過渡帶寬度的設(shè)置是否合理。4.2 整數(shù)量化與.mif格式細(xì)節(jié)FIR II的系數(shù)文件支持.mif或.hex格式。我推薦用.mif因?yàn)樗谋究勺x便于版本管理。生成.mif的MATLAB代碼如下% 轉(zhuǎn)換為16bit有符號整數(shù) Q 2^15; coeff_q round(coeff * Q); % 防止偶爾出現(xiàn)的越界值理論上不會但防御一下 coeff_q(coeff_q 32767) 32767; coeff_q(coeff_q -32768) -32768; fid fopen(lp_5k.mif, w); fprintf(fid, WIDTH 16;\n); fprintf(fid, DEPTH %d;\n, ntaps); fprintf(fid, ADDRESS_RADIX DEC;\n); fprintf(fid, DATA_RADIX DEC;\n); fprintf(fid, CONTENT BEGIN\n); for k 1:ntaps fprintf(fid, %d : %d;\n, k - 1, coeff_q(k)); end fprintf(fid, END;\n); fclose(fid);生成后記得檢查一下量化誤差把量化后的系數(shù)重新轉(zhuǎn)回浮點(diǎn)和原始系數(shù)做對比計算頻率響應(yīng)。工程上有個快速檢查方法——把量化后的系數(shù)求和。如果和接近2^1532768說明直流增益基本保持在1。因?yàn)榍懊鏆w一化時總和為1乘以32768后應(yīng)該接近32768。我碰到過有人系數(shù)文件漏了一行、或用了無符號格式導(dǎo)致FIR輸出整體幅度偏小或直流偏置異常這類問題通過求和檢查往往能立刻發(fā)現(xiàn)。4.3 多通道共享系數(shù) / 各自獨(dú)立系數(shù)的文件組織配置多通道時要分清兩種情況。如果是“所有通道共用一套系數(shù)”那只需要在MegaWizard里指定一份.mif即可上面生成的lp_5k.mif直接能用。這是最常見的多通道濾波器用法各路信號頻段一樣只是來源不同。如果是“各通道使用不同系數(shù)”需要配置多個系數(shù)Bank。這時準(zhǔn)備文件的方式略有不同不同Bank對應(yīng)的系數(shù)分別保存為單獨(dú)的.mif文件在MegaWizard里需要把這些文件關(guān)聯(lián)到各自的Bank索引或者使用在線系數(shù)更新功能在運(yùn)行時通過寄存器寫入。在線更新會引入一組coeff_write端口設(shè)計時要多出一套總線和控制邏輯復(fù)雜度明顯增加。如果需求不是特別動態(tài)比如運(yùn)行中實(shí)時切換濾波器頻段我更建議做成幾個獨(dú)立的多通道濾波器核通過MUX選擇輸出保證各路徑之間完全隔離便于調(diào)試。5. 仿真與實(shí)測那些沒人告訴你的坑5.1 輸出全零系數(shù)加載問題的排查多通道FIR II配置完成后最常遇到的現(xiàn)象就是仿真或?qū)崪y輸出全零。首先不要懷疑濾波器壞了大概率是系數(shù)沒有正確加載。排查鏈路我建議這樣走第一步檢查.mif文件路徑是否包含非ASCII字符或空格。Quartus老版本對中文路徑和空格支持很糟糕IP核生成時會靜默跳過系數(shù)文件產(chǎn)出的例化文件里系數(shù)全是0。第二步檢查生成的.qip或.v文件搜索coefficient相關(guān)初始化數(shù)據(jù)確認(rèn)系數(shù)確實(shí)寫在里面了。第三步用ModelSim或QuestaSim跑IP核自帶的行為級仿真模型看內(nèi)部ram初始化值是否正常。這類問題的特征是“編譯全通過、仿真無報錯、輸出恒為0”非常隱蔽。我在一個項目里就因?yàn)楣こ搪窂綆Я酥形恼垓v了整整一個下午。另外還要注意如果你手動修改了.mif文件必須重新生成IP核重新跑一遍MegaWizard生成流程僅僅保存修改文件不會自動更新到IP核里。5.2 數(shù)據(jù)第一個點(diǎn)對不上valid與ready的時序誤區(qū)上板實(shí)測時經(jīng)常發(fā)現(xiàn)FIR輸出比輸入延遲了一拍或兩拍或者第一批數(shù)據(jù)的前幾個樣點(diǎn)不對。這種現(xiàn)象絕大多數(shù)不是IP核有問題而是上游數(shù)據(jù)valid/ready握手沒有滿足要求。常見錯誤有兩種一是上游在valid無效時數(shù)據(jù)總線也隨意變化導(dǎo)致IP核采樣到不該采的數(shù)據(jù)二是上游把數(shù)據(jù)準(zhǔn)備好和valid拉高放在了同一拍沒有給IP核足夠的建立時間。Avalon-ST往嚴(yán)格里說是“數(shù)據(jù)必須與valid同步有效”但實(shí)際布局布線后如果數(shù)據(jù)路徑和valid路徑的延遲偏差過大時序收斂也可能出問題。建議所有上游模塊包括ADC接口邏輯、DMA控制器、自定義處理邏輯都統(tǒng)一按照“valid拉高時data必須穩(wěn)定有效”的約定來寫。如果不確定就在FIR前面加一個同步FIFO作為緩沖用FIFO的空/滿信號作為valid/ready控制。這個做法雖然多了幾個周期的延遲但能把后級邏輯徹底解耦調(diào)試時省心得多。5.3 多通道數(shù)據(jù)錯亂通道順序與數(shù)據(jù)流對齊多通道模式下的數(shù)據(jù)順序是一個必須提前約定清楚的問題。FIR II的單數(shù)據(jù)流模式要求輸入數(shù)據(jù)嚴(yán)格按照“每N個時鐘周期一個完整通道輪轉(zhuǎn)”的方式組織也就是第一個周期是通道0第二個是通道1直到第N個是通道N-1然后下一輪循環(huán)。如果你的ADC采集順序和這個不一致結(jié)果不是某一路錯位而是所有路的輸出全都亂了。排查這個問題的辦法是做一個“通道標(biāo)記測試”給每一路輸入一個不同頻率的測試單音比如通道0給1kHz正弦波通道1給2kHz正弦波通道2給3kHz正弦波以此類推然后在輸出端用SignalTap抓數(shù)據(jù)數(shù)一下通道0的波形出現(xiàn)在第幾個輸出通道位置。如果發(fā)現(xiàn)錯位只需要調(diào)整輸入數(shù)據(jù)的通道排列順序即可。另外要注意IP核輸出延遲本身就是多個周期多通道輪轉(zhuǎn)時不同通道的輸出延遲時序是錯開的。不能在輸出端根據(jù)“valid拉高”就默認(rèn)當(dāng)前數(shù)據(jù)屬于通道0必須自己維護(hù)一個與輸入對齊的通道計數(shù)邏輯。我習(xí)慣在數(shù)據(jù)進(jìn)入FIR的同時把一個通道序號寫進(jìn)一個延遲鏈對齊到輸出側(cè)這樣無論延遲多少周期都能準(zhǔn)確判斷當(dāng)前輸出是哪個通道。5.4 fMAX跑不上去怎么辦多通道FIR II另一個常見項目坑是時序收斂失敗Quartus報告fMAX不達(dá)標(biāo)。前面公式提到多通道要求時鐘頻率至少是通道數(shù)乘以采樣率所以一旦資源和布局緊張這個矛盾就立刻暴露。處理優(yōu)先級我建議按順序來先檢查Filter Architecture從Fully Parallel改成Semi-Parallel或Fully Serial這是最有效的降資源手段再檢查Pipeline Level從Min改成Max或Auto讓工具插入更多流水級。FPGA設(shè)計里加流水級是提升fMAX最直接的手段FIR II核內(nèi)部已經(jīng)預(yù)留了流水位置代價只是多幾拍延遲。如果這樣還不行檢查是否在綜合設(shè)置里限制了DSP塊的使用數(shù)量有時候手工約束會好心辦壞事。最后再看器件速度等級是不是因?yàn)槌杀究紤]選了-6甚至-7的慢速器件實(shí)際工作頻率逼近極限了。這里有另外一個經(jīng)驗(yàn)多通道FIR資源緊張時建議把“降低系數(shù)位寬”作為候選方案。系數(shù)從16bit降到12bitDSP塊占用能明顯下降阻帶抑制性能卻未必差太多??梢杂肕ATLAB把量化后的系數(shù)跑一遍freqz對比一下阻帶衰減和通帶紋波只要滿足系統(tǒng)指標(biāo)12bit完全可以用。5.5 另外一個小提醒在線調(diào)試的依賴項無論后期用SignalTap還是ILA抓信號前提都是JTAG鏈路穩(wěn)定工作。除了前面提到的USB-Blaster代碼39驅(qū)動問題還有一個細(xì)節(jié)SignalTap的采樣時鐘最好用獨(dú)立的全局時鐘不要直接抓經(jīng)過邏輯門組合的時鐘信號否則采樣會出現(xiàn)大量亞穩(wěn)態(tài)毛刺看起來像數(shù)據(jù)壞了其實(shí)是采樣方式不對。6. 工程延伸從IP到一套完整的數(shù)據(jù)鏈6.1 與ADC/DAC的時序銜接多通道FIR II在工程里通常只是完整數(shù)據(jù)鏈的中間一環(huán)。前端是ADC接口后端是DAC回放或數(shù)據(jù)處理模塊。ADC接口給到FIR的數(shù)據(jù)盡量不要直接來自引腳采樣邏輯而是先經(jīng)過一個簡單的可同步復(fù)位FIFO。原因是ADC輸出的數(shù)據(jù)和FIR要求的Avalon-ST時序不一定匹配中間插FIFO既能做跨時鐘域又能解決數(shù)據(jù)有效標(biāo)志的時序?qū)R問題。后端如果有DAC要注意FIR輸出位寬和DAC輸入位寬可能不一致。FIR輸出位寬一般會大于輸入位寬比如16bit輸入配16bit系數(shù)輸出可能會是34bit。接DAC之前要做截位截位策略可以選擇直接截高位、帶符號飽和或者加一點(diǎn)噪聲整形。直接截高位最簡單但直流偏置和削波要看實(shí)測飽和邏輯能防止信號過大時輸出翻轉(zhuǎn)。這些額外處理在IP核外面加一個小模塊即可。6.2 與STM32/上位機(jī)的數(shù)據(jù)接口很多項目是FPGA做前端濾波MCU做協(xié)議處理和上位機(jī)通信。我在文章開頭提到過STM32CubeMX配置ADC多通道DMA采集這套典型鏈路到了FPGA側(cè)思路其實(shí)一致數(shù)據(jù)采集由FPGA完成多通道處理后要送給MCU中間通常是一個雙口RAM、一個簡單寄存器組或者一套Avalon-MM接口。這里我建議輸出端單獨(dú)落一個FIFO防止MCU讀取速度跟不上導(dǎo)致數(shù)據(jù)覆蓋。FIFO深度一般取每通道采樣點(diǎn)數(shù)乘以通道數(shù)的兩倍以上比如每通道一次采集1000點(diǎn)、共16通道那FIFO深度至少2^15。同時提供一個“數(shù)據(jù)就緒”中斷信號給MCU而不是讓MCU輪詢等待這樣對系統(tǒng)實(shí)時性更友好。6.3 回環(huán)驗(yàn)證用SignalTap看濾波器輸出最后一步是驗(yàn)證整個數(shù)據(jù)鏈。我的標(biāo)準(zhǔn)做法是先在FPGA內(nèi)部用一個測試信號源直接例化ROM存一段單頻正弦波數(shù)據(jù)替代ADC輸入經(jīng)FIR濾波后通過FIFO輸出再送DAC給示波器或者用SignalTap抓取IP核輸出波形。具體操作上給通道0配置一個3kHz正弦測試信號通道1配置一個8kHz正弦測試信號兩路都經(jīng)過5kHz低通濾波器。理想結(jié)果是通道0輸出正常幅度的3kHz正弦通道1輸出被大幅衰減的8kHz波形。用SignalTap抓到這兩路結(jié)果就能同時驗(yàn)證通道順序、濾波器幅頻特性、以及信號鏈路的完整性。這一步做完整個多通道FIR濾波部分就可以放心交給后續(xù)邏輯了。我在實(shí)際項目中形成的習(xí)慣是任何一次涉及濾波器參數(shù)修改都先跑一遍這個“測試信號回環(huán)驗(yàn)證”確認(rèn)通路無誤再接真實(shí)信號。一次參數(shù)修改引發(fā)多路數(shù)據(jù)錯亂的事件我已經(jīng)見過太多次了。