FPGA 实现1553总线接口
数字式时分制指令/响应性多路传输数据总线MIL-STD-1553B,总线为半双工传输方式,在总线上传输的数据码应是曼切斯特II型双电平码,逻辑1为双极编码信号1/0,逻辑0为双极编码信号0/1,过零跳变发生在每一位时的中点。
总线传输时钟是1MHZ,传输速率1Mb/s,传输内容分为指令字,数据字,状态字,字长为16位加同步头奇偶校验位总共20位,同步头占3位,有效位占16位,校验位占1位。
1553总线有以下特点:通过同步头可以确定是数据字还是指令字或状态字;如果是指令字或状态字可以有测试手段位(第十位)来确定;数据字在传输数据时最高有效位优先传输;有效位不用位或保留位按逻辑0传输。
1553总线接口程序主要有两个模块组成:1数据接收模块 2数据发送模块
数据接收模块,如图一所示:
图一
此模块主要是实现1553总线接口部分,把接收到的串行数据转换为并行数据,经过同步头处理,奇数校验处理,输出16位有效数据。
端口说明:
input dec_clk ; // 8Mhz decoder clock.
input rst_n ; // Asynchronous reset.
input rx_data ; // Serial transmit data input.
output[0:15] rx_dword ; // Output data word receive.
output rx_dval ; // Indicates data on "rx_data" isvalid. 数据信息有效
output rx_csw ; // "rx_dword" has command orstatus word. 指令字或状态字
output rx_dw ; // "rx_dword" has data word. 表示数据字有效
output rx_perr ; // Indicates parity error in"rx_dword". 校验错误
如下图二,波形图所示,传输前两个字为状态字和指令字(tx_csw),当tx_dw为1时传输数据字,同步头比tx_csw,tx_dw晚半个T1MHZ。
数据发送模块,如图二所示:
图二
input enc_clk ; // 2Mhz encoder clock.
input rst_n ; // Asynchronous reset.yi
input[0:15] tx_dword ; // Input data word transmit.
input tx_csw ; // "tx_dword" has command or status word.
input tx_dw ; // "tx_dword" has data word.
output tx_busy ; // Encoder is not ready to accept next word.
output tx_data ; // Serial transmit data output.
output tx_dval ; // Indicates data on "tx_data" isvalid.
附件程序:
//=============================================================================
moduledecoder_1553 (
// Clock and Reset
dec_clk ,
rst_n ,
// Inputs
rx_data ,
// Outputs
rx_dword ,
rx_dval ,
rx_csw ,
rx_dw ,
rx_perr
) ;
input dec_clk ; // 8Mhz decoder clock.
input rst_n ; // Asynchronous reset.
input rx_data ; // Serial transmit data input.
output[0:15] rx_dword ; // Output data word receive.
output rx_dval ; // Indicates data on "rx_data" isvalid.
output rx_csw ; // "rx_dword" has command orstatus word.
output rx_dw ; // "rx_dword" has data word.
output rx_perr ; // Indicates parity error in"rx_dword".
reg[0:15] rx_dword ;
reg rx_dval ;
reg rx_csw ;
reg rx_dw ;
reg rx_perr ;
reg[0:23] sync_sftreg ;
reg[0:4] data_sftreg ;
reg cnt_enb ;
reg[7:0] cnt ;
reg[0:16] dword_int ;
reg sync_csw_reg ;
reg sync_dw_reg ;
wire sync_edge ;
wire data_edge ;
wire sync_csw ;
wire sync_dw ;
wire data_sample ;
wire parity ;
// Shiftin the serial data through shift registrs.
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n ) begin
data_sftreg <= 5'd0 ;
sync_sftreg <= 24'd0 ;
end
else begin
data_sftreg <={data_sftreg[1:4],rx_data} ;
sync_sftreg <={sync_sftreg[1:23],data_sftreg[0]} ;
end
end
//Detect transitions.
assigndata_edge = data_sftreg[3] ^ data_sftreg[4];
//Detect sync pattern for command and status word
assignsync_csw = (sync_sftreg == 24'hFFF_000) & data_edge ;
//Detect sync pattern for data word
assignsync_dw = (sync_sftreg == 24'h000_FFF)& data_edge ;
// Countnumber of clocks to get complete word after
//detecting the sync pattern
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n )
cnt_enb <= 1'b0 ;
else if (sync_csw || sync_dw)
cnt_enb <= 1'b1 ;
else if (cnt == 'd131)
cnt_enb <= 1'b0 ;
else
cnt_enb <= cnt_enb ;
end
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n )
cnt <= 8'hFF ;
else if (cnt_enb)
cnt <= cnt + 1 ;
else if (!cnt_enb)
cnt <= 8'hFF ;
else
cnt <= cnt ;
end
// Generatedata sample points.
assigndata_sample = (~cnt[2] & ~cnt[1]& ~cnt[0]) ;
//register data at every sample point through shift register.
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n )
dword_int <= 17'h0000 ;
else if (data_sample && cnt_enb)
dword_int <={dword_int[1:16],~data_sftreg[2]} ;
else if (!cnt_enb)
dword_int <= 17'h0000 ;
else
dword_int <= dword_int ;
end
//Register command and status sync patter type till the end
// ofdata word.
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n )
sync_csw_reg <= 1'b0 ;
else if (sync_csw)
sync_csw_reg <= 1'b1 ;
else if (cnt == 'd132)
sync_csw_reg <= 1'b0 ;
else
sync_csw_reg <= sync_csw_reg ;
end
//Register data sync patter type till the end of data word.
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n )
sync_dw_reg <= 1'b0 ;
else if (sync_dw)
sync_dw_reg <= 1'b1 ;
else if (cnt == 'd132)
sync_dw_reg <= 1'b0 ;
else
sync_dw_reg <= sync_dw_reg ;
end
//Register the parallel data word and control outputs.
always@(posedge dec_clk or negedge rst_n) begin
if (!rst_n ) begin
rx_dword <= 16'h0000 ;
rx_dval <= 1'b0 ;
rx_perr <= 1'b0 ;
rx_csw <= 1'b0 ;
rx_dw <= 1'b0 ;
end
else if (cnt == 'd131) begin
rx_dword <= dword_int[0:15] ;
rx_dval <= 1'b1 ;
rx_perr <= ((^dword_int[0:15]) != dword_int[16]) ; //odd
rx_csw <= sync_csw_reg ;
rx_dw <= sync_dw_reg ;
end
else begin
rx_dword <= 16'h0000 ;
rx_dval <= 1'b0 ;
rx_perr <= 1'b0 ;
rx_csw <= 1'b0 ;
rx_dw <= 1'b0 ;
end
end
endmodule
// =============================================================================
moduleencoder_1553 (
// Clock and Reset
enc_clk ,
rst_n ,
// Inputs
tx_dword ,
tx_csw ,
tx_dw ,
// Outputs
tx_busy ,
tx_data ,
tx_dval
) ;
input enc_clk ; // 2Mhz encoder clock.
input rst_n ; // Asynchronous reset.yi
input[0:15] tx_dword ; // Input data word transmit.
input tx_csw ; // "tx_dword" has command orstatus word.
input tx_dw ; // "tx_dword" has data word.
output tx_busy ; // Encoder is not ready to accept next word.
output tx_data ; // Serial transmit data output.
output tx_dval ; // Indicates data on "tx_data" isvalid.
reg cnt_en ;
reg cnt_en_reg ;
reg[5:0] busy_cnt ;
reg[0:16] data_reg ;
reg [5:0] sync_bits ;
reg tx_data ;
reg tx_dval ;
wire parity ;
wire[0:40] enc_data ;
wire data_out ;
// Countnumber of clocks required to encode and serialize
// theinput data.
always@(posedge enc_clk or negedge rst_n) begin
if (!rst_n)
cnt_en <= 1'b0 ;
else if (tx_csw || tx_dw )
cnt_en <= 1'b1 ;
else if (busy_cnt == 'd38)
cnt_en <= 1'b0 ;
else
cnt_en <= cnt_en ;
end
always@(posedge enc_clk or negedge rst_n) begin
if (!rst_n)
cnt_en_reg <= 1'b0 ;
else
cnt_en_reg <= cnt_en ;
end
always@(posedge enc_clk or negedge rst_n) begin
if (!rst_n)
busy_cnt <= 'd0 ;
else if (cnt_en)
busy_cnt <= busy_cnt + 1 ;
else
busy_cnt <= 'd0 ;
end
//Generate busy signal for the user interface.
assigntx_busy = cnt_en ;
//Generate parity for the given 16 bit word data.
assignparity = ^(tx_dword) ;
//Register input data word along with generated parity.
always@(posedge enc_clk or negedge rst_n) begin
if (!rst_n)
data_reg <= 17'h0000 ;
else if ((tx_csw || tx_dw) &&!cnt_en)
data_reg <= {tx_dword, parity} ;
else if (!cnt_en )
data_reg <= 17'h0000 ;
else
data_reg <= data_reg ;
end
//Determine the sync pattern based on word type.
always@(posedge enc_clk or negedge rst_n) begin
if (!rst_n)
sync_bits <= 6'b000_000 ;
else if (tx_csw)
sync_bits <= 6'b111_000 ;
else if (tx_dw)
sync_bits <= 6'b000_111 ;
else
sync_bits <= sync_bits ;
end
//Generate Manchester encoded data for combined sync pattern,
// dataword and parity.
assignenc_data = { sync_bits,
data_reg[0], ~data_reg[0],
data_reg[1], ~data_reg[1],
data_reg[2], ~data_reg[2],
data_reg[3], ~data_reg[3],
data_reg[4], ~data_reg[4],
data_reg[5], ~data_reg[5],
data_reg[6], ~data_reg[6],
data_reg[7], ~data_reg[7],
data_reg[8], ~data_reg[8],
data_reg[9], ~data_reg[9],
data_reg[10],~data_reg[10],
data_reg[11],~data_reg[11],
data_reg[12],~data_reg[12],
data_reg[13], ~data_reg[13],
data_reg[14],~data_reg[14],
data_reg[15],~data_reg[15],
data_reg[16],~data_reg[16], 1'b0 } ;
//Serialize the encoded data
always@(posedge enc_clk or negedge rst_n) begin
if (!rst_n) begin
tx_dval <= 1'b0 ;
tx_data <= 1'b0 ;
end
else if (cnt_en || cnt_en_reg) begin
tx_dval <= 1'b1 ;
tx_data <= enc_data[busy_cnt] ;
end
else begin
tx_dval <= 1'b0 ;
tx_data <= 1'b0 ;
end
end
endmodule
//=============================================================================
仿真程序:
//=============================================================================
moduletest_1553 ();
reg enc_clk ;
reg dec_clk ;
reg rst_n ;
reg[15:0] tx_dword ;
reg tx_csw ;
reg tx_dw ;
wire tx_data ;
wire tx_dval ;
wire serial_data ;
encoder_1553u1_encoder (
// Clock and Reset
.enc_clk ( enc_clk ),
.rst_n ( rst_n ),
// Inputs
.tx_dword ( tx_dword ),
.tx_csw ( tx_csw ),
.tx_dw ( tx_dw ),
// Outputs
.tx_busy ( ),
.tx_data ( tx_data ),
.tx_dval ( tx_dval )
) ;
assignserial_data = (tx_data & tx_dval) ;
decoder_1553u1_decoder (
// Clock and Reset
.dec_clk ( dec_clk ),
.rst_n ( rst_n ),
// Inputs
.rx_data ( serial_data ),
// Outputs
.rx_dword ( ),
.rx_dval ( ),
.rx_csw ( ),
.rx_dw ( ),
.rx_perr ( )
) ;
initialbegin
enc_clk <= 1'b0 ;
dec_clk <= 1'b0 ;
rst_n <= 1'b0 ;
tx_dword <= 16'd0 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
end
always#500 enc_clk = ~enc_clk ;
always#125 dec_clk = ~dec_clk ;
initialbegin
repeat (10) @(posedge enc_clk) ;
rst_n <= 1'b1 ;
repeat (39) @(posedge enc_clk) ;
tx_dword <= 16'h5555 ;
tx_csw <= 1'b1 ;
tx_dw <= 1'b0 ;
repeat (1) @(posedge enc_clk) ;
tx_dword <= 16'h0000 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
repeat (39) @(posedge enc_clk) ;
tx_dword <= 16'hABCD ;
tx_csw <= 1'b1 ;
tx_dw <= 1'b0 ;
repeat (1) @(posedge enc_clk) ;
tx_dword <= 16'h0000 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
repeat (39) @(posedge enc_clk) ;
tx_dword <= 16'hFFFF ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b1 ;
repeat (1) @(posedge enc_clk) ;
tx_dword <= 16'h0000 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
repeat (39) @(posedge enc_clk) ;
tx_dword <= 16'h1234 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b1 ;
repeat (1) @(posedge enc_clk) ;
tx_dword <= 16'h0000 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
repeat (5) @(posedge enc_clk) ;
repeat (39) @(posedge enc_clk) ;
tx_dword <= 16'h5678 ;
tx_csw <= 1'b1 ;
tx_dw <= 1'b0 ;
repeat (1) @(posedge enc_clk) ;
tx_dword <= 16'h0000 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
repeat (5) @(posedge enc_clk) ;
repeat (39) @(posedge enc_clk) ;
tx_dword <= 16'hAAAA ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b1 ;
repeat (1) @(posedge enc_clk) ;
tx_dword <= 16'h0000 ;
tx_csw <= 1'b0 ;
tx_dw <= 1'b0 ;
repeat (100) @(posedge enc_clk) ;
$display("---INFO : Simulation Ended,Check waveform");
$finish ;
end
endmodule