現(xiàn)BISS-C協(xié)議讀取絕對(duì)式編碼器:從狀態(tài)機(jī)到CRC校驗(yàn)調(diào)試指南)
簡(jiǎn)介面向FPGA開(kāi)發(fā)者與工業(yè)編碼器應(yīng)用工程師的BISS-C協(xié)議編碼器Verilog實(shí)現(xiàn)源碼包解決了在高端運(yùn)動(dòng)控制與位置反饋系統(tǒng)中讀取雷尼紹BISS-C協(xié)議編碼器的問(wèn)題。方案通過(guò)parameter參數(shù)化支持18/26/32/36bit位寬靈活切換最高10MHz時(shí)鐘頻率并采用CRC并行計(jì)算技術(shù)將校驗(yàn)耗時(shí)壓縮至單時(shí)鐘周期同時(shí)模塊化設(shè)計(jì)可支撐四路編碼器并行讀取每路約9.8MHz對(duì)實(shí)時(shí)性和多軸場(chǎng)景尤為友好。包體共10個(gè)文件包括3個(gè)Verilog源文件核心解碼模塊、多通道模塊及testbench、1個(gè)VCD仿真波形、1個(gè)仿真運(yùn)行腳本以及README說(shuō)明文檔等30KB壓縮包輕量易移植。方案不依賴IP核附帶全局異步復(fù)位與動(dòng)態(tài)時(shí)序約束處理便于導(dǎo)入不同F(xiàn)PGA平臺(tái)。已有192人學(xué)習(xí)下載適合希望快速落地BISS-C協(xié)議或研究CRC并行加速與狀態(tài)機(jī)超時(shí)檢測(cè)的工程師參考。1. FPGA讀絕對(duì)式編碼器為什么先碰BISS-C協(xié)議做運(yùn)動(dòng)控制和伺服驅(qū)動(dòng)的人遲早要跟絕對(duì)式編碼器打交道。BISS-C協(xié)議在國(guó)產(chǎn)伺服和高端設(shè)備里出現(xiàn)頻率越來(lái)越高它比EnDat和Hiperface開(kāi)放、比SSI帶寬高一根MA時(shí)鐘線加一根SLO數(shù)據(jù)線就能把位置、狀態(tài)、CRC一次性讀回來(lái)。我拆過(guò)的這套FPGA實(shí)現(xiàn)BISS-C協(xié)議編碼器源碼包解決的就是“FPGA做主站、怎么穩(wěn)定讀編碼器”這件事不是簡(jiǎn)單搭個(gè)移位寄存器而是把時(shí)序狀態(tài)機(jī)、CRC校驗(yàn)、多圈處理都做進(jìn)去了。適合想繞過(guò)數(shù)據(jù)手冊(cè)直接看工程實(shí)現(xiàn)的人也適合正在為編碼器讀取出錯(cuò)發(fā)愁的一線調(diào)試工程師。下面按我從仿真到上板的路徑來(lái)說(shuō)清楚。2. BISS-C協(xié)議幀結(jié)構(gòu)從數(shù)據(jù)手冊(cè)到寄存器級(jí)理解2.1 BISS-C的物理層與時(shí)序參數(shù)BISS-C物理層是主從同步串行接口主站負(fù)責(zé)產(chǎn)生MA時(shí)鐘從站編碼器在SLO數(shù)據(jù)線上同步回傳數(shù)據(jù)。注意它跟SPI有點(diǎn)相似但MA時(shí)鐘不是持續(xù)自由的而是在一次讀取周期里按幀突發(fā)。源碼包里把MA時(shí)鐘頻率做成可配置我通常設(shè)在2MHz到5MHz之間。這個(gè)參數(shù)直接影響整幀讀取時(shí)間也影響編碼器從站的上電響應(yīng)能力。傳輸方向只有兩根線MA從主站到編碼器SLO從編碼器回主站。MA時(shí)鐘上升沿和下降沿各有用途標(biāo)準(zhǔn)里常用上升沿鎖存SLO數(shù)據(jù)但不少編碼器在下降沿之后數(shù)據(jù)才真正穩(wěn)定這個(gè)細(xì)節(jié)是后面調(diào)試踩坑的重災(zāi)區(qū)。物理層還要注意RS-422差分還是單端源碼里默認(rèn)按差分輸入輸出處理管腳約束時(shí)就要對(duì)應(yīng)到FPGA的差分輸入緩沖器。幀與幀之間MA時(shí)鐘要保持高電平空閑。如果主站連續(xù)發(fā)時(shí)鐘編碼器會(huì)認(rèn)為是一幀超長(zhǎng)數(shù)據(jù)狀態(tài)機(jī)直接亂掉。源碼的狀態(tài)機(jī)里專(zhuān)門(mén)有一段超時(shí)檢測(cè)超過(guò)設(shè)定時(shí)鐘周期數(shù)還沒(méi)收到有效響應(yīng)就強(qiáng)制回到IDLE否則整機(jī)聯(lián)調(diào)時(shí)編碼器線松動(dòng)一次后續(xù)所有讀取全廢。2.2 一幀數(shù)據(jù)里藏了哪些字段BISS-C一幀從編碼器回傳的數(shù)據(jù)結(jié)構(gòu)可以分成幾段我拆源碼時(shí)習(xí)慣先把每一段的位寬和使用場(chǎng)景列清楚。下表是BISS-C標(biāo)準(zhǔn)幀的典型字段分布具體位寬由編碼器廠商和源碼參數(shù)決定。字段段位寬作用說(shuō)明Ack1位編碼器對(duì)主站起始請(qǐng)求的應(yīng)答Start1位數(shù)據(jù)開(kāi)始標(biāo)志通常為低電平Control1位控制位區(qū)分位置數(shù)據(jù)還是附加數(shù)據(jù)Data多比特單圈位置數(shù)據(jù)位寬可配置如17位或25位Error1位編碼器內(nèi)部錯(cuò)誤標(biāo)志CRC6位對(duì)Data和Error字段的CRC校驗(yàn)Timeout1位數(shù)據(jù)結(jié)束段主站感知傳輸結(jié)束注意一幀里并不只有位置數(shù)據(jù)。Control位決定這幀是普通位置幀還是帶診斷信息的擴(kuò)展幀源碼包里把Control位引出來(lái)供上層邏輯判斷。CRC是6位多項(xiàng)式校驗(yàn)覆蓋范圍從Data最高位到Error位不包括Ack和Start。很多第一次接觸BISS-C的人會(huì)把CRC算到整個(gè)幀最后校驗(yàn)永遠(yuǎn)不過(guò)這是協(xié)議理解上的第一個(gè)坎。2.3 協(xié)議狀態(tài)機(jī)與CRC校驗(yàn)范圍源碼的核心是一個(gè)有限狀態(tài)機(jī)狀態(tài)跳轉(zhuǎn)跟著MA時(shí)鐘和SLO反饋?zhàn)?。我從代碼里理出的狀態(tài)序列是IDLE、ACK、START、DATA、ERROR、CRC、COMPLETE。IDLE狀態(tài)下MA時(shí)鐘保持高電平置位讀請(qǐng)求后狀態(tài)機(jī)拉低MA啟動(dòng)傳輸編碼器在第一個(gè)周期內(nèi)回Ack。數(shù)據(jù)位在DATA狀態(tài)逐一進(jìn)入移位寄存器同時(shí)CRC計(jì)算模塊并行處理進(jìn)入的比特。CRC校驗(yàn)范圍要卡準(zhǔn)。BISS-C標(biāo)準(zhǔn)用的CRC多項(xiàng)式是x^6x^11初值通常為0處理的是從Data字段最高位到Error字段最后一位的比特流。源碼里單獨(dú)做了一個(gè)CRC子模塊由狀態(tài)機(jī)控制使能Data段開(kāi)始時(shí)就啟動(dòng)CRC段來(lái)臨時(shí)把接收到的CRC值與本地計(jì)算值做比較。比較結(jié)果不進(jìn)數(shù)據(jù)通路只生成crc_error標(biāo)志這樣讀取邏輯不會(huì)因?yàn)镃RC報(bào)錯(cuò)就中斷整機(jī)運(yùn)行。實(shí)現(xiàn)時(shí)還有一點(diǎn)容易被忽視CRC移位方向。標(biāo)準(zhǔn)里是按高位先發(fā)還是低位先發(fā)編碼器廠商之間并不統(tǒng)一。源碼在參數(shù)表里提供crc_lsb_first選項(xiàng)默認(rèn)配合大多數(shù)國(guó)產(chǎn)編碼器選LSB first。如果發(fā)現(xiàn)CRC總報(bào)錯(cuò)先去看編碼器手冊(cè)里單圈位數(shù)據(jù)的發(fā)送順序而不是馬上懷疑代碼邏輯。3. 源碼包功能拆解工程結(jié)構(gòu)、IP核與頂層模塊劃分3.1 源碼目錄與文件職責(zé)拆源碼包第一步是看目錄和文件劃分。這套工程的常見(jiàn)結(jié)構(gòu)是sources、tb、constraints三級(jí)目錄。sources里放RTL代碼和可選IP核tb里放仿真testbenchconstraints放管腳約束和時(shí)序約束。源碼包拿到手先把目錄樹(shù)拉出來(lái)確認(rèn)哪些是核心RTL哪些是工程生成文件避免把緩存文件當(dāng)代碼看。核心RTL文件職責(zé)可以按下表劃分。實(shí)際文件命名以包內(nèi)為準(zhǔn)我拆過(guò)的版本里會(huì)有一個(gè)頂層模塊和若干子模塊文件/模塊職責(zé)bissc_top頂層封裝對(duì)外接口統(tǒng)一內(nèi)部實(shí)例化下面的子模塊bissc_clk_genMA時(shí)鐘發(fā)生器參數(shù)控制時(shí)鐘頻率和空閑電平bissc_rxSLO數(shù)據(jù)接收完成移位和位寬拼接bissc_crc6位CRC計(jì)算和校驗(yàn)帶使能和復(fù)位bissc_state主狀態(tài)機(jī)協(xié)調(diào)發(fā)送MA時(shí)鐘和接收數(shù)據(jù)bissc_reg讀寫(xiě)寄存器接口對(duì)接Avalon或AXI-LiteAXI-Lite對(duì)接在工程里是可選的。如果你的系統(tǒng)是純邏輯讀取不經(jīng)過(guò)CPU那bissc_reg可以去掉頂層直接輸出position和error標(biāo)志位。如果要做參數(shù)化配置比如運(yùn)行中切換MA頻率或單雙圈模式保留寄存器接口更方便。3.2 時(shí)鐘域與復(fù)位策略FPGA工程里系統(tǒng)時(shí)鐘和MA時(shí)鐘是兩個(gè)域。系統(tǒng)時(shí)鐘通常50MHz或100MHzMA時(shí)鐘由分頻產(chǎn)生??鐣r(shí)鐘域處理不好位置數(shù)據(jù)會(huì)偶發(fā)跳變。源碼里MA時(shí)鐘生成沒(méi)有用計(jì)數(shù)器直接翻轉(zhuǎn)而是先做同步使能再用使能沿去驅(qū)動(dòng)狀態(tài)機(jī)保證MA的每個(gè)周期對(duì)應(yīng)固定的系統(tǒng)時(shí)鐘周期數(shù)。復(fù)位策略也不能馬虎。標(biāo)準(zhǔn)做法是整個(gè)BISS-C鏈路使用異步復(fù)位、同步釋放復(fù)位信號(hào)由頂層統(tǒng)一控制。復(fù)位有效時(shí)要同時(shí)清掉狀態(tài)機(jī)、移位寄存器、CRC模塊不能只復(fù)位主狀態(tài)機(jī)否則重新讀取時(shí)從站還是舊狀態(tài)。源碼里每個(gè)子模塊都帶rst_n端口頂層用同一個(gè)復(fù)位網(wǎng)絡(luò)代碼里可以看到復(fù)位釋放邏輯單獨(dú)處理。我還會(huì)留意全局復(fù)位和局部復(fù)位。工程里如果有軟復(fù)位寄存器和硬復(fù)位引腳兩個(gè)復(fù)位信號(hào)要做一個(gè)或門(mén)軟復(fù)位也要能清狀態(tài)機(jī)。不然在線升級(jí)或斷線重連后只能整板掉電才能恢復(fù)。源碼包里這部分邏輯做在頂層仿真時(shí)不容易暴露上板聯(lián)調(diào)才會(huì)發(fā)現(xiàn)。3.3 主要模塊接口說(shuō)明頂層接口設(shè)計(jì)直接決定接入難度。我按下表列出最常見(jiàn)的一組端口信號(hào)方向以FPGA主站視角為準(zhǔn)端口名方向說(shuō)明clkin系統(tǒng)時(shí)鐘如50MHzrst_nin全局復(fù)位低有效ma_clkout差分MA時(shí)鐘輸出ma_clk_nout差分負(fù)端單端模式懸空slo_datainSLO數(shù)據(jù)輸入slo_data_nin差分負(fù)端單端模式不接read_reqin外部發(fā)起讀取請(qǐng)求脈沖positionout解析后的位置數(shù)據(jù)validout位置數(shù)據(jù)有效標(biāo)志crc_erroroutCRC校驗(yàn)錯(cuò)誤標(biāo)志busyout狀態(tài)機(jī)忙碌指示差分負(fù)端在單端編碼器下可以不接但MA必須區(qū)分正負(fù)。源碼里用OBUFDS差分輸出緩沖器原語(yǔ)單端接入時(shí)直接把負(fù)端約束到地。實(shí)現(xiàn)時(shí)建議把SLO輸入加一個(gè)IBUFDS再進(jìn)邏輯避免信號(hào)質(zhì)量差導(dǎo)致采樣誤判。頂層模塊的Verilog端口聲明通常長(zhǎng)這樣我貼一段精簡(jiǎn)過(guò)的接口代碼module bissc_top #( parameter SINGLE_TURN_BITS 17, parameter MA_CLK_DIV 20 )( input wire clk, input wire rst_n, input wire read_req, output wire ma_clk, output wire ma_clk_n, input wire slo_data, input wire slo_data_n, output wire [31:0] position, output wire valid, output wire crc_error, output wire busy ); wire [SINGLE_TURN_BITS-1:0] raw_position; bissc_state u_state ( .clk (clk), .rst_n (rst_n), .read_req (read_req), .ma_clk (ma_clk), .ma_clk_n (ma_clk_n), .slo_data (slo_data), .slo_data_n (slo_data_n), .valid (valid), .raw_position (raw_position) ); bissc_crc #( .DATA_WIDTH(SINGLE_TURN_BITS) ) u_crc ( .clk (clk), .rst_n (rst_n), .data_in (raw_position), .enable (valid), .error (crc_error) ); assign position {15d0, raw_position}; endmodule邏輯說(shuō)明頂層模塊把MA時(shí)鐘生成、狀態(tài)機(jī)、CRC校驗(yàn)分開(kāi)實(shí)例化。SINGLE_TURN_BITS控制單圈數(shù)據(jù)位寬MA_CLK_DIV控制分頻系數(shù)。read_req是發(fā)起一次完整讀取的觸發(fā)脈沖valid拉高時(shí)表示position已經(jīng)更新同時(shí)CRC結(jié)果也出來(lái)了。position拼接成32位方便接CPU總線。注意這里把CRC校驗(yàn)放在valid之后實(shí)際工程里valid或crc_error是同時(shí)變的要讓上層邏輯同一拍采樣這兩個(gè)信號(hào)避免讀位置時(shí)校驗(yàn)結(jié)果還是上一幀。參數(shù)說(shuō)明SINGLE_TURN_BITS默認(rèn)17對(duì)應(yīng)常見(jiàn)的17位單圈編碼器如果是25位就改成25。MA_CLK_DIV是系統(tǒng)時(shí)鐘分頻系數(shù)50MHz系統(tǒng)時(shí)鐘配20就是2.5MHz MA如果編碼器支持10MHz這個(gè)參數(shù)可以壓到5。分頻系數(shù)不能太小因?yàn)闋顟B(tài)機(jī)在MA每個(gè)周期的處理邏輯也要時(shí)間分頻系數(shù)低于4時(shí)大概率時(shí)序緊張。4. 在FPGA上跑通BISS-C讀取仿真、管腳約束與板上調(diào)試4.1 搭建仿真Testbench的步驟源碼包里的tb目錄通常帶一個(gè)簡(jiǎn)化編碼器模型不依賴真實(shí)硬件就能把狀態(tài)機(jī)和采樣邏輯跑通。這個(gè)模型會(huì)按BISS-C協(xié)議把位置數(shù)據(jù)、CRC和錯(cuò)誤位拼接成串行比特流再按MA時(shí)鐘回推給主站。第一次跑仿真時(shí)務(wù)必先看波形里的MA時(shí)鐘頻率確認(rèn)分頻系數(shù)生效接著再看ACK段和Data段是否按預(yù)期對(duì)齊。tb里核心邏輯是模擬編碼器從站的串行反饋我一般會(huì)寫(xiě)一個(gè)簡(jiǎn)化版的行為模型當(dāng)作參考代碼大致思路是這樣的module bissc_slave_model #( parameter DATA_WIDTH 17 )( input wire ma_clk, input wire read_start, output reg slo_data ); reg [DATA_WIDTH-1:0] position_data; reg [5:0] crc_value; reg sending; reg [5:0] bit_cnt; always (posedge ma_clk or negedge read_start) begin if (!read_start) begin sending 1b1; bit_cnt 6d0; position_data 17h1A2B3; end else if (sending) begin bit_cnt bit_cnt 1b1; case (bit_cnt) 6d0: slo_data 1b0; // Ack 6d1: slo_data 1b0; // Start 6d2: slo_data 1b0; // Control default: begin if (bit_cnt 3 DATA_WIDTH) slo_data position_data[DATA_WIDTH-1 - (bit_cnt-3)]; else slo_data crc_value[5 - (bit_cnt - 3 - DATA_WIDTH)]; end endcase end end endmodule邏輯說(shuō)明這個(gè)模型在read_start信號(hào)有效后把Ack、Start、Control依次拉低然后按高位到低位的順序把position_data打出去最后輸出CRC。它沒(méi)包含Error位實(shí)際使用時(shí)可以在Control之后插入一個(gè)可變Error位再把CRC寬度對(duì)應(yīng)調(diào)整。仿真時(shí)用這個(gè)模型可以驗(yàn)證主站是否采到正確位置、CRC是否匹配也能用來(lái)檢查狀態(tài)機(jī)是否能正確處理單幀結(jié)束。參數(shù)說(shuō)明DATA_WIDTH要跟主站的SINGLE_TURN_BITS保持一致不一致時(shí)CRC必然報(bào)錯(cuò)。read_start在真實(shí)編碼器里是由MA時(shí)鐘起始沿觸發(fā)的這里用獨(dú)立信號(hào)是為了讓模型知道一幀開(kāi)始避免在仿真初始時(shí)刻誤發(fā)數(shù)據(jù)。position_data作為測(cè)試源隨便填但要注意別填超過(guò)DATA_WIDTH范圍的值否則移位時(shí)會(huì)丟高位。4.2 管腳約束與電氣特性注意管腳約束是上板后最容易出問(wèn)題的地方。BISS-C的MA時(shí)鐘是差分對(duì)SLO數(shù)據(jù)如果也是差分就必須用FPGA的差分IO組不能隨便選兩個(gè)普通IO當(dāng)差分對(duì)。差分正端和負(fù)端要約束在同一個(gè)差分組內(nèi)否則綜合工具會(huì)報(bào)錯(cuò)或者生成的時(shí)序特別差。我在約束文件里會(huì)用set_property PACKAGE_PIN指定正負(fù)端同時(shí)用set_property DIFF_TERM TRUE打開(kāi)片上差分端接。電氣特性上編碼器端的線纜長(zhǎng)度會(huì)直接影響最高M(jìn)A頻率。線長(zhǎng)超過(guò)1米時(shí)2.5MHz的MA一般沒(méi)問(wèn)題超過(guò)5MHz之后上升沿變緩SLO數(shù)據(jù)采樣點(diǎn)就會(huì)漂。源碼包里的MA_CLK_DIV留了很大的調(diào)整空間但硬件上最好在編碼器供電端加濾波電容信號(hào)線走差分對(duì)避免因?yàn)殡姍C(jī)動(dòng)力線耦合噪聲導(dǎo)致偶發(fā)CRC錯(cuò)誤。約束文件里時(shí)序約束要關(guān)注MA輸出到SLO輸入的路徑。SLO是編碼器隨MA時(shí)鐘回傳的數(shù)據(jù)從MA輸出沿到SLO有效沿之間存在編碼器響應(yīng)時(shí)間這個(gè)時(shí)間通常為幾百納秒。FPGA綜合工具不能自動(dòng)知道這條外部路徑要在約束里用set_max_delay或虛擬時(shí)鐘把這個(gè)外部延遲約束進(jìn)去。我建議把MA時(shí)鐘設(shè)成generated clockSLO數(shù)據(jù)按該時(shí)鐘域做input delay約束否則布局布線后采樣時(shí)序沒(méi)保證。4.3 用ILA抓實(shí)際時(shí)序上板調(diào)試時(shí)ILA是最直接的驗(yàn)證工具。先在頂層把ma_clk、slo_data、busy、valid、crc_error全部引到ILA探針里采樣深度建議設(shè)成4096采樣頻率用系統(tǒng)時(shí)鐘。觸發(fā)條件設(shè)為read_req上升沿這樣能看到完整一幀從發(fā)起請(qǐng)求到valid拉高的過(guò)程。抓到的波形先看MA時(shí)鐘發(fā)包個(gè)數(shù)再數(shù)SLO有效位數(shù)。如果MA時(shí)鐘數(shù)量固定但SLO數(shù)據(jù)全為高或全為低通常是SLO輸入管腳約束不對(duì)或者差分正負(fù)接反。如果MA時(shí)鐘數(shù)量多了說(shuō)明狀態(tài)機(jī)沒(méi)有在CRC結(jié)束后及時(shí)停止時(shí)鐘編碼器把多余時(shí)鐘當(dāng)作下一幀起始波形里會(huì)看到連續(xù)兩幀粘連。ILA只在調(diào)試階段使用量產(chǎn)工程里要把ILA核去掉或置為不例化不然邏輯資源和時(shí)序性能會(huì)被拖累。我之前調(diào)試一片板子時(shí)忘了屏蔽ILA結(jié)果顯示時(shí)序收斂沒(méi)問(wèn)題但運(yùn)行時(shí)CRC偶爾報(bào)錯(cuò)后來(lái)定位到是ILA核插入導(dǎo)致MA時(shí)鐘路徑變長(zhǎng)。從那以后我把探針做成宏開(kāi)關(guān)仿真和調(diào)試開(kāi)啟正式綜合時(shí)強(qiáng)制關(guān)閉。5. BISS-C調(diào)試避坑時(shí)序翻車(chē)、CRC錯(cuò)位與熱插拔問(wèn)題5.1 現(xiàn)象MA時(shí)鐘頻率過(guò)高導(dǎo)致編碼器無(wú)響應(yīng)現(xiàn)象把MA_CLK_DIV設(shè)為4系統(tǒng)時(shí)鐘50MHzMA跑到12.5MHz編碼器完全沒(méi)反應(yīng)SLO一直高電平狀態(tài)機(jī)卡在ACK階段valid永遠(yuǎn)不拉高。原因編碼器從站對(duì)MA時(shí)鐘有最大頻率限制常規(guī)編碼器支持到5MHz或10MHz12.5MHz超出協(xié)議要求從站內(nèi)部邏輯跟不上直接不應(yīng)答。解決查編碼器手冊(cè)的通信頻率范圍把MA_CLK_DIV調(diào)回合法范圍。調(diào)試階段從低速開(kāi)始先用5分頻跑通再逐步調(diào)高。如果必須跑高頻就要考慮縮短線纜長(zhǎng)度、降低負(fù)載電容。MA時(shí)鐘不是越快越好它只影響讀取刷新率伺服控制周期一般幾百微秒2.5MHz完全夠用。5.2 現(xiàn)象SLO數(shù)據(jù)在第二拍才穩(wěn)定采樣點(diǎn)選錯(cuò)現(xiàn)象仿真時(shí)數(shù)據(jù)正確上板后position偶發(fā)跳變ILA抓波形發(fā)現(xiàn)SLO數(shù)據(jù)在MA上升沿之后還有抖動(dòng)采樣點(diǎn)打在了數(shù)據(jù)穩(wěn)定之前。原因編碼器并非在MA上升沿瞬間更新SLO數(shù)據(jù)線上存在從站輸出延遲。MA時(shí)鐘路徑與SLO回傳路徑的累計(jì)延遲不一定能被FPGA內(nèi)部時(shí)鐘對(duì)齊單純用上升沿采樣是碰運(yùn)氣。解決在狀態(tài)機(jī)里把SLO采樣點(diǎn)改為MA下降沿之后半個(gè)系統(tǒng)時(shí)鐘周期或者直接生成本地延遲采樣使能讓采樣點(diǎn)避開(kāi)數(shù)據(jù)變化沿。具體做法是計(jì)數(shù)MA周期在周期中間位置產(chǎn)生采樣脈沖。這個(gè)邏輯源碼包里可以參數(shù)化控制我一般默認(rèn)開(kāi)延遲采樣只有對(duì)延遲極小的編碼器才切回上升沿直接采樣。注意延遲采樣不能跨時(shí)鐘域要在系統(tǒng)時(shí)鐘域內(nèi)生成同步使能。5.3 現(xiàn)象CRC校驗(yàn)總報(bào)錯(cuò)數(shù)據(jù)移位一位現(xiàn)象valid正常拉高position值看起來(lái)有規(guī)律變化但數(shù)值整體偏小或每位都像左移了一位crc_error一直為高。原因CRC校驗(yàn)范圍或位序配置不對(duì)。常見(jiàn)是編碼器數(shù)據(jù)幀里多了一位Error字段而源碼里把Error位當(dāng)成了Data的一部分或者CRC計(jì)算時(shí)把Ack和Start也納入了范圍導(dǎo)致校驗(yàn)結(jié)果對(duì)不上。解決先逐項(xiàng)核對(duì)Data字段位寬和CRC覆蓋寬度。用ILA抓一幀完整SLO序列人工把里面的Ack、Start、Control、Data、Error、CRC字段標(biāo)出來(lái)再跟源碼的狀態(tài)機(jī)位寬對(duì)照。CRC位序也在這里看如果編碼器手冊(cè)寫(xiě)明數(shù)據(jù)高位先發(fā)就把crc_lsb_first設(shè)為0。還有一個(gè)細(xì)節(jié)CRC計(jì)算需要把Error位包含進(jìn)去即使Error位固定為0也不能跳過(guò)否則CRC計(jì)算結(jié)果會(huì)整體偏移。5.4 現(xiàn)象上電后第一次讀卡死狀態(tài)機(jī)不復(fù)位現(xiàn)象系統(tǒng)上電后第一次發(fā)read_reqbusy信號(hào)拉高后一直不拉低valid和crc_error都不變化但斷電重新上電后第一次讀取正常再觸發(fā)一次卡死。原因狀態(tài)機(jī)在上電或復(fù)位釋放瞬間收到未定義的SLO電平把狀態(tài)誤判成別的狀態(tài)而狀態(tài)機(jī)沒(méi)有看門(mén)狗超時(shí)機(jī)制卡在某個(gè)錯(cuò)誤狀態(tài)不返回IDLE。另一種可能是在線調(diào)試時(shí)復(fù)位信號(hào)比系統(tǒng)時(shí)鐘先釋放狀態(tài)機(jī)寄存器處于亞穩(wěn)態(tài)。解決源碼里需要有一個(gè)超時(shí)計(jì)數(shù)器始發(fā)讀取后如果超過(guò)預(yù)設(shè)周期數(shù)沒(méi)有收到完整幀就把狀態(tài)機(jī)強(qiáng)制復(fù)位回IDLE。我是直接把超時(shí)計(jì)數(shù)并到MA時(shí)鐘產(chǎn)生模塊里數(shù)滿2048個(gè)MA周期沒(méi)完成就自動(dòng)拉resync信號(hào)清掉內(nèi)部狀態(tài)。另外把復(fù)位信號(hào)的同步釋放邏輯單獨(dú)做了兩級(jí)同步器確保復(fù)位釋放時(shí)跟著系統(tǒng)時(shí)鐘沿不產(chǎn)生毛刺。加完這兩個(gè)措施后熱拔插編碼器再接回去也能自動(dòng)恢復(fù)讀取。6. 讓這套源碼更通用參數(shù)化設(shè)計(jì)、多圈處理與后續(xù)擴(kuò)展6.1 參數(shù)化總線寬度與CRC多項(xiàng)式源碼包里最值得改的是把位寬做成參數(shù)。單圈位寬、MA分頻系數(shù)、CRC多項(xiàng)式系數(shù)、采樣延遲周期全部參數(shù)化后同一套R(shí)TL可以適配多款編碼器不用每次復(fù)制工程再手改邏輯。我通常會(huì)在頂層增加一個(gè)參數(shù)組parameter SINGLE_TURN_BITS 17, parameter MULTI_TURN_BITS 0, parameter MA_CLK_DIV 20, parameter CRC_POLY 6b000011, parameter CRC_INIT 6d0, parameter SAMPLE_DELAY 1邏輯說(shuō)明MULTI_TURN_BITS為0時(shí)表示只有單圈輸出拼接時(shí)把多圈段去掉。CRC_POLY和CRC_INIT直接傳到CRC子模塊換編碼器時(shí)只需查手冊(cè)改這兩個(gè)值。SAMPLE_DELAY控制采樣點(diǎn)相對(duì)MA時(shí)鐘沿的延遲周期數(shù)改成參數(shù)后不用動(dòng)狀態(tài)機(jī)。這些參數(shù)在綜合時(shí)都是常量不會(huì)額外消耗寄存器。參數(shù)化的意義在于維護(hù)成本。一個(gè)項(xiàng)目里同時(shí)用了17位和21位編碼器只需要例化兩次頂層模塊分別配不同參數(shù)不需要維護(hù)兩套代碼。后續(xù)如果換上帶多圈功能的編碼器只需把MULTI_TURN_BITS設(shè)為12之類(lèi)輸出位寬自動(dòng)擴(kuò)展。6.2 多圈計(jì)數(shù)與掉電保存的處理技巧BISS-C本身是把多圈位數(shù)直接從編碼器讀出來(lái)的FPGA端只負(fù)責(zé)把多圈段拼進(jìn)位置數(shù)據(jù)。如果編碼器不帶電池備份多圈主站側(cè)的計(jì)數(shù)掉電后會(huì)丟失。源碼包通常不包含掉電保存邏輯但工程里一般會(huì)留出接口。我常用的做法是外接SPI Flash或者鐵電存儲(chǔ)器在每幀數(shù)據(jù)valid有效時(shí)把多圈計(jì)數(shù)值和單圈原始值一起寫(xiě)入備份區(qū)寫(xiě)入頻率不能是每一幀都寫(xiě)Flash壽命會(huì)很快耗盡。實(shí)際做法是快速連續(xù)變化時(shí)只緩存到RAM斷電瞬間檢測(cè)掉電信號(hào)再緊急寫(xiě)入一次。掉電檢測(cè)需要用模擬比較器監(jiān)測(cè)24V或5V供電FPGA里可以留一個(gè)電平輸入給中斷處理。如果編碼器本身支持多圈并且內(nèi)置電池那FPGA端就不需要備份直接讀出來(lái)的就是完整位置。判斷依據(jù)是編碼器手冊(cè)里的“多圈類(lèi)型”字段是電池備份還是純機(jī)械多圈。機(jī)械多圈掉電后讀數(shù)仍在但需要上電后做一次絕對(duì)位置零點(diǎn)校準(zhǔn)。6.3 一條經(jīng)驗(yàn)強(qiáng)制走一遍完整回環(huán)測(cè)試最后的建議是把這套源碼當(dāng)作一個(gè)整體測(cè)試對(duì)象而不是只測(cè)讀取功能。我最常做的是在FPGA內(nèi)部做回環(huán)把頂層模塊的position和valid信號(hào)引出到另一個(gè)仿真子模塊模擬CPU讀寫(xiě)總線讓數(shù)據(jù)在內(nèi)部轉(zhuǎn)一圈再寫(xiě)回編碼器模型對(duì)比是否完全一致。回環(huán)測(cè)試能同時(shí)覆蓋狀態(tài)機(jī)、CRC信號(hào)和valid時(shí)序比單看ILA波形更能發(fā)現(xiàn)問(wèn)題。我曾經(jīng)在改參數(shù)時(shí)漏掉了CRC_POLY的位寬回環(huán)測(cè)試跑到一半crc_error拉高位置數(shù)據(jù)跟預(yù)期差了幾個(gè)值順著回環(huán)鏈路才定位到是CRC子模塊的輸入位寬沒(méi)有跟隨頂層參數(shù)變化。從那以后我每次改參數(shù)都強(qiáng)制走一遍完整回環(huán)測(cè)試仿真通過(guò)才允許上板這套流程已經(jīng)幫我攔下了不少低級(jí)錯(cuò)誤。如果只是做一次性讀取驗(yàn)證也可以把讀到的位置值通過(guò)串口或以太網(wǎng)發(fā)出來(lái)但串口帶寬低高速運(yùn)動(dòng)時(shí)數(shù)據(jù)更新率不夠?;丨h(huán)測(cè)試和ILA配合是最穩(wěn)的組合既能看到協(xié)議層細(xì)節(jié)又能驗(yàn)證數(shù)據(jù)正確性。希望這套調(diào)試流程能幫你在BISS-C項(xiàng)目上少走點(diǎn)彎路。本文還有配套的精品資源點(diǎn)擊獲取