處理開(kāi)發(fā)套件設(shè)計(jì)及調(diào)試要點(diǎn)解析)
開(kāi)發(fā)SoC FPGA音頻與信號(hào)處理開(kāi)發(fā)套件那陣子最常被問(wèn)到的問(wèn)題就是“為什么不直接上一塊MCU加一顆Codec或者干脆用DSP”說(shuō)實(shí)話音頻處理這塊能選的路子確實(shí)不少但如果你要的是多通道低延遲采集、自定義數(shù)字濾波、復(fù)雜信號(hào)分析同時(shí)還要跑協(xié)議棧、做網(wǎng)絡(luò)傳輸、上Linux界面那SoC FPGA這套組合幾乎就是為這個(gè)場(chǎng)景量身定做的。這個(gè)項(xiàng)目標(biāo)題里三個(gè)關(guān)鍵詞很實(shí)在SoC、FPGA、Audio Processing再加上Development Kit說(shuō)明不是單純畫(huà)一塊板子而是要做成一整套能快速上手、能復(fù)現(xiàn)、能二次開(kāi)發(fā)的硬件平臺(tái)。這篇文章就圍繞這個(gè)套件的設(shè)計(jì)思路、核心模塊、工程實(shí)現(xiàn)和調(diào)試經(jīng)驗(yàn)展開(kāi)適合正在做音頻處理、高速信號(hào)采集、或者剛接觸Zynq/SoC FPGA的工程師閱讀。1. 為什么選SoC FPGA做音頻與信號(hào)處理1.1 SoC FPGA和純FPGA、MCU、DSP的本質(zhì)區(qū)別很多第一次接觸SoC FPGA的人會(huì)把它當(dāng)成“帶ARM的FPGA”或者“帶FPGA的ARM”這個(gè)說(shuō)法不算錯(cuò)但容易低估它的意義。以Xilinx Zynq-7000系列為例PS端是雙核Cortex-A9 ARM處理器PL端是邏輯資源兩者之間通過(guò)AXI總線進(jìn)行高速通信。這種架構(gòu)最大的好處是實(shí)時(shí)性要求極高的信號(hào)處理放在PL端完成比如采樣數(shù)據(jù)的抽取、濾波、FFT、調(diào)制解調(diào)而管理、控制、通信、人機(jī)交互這類對(duì)實(shí)時(shí)性要求不那么苛刻的任務(wù)放在PS端跑Linux或裸機(jī)程序。音頻項(xiàng)目里典型的場(chǎng)景是AD/DA高速采樣通過(guò)JESD204B接口進(jìn)PLPL把數(shù)據(jù)流做處理之后通過(guò)AXI DMA搬到DDR3PS端拿到數(shù)據(jù)后再做編碼、存儲(chǔ)、網(wǎng)絡(luò)發(fā)送這一整條鏈路在單個(gè)芯片上就能閉環(huán)。如果你用純FPGA當(dāng)然也能實(shí)現(xiàn)強(qiáng)大的并行處理但寫(xiě)一個(gè)音頻協(xié)議棧、做網(wǎng)絡(luò)協(xié)議、維護(hù)文件系統(tǒng)會(huì)繁瑣到讓人懷疑人生。如果用MCU并行處理能力有限四路以上音頻同步采集再加上實(shí)時(shí)濾波就會(huì)比較吃力。用傳統(tǒng)DSP的話編程難度低一些但它的靈活性主要體現(xiàn)在軟件上遇到需要自定義高速接口或者極低延遲吞吐結(jié)構(gòu)的時(shí)候FPGA的硬件可編程能力是無(wú)法替代的。SoC FPGA恰好是兩邊的結(jié)合點(diǎn)這也是為什么中高端音頻設(shè)備、無(wú)線電接收機(jī)、醫(yī)療超聲前端、工業(yè)振動(dòng)監(jiān)測(cè)都喜歡往這個(gè)方向走。1.2 這套開(kāi)發(fā)套件到底能解決什么問(wèn)題項(xiàng)目標(biāo)題里特意寫(xiě)了Development Kit開(kāi)發(fā)套件意味著不是一張裸板而是一套軟硬件工具鏈、參考設(shè)計(jì)和例程的集合體。它面向的真實(shí)需求可以拆成四塊音頻采集把模擬麥克風(fēng)、線性輸入、數(shù)字麥克風(fēng)等信號(hào)轉(zhuǎn)成PCM數(shù)據(jù)。音頻處理實(shí)現(xiàn)降采樣、濾波、增益控制、回聲消除、波束成形等算法。高速數(shù)據(jù)搬運(yùn)多通道數(shù)據(jù)在PL和PS之間高效流轉(zhuǎn)不丟幀、不阻塞。系統(tǒng)整合跑Linux操作系統(tǒng)提供Web配置頁(yè)面、音頻流網(wǎng)絡(luò)發(fā)送等能力。套件的意義在于把“從零做板子”變成“拿到板子就開(kāi)始寫(xiě)算法”。我自己做這類項(xiàng)目時(shí)最大的感受是最難的不是某個(gè)濾波器的系數(shù)而是系統(tǒng)級(jí)集成。SoC FPGA開(kāi)發(fā)套件把ARM端啟動(dòng)、PL端配置、音頻Codec驅(qū)動(dòng)、DMA傳輸這些骨架搭好工程師能集中精力做自己的核心算法和業(yè)務(wù)邏輯這對(duì)項(xiàng)目周期的影響非常大。2. 開(kāi)發(fā)套件的整體設(shè)計(jì)與硬件選型2.1 板級(jí)資源和核心芯片怎么選既然是音頻與處理應(yīng)用的套件硬件選型必須以“滿足音頻級(jí)性能和可擴(kuò)展性”為前提。我建議的核心配置大概是這樣的模塊選型方案理由SoC FPGAXilinx Zynq-7020 / Zynq-7045 / Artix-7 Cortex-A9資源適中PS/PL平衡社區(qū)資料多音頻CodecADAU1761 / TLV320AIC23 / WM8731支持I2S、TDM信噪比高Linux驅(qū)動(dòng)成熟高速ADC/DACAD9208 AD9172JESD204B接口面向?qū)拵盘?hào)處理采樣率高存儲(chǔ)DDR3 SODIMM / 芯片顆粒數(shù)據(jù)緩沖、Linux運(yùn)行內(nèi)存電源樹(shù)多路DC-DC LDO模擬部分獨(dú)立LDO降低紋波保證音頻底噪時(shí)鐘低抖動(dòng)晶振可編程時(shí)鐘芯片低抖動(dòng)時(shí)鐘是ADC/DAC信噪比的基礎(chǔ)對(duì)于入門(mén)級(jí)音頻套件Zynq-7020就夠用了。PL端大概有85K邏輯單元、220個(gè)DSP Slice做4到8通道的FIR濾波和FFT沒(méi)問(wèn)題。如果你要做復(fù)雜的波束成形或者多通道寬帶采集建議選更大規(guī)模的型號(hào)。開(kāi)發(fā)套件一定要把FPGA的引腳引出來(lái)比如FMC接口這樣可以接不同的子板這是擴(kuò)展性的關(guān)鍵。2.2 音頻數(shù)據(jù)通路的設(shè)計(jì)思路音頻鏈路聽(tīng)起來(lái)簡(jiǎn)單實(shí)際在FPGA內(nèi)部要處理的問(wèn)題不少。以一套典型的I2S音頻采集鏈路為例模擬音頻經(jīng)過(guò)Codec采樣量化后通過(guò)I2S或TDM接口送到PL端。PL端先做一個(gè)格式轉(zhuǎn)換模塊把串行數(shù)據(jù)轉(zhuǎn)成并行PCM數(shù)據(jù)然后進(jìn)入濾波模塊濾波后的數(shù)據(jù)寫(xiě)入AXI4-Stream FIFO然后由AXI DMA搬移到PS的DDR3。PS端應(yīng)用從DDR3拿到數(shù)據(jù)后可以做文件存儲(chǔ)、網(wǎng)絡(luò)發(fā)送或?qū)崟r(shí)頻譜顯示。這套通路里有個(gè)關(guān)鍵點(diǎn)I2S的采樣時(shí)鐘、位時(shí)鐘和系統(tǒng)時(shí)鐘一般都是由音頻晶振直接提供或者由Codec自己產(chǎn)生而PS/DMA工作時(shí)鐘是由ARM PLL生成的兩者來(lái)自不同時(shí)鐘源。如果不做跨時(shí)鐘域處理數(shù)據(jù)必然會(huì)出現(xiàn)偶發(fā)錯(cuò)位和爆音。我在工程里通常會(huì)在I2S接收模塊后面加一個(gè)異步FIFO把音頻時(shí)鐘域的并行數(shù)據(jù)安全搬到AXI時(shí)鐘域這個(gè)細(xì)節(jié)很容易被新手忽略。2.3 電源紋波和時(shí)鐘抖動(dòng)音頻品質(zhì)的隱形殺手很多工程師會(huì)把注意力放在Codec選型上忽略電源和時(shí)鐘結(jié)果測(cè)出來(lái)信噪比不理想。這里有一個(gè)實(shí)際經(jīng)驗(yàn)ADC電源引腳上的紋波會(huì)直接進(jìn)入采樣信號(hào)尤其當(dāng)紋波頻率落在音頻頻帶內(nèi)時(shí)會(huì)在頻譜上看到明顯的雜散和底噪抬高。射頻SoC器件的數(shù)據(jù)手冊(cè)里關(guān)于ADC電源紋波的要求通常非常嚴(yán)格比如要求20mV以內(nèi)甚至更低音頻ADC雖然沒(méi)這么夸張但模擬電源和數(shù)字電源必須隔離模擬地平面要單獨(dú)處理。建議的電源架構(gòu)是整板輸入5V或12V用DC-DC先降到各路中間電壓然后在每個(gè)模擬器件附近用LDO做二次穩(wěn)壓。LDO的電源抑制比能有效濾除開(kāi)關(guān)紋波代價(jià)是效率低一些但模擬電路不在乎這點(diǎn)損耗。時(shí)鐘方面MCLK的抖動(dòng)會(huì)影響ADC的采樣抖動(dòng)采樣抖動(dòng)又直接決定信噪比上限。音頻晶振最好選用低抖動(dòng)有源晶振或者用可編程抖動(dòng)衰減器別用便宜的無(wú)源晶振湊合。3. 音頻處理鏈路的核心細(xì)節(jié)與FPGA實(shí)現(xiàn)3.1 從I2S到并行PCM數(shù)據(jù)接口時(shí)序必須摳到bit級(jí)I2S總線的時(shí)序不算復(fù)雜但有一點(diǎn)必須注意數(shù)據(jù)位和幀時(shí)鐘、位時(shí)鐘的相位關(guān)系。標(biāo)準(zhǔn)I2S是位時(shí)鐘BCLK驅(qū)動(dòng)每一位幀時(shí)鐘WCLK也叫LRCLK變化時(shí)對(duì)應(yīng)一個(gè)新聲道開(kāi)始數(shù)據(jù)通常比WCLK延遲一個(gè)BCLK周期對(duì)齊。實(shí)際操作中不同Codec的實(shí)現(xiàn)可能略有差異比如TDM模式下MSB延遲可能是0個(gè)周期也可能是1個(gè)周期所以要參考數(shù)據(jù)手冊(cè)不能一根筋按標(biāo)準(zhǔn)來(lái)。下面是一個(gè)簡(jiǎn)單的I2S接收模塊的Verilog實(shí)現(xiàn)骨架只處理標(biāo)準(zhǔn)的立體聲PCM數(shù)據(jù)module i2s_rx #( parameter DATA_WIDTH 24 )( input wire bclk, input wire wclk, input wire sdata_in, input wire rst_n, output reg [DATA_WIDTH-1:0] left_chan, output reg [DATA_WIDTH-1:0] right_chan, output reg sample_valid ); reg [5:0] bit_cnt; reg [DATA_WIDTH-1:0] shift_reg; reg wclk_d; always (posedge bclk or negedge rst_n) begin if (!rst_n) begin bit_cnt 0; shift_reg 0; end else begin wclk_d wclk; if (wclk ! wclk_d) begin bit_cnt 0; end else begin if (bit_cnt DATA_WIDTH) begin shift_reg {shift_reg[DATA_WIDTH-2:0], sdata_in}; bit_cnt bit_cnt 1; end end end end always (negedge wclk or negedge rst_n) begin if (!rst_n) begin left_chan 0; right_chan 0; sample_valid 0; end else begin if (wclk) begin // left channel, adjust polarities as needed left_chan shift_reg; sample_valid 1; end else begin right_chan shift_reg; sample_valid 0; end end end endmodule這個(gè)模塊只表達(dá)基本思路實(shí)際使用時(shí)要特別注意跨時(shí)鐘域和WCLK邊沿位置的細(xì)節(jié)。在Vivado工程里我會(huì)用ILA邏輯分析儀抓BCLK、WCLK和SDATA波形確認(rèn)Codec輸出的數(shù)據(jù)格式和模塊假設(shè)一致再往下做濾波處理。3.2 CIC濾波器、抽取與插值以及音頻濾波器組FPGA做音頻處理最常碰到的濾波器無(wú)非三種FIR、IIR、CIC。CIC濾波器在FPGA里的價(jià)值在于不需要乘法器只用累加器和寄存器特別適合做高倍率抽取或插值。比如把1.536MHz的過(guò)采樣數(shù)據(jù)降到48kHz標(biāo)準(zhǔn)音頻采樣率抽取32倍用CIC濾波器最劃算。代價(jià)是通帶會(huì)有一個(gè)跌落需要在后面接一個(gè)CIC補(bǔ)償濾波器來(lái)拉平。以ADC輸出1.536MSPS、需要48kHz采樣率為例抽取因子R32CIC階數(shù)N4差分延遲M1。CIC的增益大致是(RM)^N也就是32的4次方等于1048576。如果不做位寬擴(kuò)展累加器早就溢出了所以CIC內(nèi)部寄存器的位寬必須比輸入位寬大log2((RM)^N)比特這是大家最容易踩的坑。實(shí)際處理音頻時(shí)我一般會(huì)先用CIC做粗抽取再用FIR做抗混疊和頻率均衡。FIR的系數(shù)可以用MATLAB的Filter Designer或Python的scipy生成導(dǎo)出成coe文件在Vivado中用FIR Compiler IP核加載。注意輸入輸出位寬、系數(shù)位寬要匹配否則量化噪聲會(huì)變成底噪的一部分。3.3 多通道同步采集與DMA傳輸當(dāng)套件需要支持四路或八路音頻同步采集時(shí)數(shù)據(jù)通路的設(shè)計(jì)就不僅僅是濾波的問(wèn)題了。每個(gè)ADC通道的數(shù)據(jù)都要在一個(gè)明確的采樣幀邊界到達(dá)否則通道間會(huì)有固定的時(shí)間偏移。在FPGA設(shè)計(jì)里我會(huì)在I2S/TDM接口模塊中生成一個(gè)frame_sync信號(hào)把所有通道的數(shù)據(jù)對(duì)齊到這個(gè)信號(hào)之后再做后續(xù)處理保證通道間的采樣時(shí)刻一致。接著就是大帶寬數(shù)據(jù)傳輸。音頻數(shù)據(jù)量看起來(lái)不大但高速ADC配合多通道時(shí)也需要DMA來(lái)減輕CPU負(fù)擔(dān)。我會(huì)在PL端例化AXI DMA IP核以內(nèi)存映射模式把連續(xù)采樣的數(shù)據(jù)寫(xiě)入PS DDR3。PS端的驅(qū)動(dòng)采用Ping-pong緩沖機(jī)制DMA在寫(xiě)完緩沖A后觸發(fā)中斷CPU處理A的同時(shí)DMA繼續(xù)寫(xiě)B(tài)這樣不會(huì)丟數(shù)據(jù)。采樣率越高、通道越多Ping-pong緩沖的深度就越大需要根據(jù)DDR帶寬和中斷響應(yīng)時(shí)間做權(quán)衡。4. 實(shí)操?gòu)腣ivado建工程到跑通音頻Demo4.1 搭建Vivado工程與關(guān)鍵IP連接整個(gè)流程我習(xí)慣用Vivado的Block Design來(lái)做因?yàn)閆ynq的PS配置和相關(guān)IP的連接用圖形化界面高效很多。如果你是命令行愛(ài)好者也可以用Tcl腳本建工程這樣方便版本管理。下面是一個(gè)簡(jiǎn)化的Tcl建工程示例create_project audio_kit ./audio_kit -part xc7z020clg400-1 create_bd_design system # 添加Zynq PS create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 # 配置PS比如UART、SD、ENET1、DDR等 set_property -dict [list \ CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} \ CONFIG.PCW_ENET1_PERIPHERAL_ENABLE {1} \ CONFIG.PCW_SD0_PERIPHERAL_ENABLE {0} \ CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {100} \ ] [get_bd_cells processing_system7_0] # 添加AXI DMA和Audio I2S模塊 create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 axi_dma_0 create_bd_cell -type ip -vlnv xilinx.com:ip:axi_i2s_adi:1.2 axi_i2s_adi_0Block Design里關(guān)鍵連接包括Zynq PS的M_AXI_GP0接口通過(guò)AXI Interconnect連接到AXI DMA的S_AXI_LITE和S_AXI_MM。AXI DMA的M_AXI_MM2S和S_AXI_S2MM連接到DDR。AXI I2S控制器通過(guò)AXI-Lite配置寄存器I2S數(shù)據(jù)線連接到PL引腳或者自定義I2S模塊通過(guò)AXI Stream連接到DMA。這里有句實(shí)在話用Xilinx官方ADI的AXI I2S IP比自己寫(xiě)I2S驅(qū)動(dòng)省心很多它已經(jīng)把寄存器接口、FIFO和DMA握手做好了。如果是板載Codec不匹配IP可以在IP的配置項(xiàng)里調(diào)整TDM和格式參數(shù)。4.2 PS端裸機(jī)代碼Codec初始化和DMA中斷以一個(gè)ADAU1761 Codec為例它的配置通過(guò)I2C完成寄存器非常多但核心步驟無(wú)非是復(fù)位、設(shè)置采樣率、使能ADC通路、配置輸出音量、配置I2S格式。我一般是先把所有寄存器寫(xiě)到一個(gè)數(shù)組里然后循環(huán)發(fā)送。I2C_Config codec_config[] { {0x00, 0x1F}, // Register 0x00: clock enable {0x01, 0x02}, // PLL if needed {0x08, 0xFF}, // DAC and ADC power up // ... 更多寄存器 {0x10, 0x03}, // ADC control {0x18, 0x03}, // Digital audio interface format, I2S };初始化完Codec后配置DMA中斷。AXI DMA的驅(qū)動(dòng)可以用Xilinx的XAxis_Dma庫(kù)也可以直接用BSP里的函數(shù)。核心邏輯是初始化DMA并設(shè)置收發(fā)緩沖區(qū)。注冊(cè)DMA發(fā)送完成和接收完成回調(diào)。使能DMA的S2MM和MM2S通道。在中斷回調(diào)里處理一幀音頻數(shù)據(jù)比如打印幅度、做簡(jiǎn)單音量調(diào)節(jié)、或者通過(guò)網(wǎng)絡(luò)發(fā)送。這里有個(gè)經(jīng)驗(yàn)DMA描述符必須放在DDR里而且要對(duì)齊到32字節(jié)邊界。如果發(fā)現(xiàn)DMA傳輸時(shí)好時(shí)壞優(yōu)先查描述符地址對(duì)齊和Cache一致性。裸機(jī)環(huán)境下通常不需要處理Cache但跑Linux時(shí)就一定要用dma_alloc_coherent或dma_map_single來(lái)保證一致性。4.3 時(shí)序約束怎么加才不糊弄音頻工程的時(shí)鐘頻率不高但如果不加約束Vivado的綜合布局布線很可能把關(guān)鍵路徑放飛到不合格尤其在PL端和PS端跨時(shí)鐘域時(shí)。我會(huì)在XDC里至少加這樣幾類約束主時(shí)鐘約束把板載晶振、Codec MCLK、PL端的恢復(fù)時(shí)鐘都創(chuàng)建為primary clock。生成時(shí)鐘約束若使用了MMCM/PLL讓工具自動(dòng)推導(dǎo)生成時(shí)鐘但要注意檢查是否自動(dòng)傳到了每個(gè)時(shí)鐘端點(diǎn)。異步時(shí)鐘組約束音頻I2S時(shí)鐘域和AXI時(shí)鐘域是異步的中間用異步FIFO隔離要使用set_clock_groups -asynchronous明確告訴工具不需要分析跨時(shí)鐘域路徑否則會(huì)出現(xiàn)一堆假時(shí)序違例。create_clock -name audio_mclk -period 40.690 [get_ports mclk] # 24.576 MHz create_clock -name axi_aclk -period 10.000 [get_ports axi_aclk] # 100 MHz set_clock_groups -asynchronous -group [get_clocks audio_mclk] -group [get_clocks axi_aclk]注意這里的時(shí)鐘周期要按自己板子的晶振頻率算不要照抄。時(shí)序約束的價(jià)值不在于把時(shí)序報(bào)告搞綠而在于讓布局布線工具知道真實(shí)的設(shè)計(jì)約束避免在異步路徑上亂優(yōu)化導(dǎo)致資源浪費(fèi)。5. 調(diào)試中遇到的坑和排查思路5.1 音頻輸出無(wú)聲或噪聲明顯的排查順序這是音頻開(kāi)發(fā)里最常見(jiàn)的問(wèn)題。我一般按照信號(hào)鏈路從后往前查第一看Codec是否正常初始化。用I2C讀回寄存器確認(rèn)Reg 0x00到0x1F的值和寫(xiě)入一致。很多“無(wú)聲”問(wèn)題其實(shí)是I2C地址搞錯(cuò)或者片選地址引腳沒(méi)接對(duì)導(dǎo)致寄存器根本沒(méi)寫(xiě)進(jìn)去。第二看主時(shí)鐘MCLK是否送到了Codec。有的板子設(shè)計(jì)了FPGA輸出MCLK有的直接用晶振。用示波器測(cè)MCLK引腳同時(shí)看是否有穩(wěn)定頻率。MCLK沒(méi)起振Codec的ADC和DAC都不會(huì)工作。第三看I2S管腳電平是否符合預(yù)期。重點(diǎn)抓BCLK和WCLK的頻率正常48kHz采樣率、位深24bit時(shí)BCLK約為2.88MHz左右WCLK剛好是48kHz。如果看到WCLK不是正確的采樣率說(shuō)明Codec配置或時(shí)鐘分頻有問(wèn)題。第四看DMA是否真的在搬運(yùn)數(shù)據(jù)。在ILA里觀察AXI Stream的tvalid和tlast信號(hào)確認(rèn)數(shù)據(jù)正在流出?;蛘咴赑S端定時(shí)打印DMA的中斷次數(shù)如果中斷次數(shù)不增加則問(wèn)題出在PL端數(shù)據(jù)生成而不是后級(jí)。無(wú)聲問(wèn)題解決后容易出現(xiàn)的是底噪高。排除接地不良、電源紋波之外很常見(jiàn)的一個(gè)坑是Codec的數(shù)字電源和模擬電源沒(méi)有分開(kāi)從數(shù)字引腳傳進(jìn)來(lái)的開(kāi)關(guān)噪聲直接耦合到模擬輸出。解決方法是增加磁珠或PI型濾波并且讓PCB布局盡量保證模擬地和數(shù)字地單點(diǎn)連接。5.2 JESD204B鏈路建立失敗與電源紋波的影響如果這套SoC FPGA開(kāi)發(fā)套件帶有高速射頻ADC/DAC子卡比如AD9208這類JESD204B接口的器件那調(diào)試難度會(huì)明顯上一個(gè)臺(tái)階。尤其是Subclass 1模式需要SYSREF信號(hào)來(lái)對(duì)齊多片器件的采樣時(shí)鐘。我遇到過(guò)不少次“鏈路建立失敗”的情況最終原因往往不是FPGA邏輯問(wèn)題而是電源紋波導(dǎo)致LMK04828等時(shí)鐘芯片的鎖定狀態(tài)波動(dòng)或者SYSREF信號(hào)質(zhì)量太差。JESD204B的調(diào)試可以按這個(gè)順序先確保參考時(shí)鐘和SYSREF信號(hào)頻率正確并且滿足建立保持時(shí)間。檢查FPGA端GTX參考時(shí)鐘的電壓擺幅和偏置。檢查復(fù)位順序尤其是所有器件的sysref和reset必須按子類要求。用ILA監(jiān)測(cè)鏈路層的sync信號(hào)確認(rèn)握手完成。如果鏈路層偶發(fā)下電考慮用頻譜儀看時(shí)鐘的相位噪聲同時(shí)量一下電源紋波。在高速數(shù)據(jù)轉(zhuǎn)換器應(yīng)用中電源紋波對(duì)ADC的SNR和SFDR影響非常明顯。曾經(jīng)有一次在2.4GHz輸入信號(hào)附近看到底噪平臺(tái)最初懷疑是濾波器最后發(fā)現(xiàn)是ADC供電的LDO輸入輸出壓差不夠紋波通過(guò)電源引腳耦合到了采樣保持電路。后來(lái)在LDO前面加了低噪聲高頻去耦電容并把開(kāi)關(guān)電源頻率移開(kāi)信號(hào)頻帶頻譜立刻干凈了很多。這個(gè)經(jīng)驗(yàn)在射頻SoC器件的電源設(shè)計(jì)文檔里被反復(fù)強(qiáng)調(diào)但很多人容易忽略真正的問(wèn)題上來(lái)就對(duì)著FPGA邏輯找毛病方向反而錯(cuò)了。5.3 時(shí)序違例不解決有時(shí)候不是時(shí)鐘頻率問(wèn)題開(kāi)發(fā)套件跑音頻算法時(shí)時(shí)鐘頻率一般不高100MHz左右按理說(shuō)時(shí)序不容易違例。但如果看到setup或hold violation原因往往不是時(shí)鐘頻率太高而是約束文件缺失或?qū)戝e(cuò)了跨時(shí)鐘域路徑。我見(jiàn)過(guò)有同事把兩個(gè)異步時(shí)鐘域的路徑錯(cuò)誤地設(shè)成了false_path但這兩個(gè)信號(hào)其實(shí)是要參與邏輯判定的結(jié)果功能時(shí)好時(shí)壞。更穩(wěn)妥的做法是在跨時(shí)鐘域的地方使用同步器、異步FIFO或者XPM模塊然后把異步組用set_clock_groups聲明。這樣既不會(huì)產(chǎn)生假的時(shí)序違例也不會(huì)漏掉真正需要檢查的路徑。有時(shí)候時(shí)序違例是多個(gè)路徑同時(shí)爆紅這時(shí)候先用Vivado的時(shí)序摘要看最差的WNS和TNS然后針對(duì)關(guān)鍵路徑做retiming或插入流水線寄存器。不要一上來(lái)就把時(shí)鐘頻率降下來(lái)那是治標(biāo)不治本。穩(wěn)定的開(kāi)發(fā)套件應(yīng)該敢于把時(shí)序余量留足而不是靠運(yùn)氣跑起來(lái)。6. 最后再分享幾個(gè)讓我印象深刻的細(xì)節(jié)項(xiàng)目走到后期我最大的感受是SoC FPGA做音頻處理硬件設(shè)計(jì)和軟件調(diào)試的時(shí)間占比大概是四六開(kāi)軟件更多。硬件上只要把電源、時(shí)鐘、接口和PCB布線做扎實(shí)后面省的時(shí)間遠(yuǎn)超前期投入。幾個(gè)細(xì)節(jié)我反復(fù)強(qiáng)調(diào)過(guò)很多次Codec初始化寄存器配置一定要做成可回讀校驗(yàn)I2S接口的時(shí)序必須用邏輯分析儀抓過(guò)再繼續(xù)寫(xiě)算法以及DMA中斷回調(diào)里千萬(wàn)不要做耗時(shí)的打印操作否則音頻幀會(huì)被CPU周期擠掉。另外無(wú)論你用的是哪一家開(kāi)發(fā)套件拿到板子第一件事不要急著寫(xiě)算法而是先把最簡(jiǎn)的“回環(huán)測(cè)試”跑通也就是Codec采集一段音頻在FPGA里原樣搬回DAC輸出?;丨h(huán)通了再去加濾波、加FFT、加網(wǎng)絡(luò)傳輸。這一步能幫你把鏈路分成兩段問(wèn)題出在前半段還是后半段一目了然。對(duì)于想深入做音頻信號(hào)處理的工程師這套路值得借鑒。