國內(nèi)頂尖網(wǎng)站設計公司口碑營銷的定義
FPGA:RS編碼仿真過程
RS碼是一種糾錯性能很強的線性糾錯碼,能夠糾正隨機錯誤和突發(fā)錯誤。RS碼是一種多進制BCH碼,能夠同時糾正多個碼元錯誤。
之前已經(jīng)記錄了在MATLAB中進行rs編解碼的過程,現(xiàn)在利用FPGA的IP核實現(xiàn)RS編碼的過程,方便使用RS編碼。
這個過程分成兩部分來記錄,這篇主要記錄rs編碼過程。
1. 開始準備
在FPGA設計通信系統(tǒng)的過程中進行rs編譯碼,需要用到rs編譯碼的IP核,這個IP核已經(jīng)分享,可以直接下載。也已經(jīng)通過程序自己編寫編譯碼的過程,但是完全沒有必要,現(xiàn)成的IP核用好就可以了。
同時為了更好的理解FPGA中rs編碼的過程,這個仿真程序的參數(shù)是可以與記錄的MATLAB教程相對應的。
同時在使用IP核的重要的一步,需要下載對應的pdf文檔,這個能夠幫助更好的使用IP核,編寫自己的程序。
2. RS編碼IP核
RS編碼IP核全名 Reed-Solomon Encoder,首先看這個rs編碼IP核的需要設置的參數(shù)。
這里面和MATLAB仿真對應的參數(shù)設置是Symbol Width
,這個對應MATLAB中的參數(shù)m,也就是符號的位寬,Data Symbols(k)
和Symbols Per Block(n)
分別對應k
和n
。這里的設置注意,k
的限制是和n
相差正偶數(shù)。簡單來說就是每一次k
個數(shù)據(jù)被編碼,然后生成n
個數(shù)據(jù),每個數(shù)據(jù)的位寬是m
,然后參數(shù)Field Polynomial
是多項式,這個所對應的和MATLAB中的也是一樣的,這在文檔中有。
然后注意剩下的參數(shù),其中第一個Code Specification
參數(shù)選擇第一個選項Custom
,其他的選項可以對應不同的協(xié)議的,這個詳細的可以查看文檔,這個直接選擇Custom
,然后參數(shù)Scaling Factor(h)
這個參數(shù)可以設置成默認的1,然后注意Generator Start
參數(shù)設置為1.
這兩個參數(shù)的解釋參照技術文檔中的說法是h
是生成器多項式根索引的比例因子,第二個參數(shù)是生成多項式第一個根的伽羅瓦域?qū)?shù),這兩個參數(shù)直接都設置成1就可以了。
然后再Implementation
參數(shù)設置頁面中,需要設置的參數(shù)相對較少。
可以參考如上設置,選擇一個通道,然后把m_axis_output_tready
信號勾選上。同時注意Latency
的數(shù)值是多少,這個可以與生成的編碼數(shù)據(jù)對應上,這里main設置完為5,相當于編碼后的輸出延時5個clk
。
3. 代碼編寫
接下來進行代碼編寫,直接上代碼rs_encoder.v
。在這里是利用自然數(shù)進行編碼,0-15。大體思路是用有效信號控制輸入的數(shù)據(jù),使得在有效的時候依次輸入0-15。這里面的ready
信號和valid
信號相關控制可以直接看程序,和最后的仿真時序。編碼的參數(shù)如上面的設置m=4
,n=15
,k=3
,ploy=19
。
`timescale 1ns / 1psmodule rs_encoder(input clk, //時鐘input rst_n // 復位 高電平復位
// input [7:0] data_in, // 輸入的待編碼數(shù)據(jù)
// output [7:0] dataout // 輸出的解碼數(shù)據(jù));wire rs_encode_input_tready; // 編碼輸入準備信號
reg rs_encode_input_tvalid_reg; // 編碼輸入有效信號
reg rs_encode_input_tready_reg;
wire rs_encode_input_tlast;
reg rs_encode_input_tlast_reg;
wire[7:0] rs_encode_data;
wire rs_encode_output_tvalid;
wire rs_encode_output_tlast;
wire rs_enocde_output_tready;
reg rs_enocde_output_tready_reg;parameter K = 3; // 對應MATLAB仿真中的k和n的值,這個在IP核設置中已經(jīng)有體現(xiàn)
parameter N = 4; //
parameter L = 15; // 編碼之后的數(shù)據(jù)長度reg [3:0] datain_num; // 每一組編碼的原始數(shù)據(jù)個數(shù)
reg [5:0] dataout_num; //輸出編碼數(shù)據(jù)的個數(shù)// 設計輸入數(shù)據(jù)
reg [3:0] datain;
always@(posedge clk)beginif(~rst_n)begindatain <= 4'b0;rs_encode_input_tready_reg <= 1'b0;rs_encode_input_tvalid_reg <= 1'b0;rs_encode_input_tlast_reg <= 1'b0;rs_enocde_output_tready_reg <= 1'b0;datain_num <= 4'b0;endelse beginrs_encode_input_tready_reg <= rs_encode_input_tready;rs_encode_input_tvalid_reg <= 1'b1;if(rs_encode_input_tready == 1'b1 && rs_encode_input_tvalid_reg == 1'b1)begin // 在ready 和valid信號都有效的時候才開始編碼數(shù)據(jù),可以在這里計數(shù)編碼的個數(shù)。datain <= datain + 4'b1;datain_num <= 4'b1 + datain_num;rs_enocde_output_tready_reg <= 1'b1;endelse beginendend
end// 根據(jù)每一組編碼的組數(shù)來確定數(shù)據(jù)順序 控制最后一個tlast信號。
always@(posedge clk)beginif(~rst_n)beginrs_encode_input_tlast_reg <= 1'b0; // 這個信號是需要在一組中的最后一個數(shù)據(jù)時候信號處于高電平 和k的大小對應endelse beginif(datain_num >= K)beginrs_encode_input_tlast_reg <= 1'b1;endelse beginrs_encode_input_tlast_reg <= 1'b0; //然后重新置零endend
endwire [3:0] data_in;
assign data_in = datain;rs_encoder_0 rs_encoder_0_ins ( //latency 5clk.aclk(clk), // input wire aclk.aresetn(rst_n), // input wire aresetn.s_axis_input_tdata(data_in), // input wire [7 : 0] s_axis_input_tdata.s_axis_input_tvalid(rs_encode_input_tvalid_reg), // input wire s_axis_input_tvalid.s_axis_input_tready(rs_encode_input_tready), // output wire s_axis_input_tready.s_axis_input_tlast(rs_encode_input_tlast_reg), // input wire s_axis_input_tlast.m_axis_output_tdata(rs_encode_data), // output wire [7 : 0] m_axis_output_tdata.m_axis_output_tvalid(rs_encode_output_tvalid), // output wire m_axis_output_tvalid.m_axis_output_tready(rs_enocde_output_tready_reg), // input wire m_axis_output_tready.m_axis_output_tlast(rs_encode_output_tlast) // output wire m_axis_output_tlast
);// 通過編碼模塊輸出的valid信號和ready信號來記錄輸出數(shù)據(jù)的個數(shù)
always@(posedge clk)beginif(~rst_n)begindataout_num <= 6'b0;endelse beginif(rs_encode_output_tvalid==1'b1 && rs_enocde_output_tready_reg==1'b1)begindataout_num <= dataout_num + 6'b1;if(dataout_num >= 6'd15)begindataout_num <= 6'b0;endendelse beginendend
endendmodule
首先利用MATLAB
仿真看一下[0,1,2,3,4,5,6,7,8]
這幾個編碼后的數(shù)據(jù)是多少,在MATLAB
仿真中用的是矩陣,所以結果得到的也是矩陣,三個數(shù)據(jù)一組,所以相當于進行了三次編碼
4. 仿真測試
然后添加一個testbench
文件然后程序運行起來。rs_tb.v
,這個程序比較簡單,就是進行初始化,設置時鐘和復位信號。
`timescale 1ns / 1psmodule rs_tb();reg l_clk;
reg rst_n;rs_encoder rs_test_ins(.clk(l_clk), //時鐘.rst_n(rst_n) // 復位 高電平復位
// input [7:0] data_in, // 輸入的待編碼數(shù)據(jù)
// output [7:0] dataout // 輸出的解碼數(shù)據(jù));initial l_clk = 1;
always #5 l_clk= !l_clk; //15.625 initial beginrst_n <= 0;#40;rst_n <= 1;#320;//#50000000;#320;
// $stop;
end
endmodule
然后運行仿真,可以得到.
首先看第一個藍色標線,ready
信號和valid
信號同時為高,此時輸入的編碼數(shù)據(jù)有三個,分別為0,1,2
,然后經(jīng)過5個clk
延遲,第2個藍色標線處,編碼輸出的ready
信號和valid
信號同時為高,表示編碼輸出有效,得到的編碼結果為0,1,2,1,15,0,12,3,2,12,14,3,15,13,13
,然后是第二組編碼數(shù)據(jù)的結果3,4,5
與MATLAB
仿真的結果是能夠?qū)纳系摹?/p>
這個仿真中的s_tlast
信號可以調(diào)整一下,每輸入三個數(shù)據(jù)拉高一次,防止出錯。
等下一部分進行rs解碼的仿真。