CAN协议FPGA篇
2023-12-26 22:53:50
一.引言
????????CAN(Controller Area Network)总线,即控制器局域网总线,是一种功能丰富的车用总线标准。该协议最初是由德国博世(Bosch)公司在1983年制定的,之后在美国密歇根州底特律举行的汽车工程师协会(SAE) 会议上正式发布推出。1987年,Intel公司推出的首款CAN总线芯片(82526)上市销售。1991年,奔驰汽车发布的第一款基于CAN总线的多路布线系统汽车——W140量产,1993年,国际标准化组织(ISO)发布了CAN标准ISO 11898。后来CAN标准被重新编译分成两个部分:ISO 11898-1涵盖了数据链路层,ISO 11898-2涵盖了高速CAN总线的物理层,所以ISO 11898是针对通信速率为125Kbps~1Mbps的高速通信标准。与此同时,还有另一个标准ISO 11519是针对通信速率为125Kbps以下的低速CAN通信标准,不过ISO 11519后来被此后发布的ISO 11898-3:2006所替代。当然,现在新版的CAN总线芯片支持的通信速率最高波特率也已达5Mbps。
?
二.CAN总线协议
(1) CAN总线协议图? ? ? ?
?
(2)标准协议数据解析图?
?
?(3)拓展协议信息解析图
?
?
(4)CAN总线协议传输图
?
三.FPGA框架设计
(1)控制器设计框图?
?
(2)CAN系统设计框图
?
四.FPGA代码?
(1)整体控制?
//连接其他模块
//寄存器模块
can_registers i_can_registers (
.clk(clk_i),
.rst(rst),
.cs(cs),
.we(we),
….)
//连接 Bit Timing Logic 模块
can_btl i_can_btl (
.clk(clk_i),
.rst(rst),
.rx(rx_i),
…)
//连接 Bit Streaming Processor 模块
can_bsp i_can_bsp(
.clk(clk_i),
.rst(rst),
…)
//选择输出 fifo 或者寄存器中的数据模式
always @ (extended_mode or addr or reset_mode)
begin
if (extended_mode & (~reset_mode) & ((addr >= 8'd16) && (addr <= 8'd28)) | (~extended_mode)
& ((addr >= 8'd20) && (addr <= 8'd29)))
data_out_fifo_selected <= 1'b1;
else
data_out_fifo_selected <= 1'b0;
end
//输出数据
always @ (posedge clk_i)
begin
if (cs & (~we))
begin
if (data_out_fifo_selected)
data_out <=#Tp data_out_fifo;
else
data_out <=#Tp data_out_regs;
end
end
// 锁存地址
always @ (negedge clk_i or posedge rst)
begin
if (rst)
addr_latched <= 8'h0;
else if (ale_i)
addr_latched <=#Tp port_0_io;
end
// 产生延迟信号
always @ (posedge clk_i or posedge rst)
begin
if (rst)
begin
wr_i_q <= 1'b0;
rd_i_q <= 1'b0;
end
else
begin
wr_i_q <=#Tp wr_i;
rd_i_q <=#Tp rd_i;
end
end
//组合得到多个信号,如片选、重起等
assign cs = ((wr_i & (~wr_i_q)) | (rd_i & (~rd_i_q))) & cs_can_i;
assign rst = rst_i;
assign we = wr_i;
assign addr = addr_latched;
assign data_in = port_0_io;
assign port_0_io = (cs_can_i & rd_i)? data_out : 8'hz;
?(2)寄存器控制模块
always @ (posedge clk)
begin
tx_successful_q <=#Tp tx_successful;
overrun_q <=#Tp overrun;
transmit_buffer_status_q <=#Tp transmit_buffer_status;
info_empty_q <=#Tp info_empty;
error_status_q <=#Tp error_status;
node_bus_off_q <=#Tp node_bus_off;
node_error_passive_q <=#Tp node_error_passive;
end
…
//模式寄存器
wire [0:0] mode;
wire [4:1] mode_basic;
wire [3:1] mode_ext;
wire receive_irq_en_basic;
wire transmit_irq_en_basic;
wire error_irq_en_basic;
wire overrun_irq_en_basic;
can_register_asyn_syn #(1, 1'h1) MODE_REG0(
.data_in(data_in[0]),
.data_out(mode[0]),
.we(we_mode),
.clk(clk),
.rst(rst),
.rst_sync(set_reset_mode)
);
can_register_asyn #(4, 0) MODE_REG_BASIC(
.data_in(data_in[4:1]),
.data_out(mode_basic[4:1]),
.we(we_mode),
.clk(clk),
.rst(rst)
);
can_register_asyn #(3, 0) MODE_REG_EXT(
.data_in(data_in[3:1]),
.data_out(mode_ext[3:1]),
.we(we_mode & reset_mode),
.clk(clk),
.rst(rst)
);
//命令寄存器
wire [4:0] command;
can_register_asyn_syn #(1, 1'h0) COMMAND_REG0(
.data_in(data_in[0]),
.data_out(command[0]),
.we(we_command),
.clk(clk),
.rst(rst),
.rst_sync(tx_request & sample_point)
);
can_register_asyn_syn #(1, 1'h0) COMMAND_REG1(
.data_in(data_in[1]),
.data_out(command[1]),
.we(we_command),
.clk(clk),
.rst(rst),
.rst_sync(abort_tx & ~transmitting)
);
can_register_asyn_syn #(2, 2'h0) COMMAND_REG(
.data_in(data_in[3:2]),
.data_out(command[3:2]),
.we(we_command),
.clk(clk),
.rst(rst),
.rst_sync(|command[3:2])
);
can_register_asyn_syn #(1, 1'h0) COMMAND_REG4(
.data_in(data_in[4]),
.data_out(command[4]),
.we(we_command),
.clk(clk),
.rst(rst),
.rst_sync(tx_successful & (~tx_successful_q) | abort_tx)
);
assign self_rx_request = command[4] & (~command[0]);
assign clear_data_overrun = command[3];
assign release_buffer = command[2];
assign abort_tx = command[1] & (~command[0]) & (~command[4]);
assign tx_request = command[0] | command[4];
always @ (posedge clk or posedge rst)
begin
if (rst)
single_shot_transmission <= 1'b0;
else if (we_command & data_in[1] & (data_in[1] | data_in[4]))
single_shot_transmission <=#Tp 1'b1;
else if (tx_successful & (~tx_successful_q))
single_shot_transmission <=#Tp 1'b0;
end
//状态寄存器
wire [7:0] status;
assign status[7] = node_bus_off;
assign status[6] = error_status;
assign status[5] = transmit_status;
assign status[4] = receive_status;
assign status[3] = transmission_complete;
assign status[2] = transmit_buffer_status;
assign status[1] = overrun_status;
assign status[0] = receive_buffer_status;
always @ (posedge clk or posedge rst)
begin
if (rst)
transmission_complete <= 1'b1;
else if (tx_successful & (~tx_successful_q) | abort_tx)
transmission_complete <=#Tp 1'b1;
else if (tx_request)
transmission_complete <=#Tp 1'b0;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
transmit_buffer_status <= 1'b1;
else if (tx_request)
transmit_buffer_status <=#Tp 1'b0;
else if (~need_to_tx)
transmit_buffer_status <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overrun_status <= 1'b0;
else if (overrun & (~overrun_q))
overrun_status <=#Tp 1'b1;
else if (clear_data_overrun)
overrun_status <=#Tp 1'b0;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
receive_buffer_status <= 1'b0;
else if (release_buffer)
receive_buffer_status <=#Tp 1'b0;
else if (~info_empty)
receive_buffer_status <=#Tp 1'b1;
end
//总线时序寄存器 1
wire [7:0] bus_timing_0;
can_register #(8) BUS_TIMING_0_REG(
.data_in(data_in),
.data_out(bus_timing_0),
.we(we_bus_timing_0),
.clk(clk)
);
assign baud_r_presc = bus_timing_0[5:0];
assign sync_jump_width = bus_timing_0[7:6];
//总线时序寄存器 2
wire [7:0] bus_timing_1;
can_register #(8) BUS_TIMING_1_REG(
.data_in(data_in),
.data_out(bus_timing_1),
.we(we_bus_timing_1),
.clk(clk)
);
assign time_segment1 = bus_timing_1[3:0];
assign time_segment2 = bus_timing_1[6:4];
assign triple_sampling = bus_timing_1[7];
//错误提示寄存器
can_register_asyn #(8, 96) ERROR_WARNING_REG(
.data_in(data_in),
.data_out(error_warning_limit),
.we(we_error_warning_limit),
.clk(clk),
.rst(rst)
);
//时钟分频寄存器
wire [7:0] clock_divider;
wire clock_off;
wire [2:0] cd;
reg [2:0] clkout_div;
reg [2:0] clkout_cnt;
reg clkout_tmp;
//reg clkout;
can_register #(1) CLOCK_DIVIDER_REG_7(
.data_in(data_in[7]),
.data_out(clock_divider[7]),
.we(we_clock_divider_hi),
.clk(clk)
);
assign clock_divider[6:4] = 3'h0;
can_register #(1) CLOCK_DIVIDER_REG_3(
.data_in(data_in[3]),
.data_out(clock_divider[3]),
.we(we_clock_divider_hi),
.clk(clk)
);
can_register #(3) CLOCK_DIVIDER_REG_LOW(
.data_in(data_in[2:0]),
.data_out(clock_divider[2:0]),
.we(we_clock_divider_low),
.clk(clk)
);
assign extended_mode = clock_divider[7];
assign clock_off = clock_divider[3];
assign cd[2:0] = clock_divider[2:0];
always @ (cd)
begin
case (cd) // synopsys_full_case synopsys_paralel_case
3'b000 : clkout_div <= 0;
3'b001 : clkout_div <= 1;
3'b010 : clkout_div <= 2;
3'b011 : clkout_div <= 3;
3'b100 : clkout_div <= 4;
3'b101 : clkout_div <= 5;
3'b110 : clkout_div <= 6;
3'b111 : clkout_div <= 0;
endcase
end
always @ (posedge clk or posedge rst)
begin
if (rst)
clkout_cnt <= 3'h0;
else if (clkout_cnt == clkout_div)
clkout_cnt <=#Tp 3'h0;
else
clkout_cnt <= clkout_cnt + 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
clkout_tmp <= 1'b0;
else if (clkout_cnt == clkout_div)
clkout_tmp <=#Tp ~clkout_tmp;
end
always @ (cd or clkout_tmp or clock_off)
begin
if (clock_off)
clkout <=#Tp 1'b1;
else
clkout <=#Tp clkout_tmp;
end
assign clkout = clock_off ? 1'b1 : ((&cd)? clk : clkout_tmp);
//从寄存器中读数据
always @ ( addr or read or extended_mode or mode or bus_timing_0 or bus_timing_1 or clock_divider
or
acceptance_code_0 or acceptance_code_1 or acceptance_code_2 or acceptance_code_3
or
acceptance_mask_0 or acceptance_mask_1 or acceptance_mask_2 or acceptance_mask_3
or
reset_mode or tx_data_0 or tx_data_1 or tx_data_2 or tx_data_3 or tx_data_4 or
tx_data_5 or tx_data_6 or tx_data_7 or tx_data_8 or tx_data_9 or status or
error_warning_limit or rx_err_cnt or tx_err_cnt or irq_en_ext or irq_reg or
mode_ext or
arbitration_lost_capture or rx_message_counter or mode_basic or
error_capture_code
)
begin
if(read) // read
begin
if (extended_mode) // EXTENDED mode (Different register map depends on mode)
begin
case(addr)
8'd0 : data_out_tmp <= {4'b0000, mode_ext[3:1], mode[0]};
8'd1 : data_out_tmp <= 8'h0;
8'd2 : data_out_tmp <= status;
8'd3 : data_out_tmp <= irq_reg;
8'd4 : data_out_tmp <= irq_en_ext;
8'd6 : data_out_tmp <= bus_timing_0;
8'd7 : data_out_tmp <= bus_timing_1;
8'd11 : data_out_tmp <= {3'h0, arbitration_lost_capture[4:0]};
8'd12 : data_out_tmp <= error_capture_code;
8'd13 : data_out_tmp <= error_warning_limit;
8'd14 : data_out_tmp <= rx_err_cnt;
8'd15 : data_out_tmp <= tx_err_cnt;
8'd16 : data_out_tmp <= acceptance_code_0;
8'd17 : data_out_tmp <= acceptance_code_1;
8'd18 : data_out_tmp <= acceptance_code_2;
8'd19 : data_out_tmp <= acceptance_code_3;
8'd20 : data_out_tmp <= acceptance_mask_0;
8'd21 : data_out_tmp <= acceptance_mask_1;
8'd22 : data_out_tmp <= acceptance_mask_2;
8'd23 : data_out_tmp <= acceptance_mask_3;
8'd24 : data_out_tmp <= 8'h0;
8'd25 : data_out_tmp <= 8'h0;
8'd26 : data_out_tmp <= 8'h0;
8'd27 : data_out_tmp <= 8'h0;
8'd28 : data_out_tmp <= 8'h0;
8'd29 : data_out_tmp <= {1'b0, rx_message_counter};
8'd31 : data_out_tmp <= clock_divider;
default: data_out_tmp <= 8'h0;
endcase
end
else // BASIC mode
begin
case(addr)
8'd0 : data_out_tmp <= {3'b001, mode_basic[4:1], mode[0]};
8'd1 : data_out_tmp <= 8'hff;
8'd2 : data_out_tmp <= status;
8'd3 : data_out_tmp <= {4'hf, irq_reg[3:0]};
8'd4 : data_out_tmp <= reset_mode? acceptance_code_0 : 8'hff;
8'd5 : data_out_tmp <= reset_mode? acceptance_mask_0 : 8'hff;
8'd6 : data_out_tmp <= reset_mode? bus_timing_0 : 8'hff;
8'd7 : data_out_tmp <= reset_mode? bus_timing_1 : 8'hff;
8'd10 : data_out_tmp <= reset_mode? 8'hff : tx_data_0;
8'd11 : data_out_tmp <= reset_mode? 8'hff : tx_data_1;
8'd12 : data_out_tmp <= reset_mode? 8'hff : tx_data_2;
8'd13 : data_out_tmp <= reset_mode? 8'hff : tx_data_3;
8'd14 : data_out_tmp <= reset_mode? 8'hff : tx_data_4;
8'd15 : data_out_tmp <= reset_mode? 8'hff : tx_data_5;
8'd16 : data_out_tmp <= reset_mode? 8'hff : tx_data_6;
8'd17 : data_out_tmp <= reset_mode? 8'hff : tx_data_7;
8'd18 : data_out_tmp <= reset_mode? 8'hff : tx_data_8;
8'd19 : data_out_tmp <= reset_mode? 8'hff : tx_data_9;
8'd31 : data_out_tmp <= clock_divider;
default: data_out_tmp <= 8'h0;
endcase
end
end
else
data_out_tmp <= 8'h0;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
data_out <= 0;
else if (read)
data_out <=#Tp data_out_tmp;
end
(3)时序逻辑模块
//计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
clk_cnt <= 0;
else if (clk_cnt == (preset_cnt-1))
clk_cnt <=#Tp 0;
else
clk_cnt <=#Tp clk_cnt + 1;
end
//产生定义波特率的一般使能信号
always @ (posedge clk or posedge rst)
begin
if (rst)
clk_en <= 1'b0;
else if (clk_cnt == (preset_cnt-1))
clk_en <=#Tp 1'b1;
else
clk_en <=#Tp 1'b0;
end
//改变状态
assign go_sync = clk_en & (seg2 & (~hard_sync) & (~resync) & ((quant_cnt == time_segment2)));
assign go_seg1 = clk_en & (sync | hard_sync | (resync & seg2 & sync_window) | (resync_latched
& sync_window));
assign go_seg2 = clk_en & (seg1 & (~hard_sync) & (quant_cnt == (time_segment1 + delay)));
//当探测到 SJW 字段的沿时,同步请求被锁存并被执行
always @ (posedge clk or posedge rst)
begin
if (rst)
resync_latched <= 1'b0;
else if (resync & seg2 & (~sync_window))
resync_latched <=#Tp 1'b1;
else if (go_seg1)
resync_latched <= 1'b0;
end
//同步的平台或片断
always @ (posedge clk or posedge rst)
begin
if (rst)
sync <= 0;
else if (go_sync)
sync <=#Tp 1'b1;
else if (go_seg1)
sync <=#Tp 1'b0;
end
assign tx_point = go_sync;
//片断 seg1
always @ (posedge clk or posedge rst)
begin
if (rst)
seg1 <= 1;
else if (go_seg1)
seg1 <=#Tp 1'b1;
else if (go_seg2)
seg1 <=#Tp 1'b0;
end
//片断 seg2
always @ (posedge clk or posedge rst)
begin
if (rst)
seg2 <= 0;
else if (go_seg2)
seg2 <=#Tp 1'b1;
else if (go_sync | go_seg1)
seg2 <=#Tp 1'b0;
end
//Quant 计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
quant_cnt <= 0;
else if (go_sync | go_seg1 | go_seg2)
quant_cnt <=#Tp 0;
else if (clk_en)
quant_cnt <=#Tp quant_cnt + 1'b1;
end
//当探测到后沿时,片断 seg1 被延时
begin
if (rst)
delay <= 0;
else if (clk_en & resync & seg1)
delay <=#Tp (quant_cnt > sync_jump_width)? (sync_jump_width + 1) : (quant_cnt + 1);
else if (go_sync | go_seg1)
delay <=#Tp 0;
end
//如果沿出现在这个窗口中,相位的错误将得到完全的补偿
assign sync_window = ((time_segment2 - quant_cnt) < ( sync_jump_width + 1));
//数据采样
always @ (posedge clk or posedge rst)
begin
if (rst)
sample <= 2'b11;
else if (clk_en)
sample <= {sample[0], rx};
end
//获得使能后,采样完成
always @ (posedge clk or posedge rst)
begin
if (rst)
begin
sampled_bit <= 1;
sampled_bit_q <= 1;
sample_point <= 0;
end
else if (clk_en & (~hard_sync))
begin
if (seg1 & (quant_cnt == (time_segment1 + delay)))
begin
sample_point <=#Tp 1;
sampled_bit_q <=#Tp sampled_bit;
if (triple_sampling)
sampled_bit <=#Tp (sample[0] & sample[1]) | ( sample[0] & rx) | (sample[1] & rx);
else
sampled_bit <=#Tp rx;
end
end
else
sample_point <=#Tp 0;
end
//阻塞同步
always @ (posedge clk or posedge rst)
begin
if (rst)
sync_blocked <=#Tp 1'b0;
else if (clk_en)
begin
if (hard_sync | resync)
sync_blocked <=#Tp 1'b1;
else if (seg2 & quant_cnt == time_segment2)
sync_blocked <=#Tp 1'b0;
end
end
//阻塞重同步直到收到开始信号
/* Blocking resynchronization until reception starts (needed because after reset mode exits
we are waiting for
end-of-frame and interframe. No resynchronization is needed meanwhile). */
always @ (posedge clk or posedge rst)
begin
if (rst)
resync_blocked <=#Tp 1'b1;
else if (reset_mode)
resync_blocked <=#Tp 1'b1;
else if (hard_sync)
resync_blocked <=#Tp 1'b0;
end
?(4)位数据流处理器模块
//各个数据收发的起始状态
//接收数据的 idle 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_idle <= 1'b0;
else if (reset_mode | go_rx_id1 | error_frame)
rx_idle <=#Tp 1'b0;
else if (go_rx_idle)
rx_idle <=#Tp 1'b1;
end
// 接收数据的 id1 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_id1 <= 1'b0;
else if (reset_mode | go_rx_rtr1 | error_frame)
rx_id1 <=#Tp 1'b0;
else if (go_rx_id1)
rx_id1 <=#Tp 1'b1;
end
//接收数据的 rtr1 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_rtr1 <= 1'b0;
else if (reset_mode | go_rx_ide | error_frame)
rx_rtr1 <=#Tp 1'b0;
else if (go_rx_rtr1)
rx_rtr1 <=#Tp 1'b1;
end
//接收数据的 ide 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_ide <= 1'b0;
else if (reset_mode | go_rx_r0 | go_rx_id2 | error_frame)
rx_ide <=#Tp 1'b0;
else if (go_rx_ide)
rx_ide <=#Tp 1'b1;
end
//接收数据的 id2 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_id2 <= 1'b0;
else if (reset_mode | go_rx_rtr2 | error_frame)
rx_id2 <=#Tp 1'b0;
else if (go_rx_id2)
rx_id2 <=#Tp 1'b1;
end
//接收数据的 rtr2 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_rtr2 <= 1'b0;
else if (reset_mode | go_rx_r1 | error_frame)
rx_rtr2 <=#Tp 1'b0;
else if (go_rx_rtr2)
rx_rtr2 <=#Tp 1'b1;
end
//接收数据的 r0 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_r1 <= 1'b0;
else if (reset_mode | go_rx_r0 | error_frame)
rx_r1 <=#Tp 1'b0;
else if (go_rx_r1)
rx_r1 <=#Tp 1'b1;
end
//接收数据的 r0 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_r0 <= 1'b0;
else if (reset_mode | go_rx_dlc | error_frame)
rx_r0 <=#Tp 1'b0;
else if (go_rx_r0)
rx_r0 <=#Tp 1'b1;
end
//接收数据的 dlc 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_dlc <= 1'b0;
else if (reset_mode | go_rx_data | go_rx_crc | error_frame)
rx_dlc <=#Tp 1'b0;
else if (go_rx_dlc)
rx_dlc <=#Tp 1'b1;
end
//接收数据状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_data <= 1'b0;
else if (reset_mode | go_rx_crc | error_frame)
rx_data <=#Tp 1'b0;
else if (go_rx_data)
rx_data <=#Tp 1'b1;
end
// 接收数据的 crc 状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_crc <= 1'b0;
else if (reset_mode | go_rx_crc_lim | error_frame)
rx_crc <=#Tp 1'b0;
else if (go_rx_crc)
rx_crc <=#Tp 1'b1;
end
//接收数据 crc 分隔符状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_crc_lim <= 1'b0;
else if (reset_mode | go_rx_ack | error_frame)
rx_crc_lim <=#Tp 1'b0;
else if (go_rx_crc_lim)
rx_crc_lim <=#Tp 1'b1;
end
//接收数据的应答状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_ack <= 1'b0;
else if (reset_mode | go_rx_ack_lim | error_frame)
rx_ack <=#Tp 1'b0;
else if (go_rx_ack)
rx_ack <=#Tp 1'b1;
end
//接收数据分隔符状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_ack_lim <= 1'b0;
else if (reset_mode | go_rx_eof | error_frame)
rx_ack_lim <=#Tp 1'b0;
else if (go_rx_ack_lim)
rx_ack_lim <=#Tp 1'b1;
end
//接收数据的帧尾状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_eof <= 1'b0;
else if (go_rx_inter | error_frame | go_overload_frame)
rx_eof <=#Tp 1'b0;
else if (go_rx_eof)
rx_eof <=#Tp 1'b1;
end
//帧间空间状态
always @ (posedge clk or posedge rst)
begin
if (rst)
rx_inter <= 1'b0;
else if (reset_mode | go_rx_idle | go_rx_id1 | go_overload_frame | go_error_frame)
rx_inter <=#Tp 1'b0;
else if (go_rx_inter)
rx_inter <=#Tp 1'b1;
end
// ID 寄存器
always @ (posedge clk or posedge rst)
begin
if (rst)
id <= 0;
else if (sample_point & (rx_id1 | rx_id2) & (~bit_de_stuff))
id <=#Tp {id[27:0], sampled_bit};
end
// rtr1 位
always @ (posedge clk or posedge rst)
begin
if (rst)
rtr1 <= 0;
else if (sample_point & rx_rtr1 & (~bit_de_stuff))
rtr1 <=#Tp sampled_bit;
end
// rtr2 位
always @ (posedge clk or posedge rst)
begin
if (rst)
rtr2 <= 0;
else if (sample_point & rx_rtr2 & (~bit_de_stuff))
rtr2 <=#Tp sampled_bit;
end
// ide 位
always @ (posedge clk or posedge rst)
begin
if (rst)
ide <= 0;
else if (sample_point & rx_ide & (~bit_de_stuff))
ide <=#Tp sampled_bit;
end
// 获得数据长度
always @ (posedge clk or posedge rst)
begin
if (rst)
data_len <= 0;
else if (sample_point & rx_dlc & (~bit_de_stuff))
data_len <=#Tp {data_len[2:0], sampled_bit};
end
// 获得数据
always @ (posedge clk or posedge rst)
begin
if (rst)
tmp_data <= 0;
else if (sample_point & rx_data & (~bit_de_stuff))
tmp_data <=#Tp {tmp_data[6:0], sampled_bit};
end
always @ (posedge clk or posedge rst)
begin
if (rst)
write_data_to_tmp_fifo <= 0;
else if (sample_point & rx_data & (~bit_de_stuff) & (&bit_cnt[2:0]))
write_data_to_tmp_fifo <=#Tp 1'b1;
else
write_data_to_tmp_fifo <=#Tp 0;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
byte_cnt <= 0;
else if (write_data_to_tmp_fifo)
byte_cnt <=#Tp byte_cnt + 1;
else if (reset_mode | (sample_point & go_rx_crc_lim))
byte_cnt <=#Tp 0;
end
always @ (posedge clk)
begin
if (write_data_to_tmp_fifo)
tmp_fifo[byte_cnt] <=#Tp tmp_data;
end
// CRC 校验数据
always @ (posedge clk or posedge rst)
begin
if (rst)
crc_in <= 0;
else if (sample_point & rx_crc & (~bit_de_stuff))
crc_in <=#Tp {crc_in[13:0], sampled_bit};
end
//计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
bit_cnt <= 0;
else if (go_rx_id1 | go_rx_id2 | go_rx_dlc | go_rx_data | go_rx_crc |
go_rx_ack | go_rx_eof | go_rx_inter | go_error_frame | go_overload_frame)
bit_cnt <=#Tp 0;
else if (sample_point & (~bit_de_stuff))
bit_cnt <=#Tp bit_cnt + 1'b1;
end
//帧尾计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
eof_cnt <= 0;
else if (sample_point)
begin
if (reset_mode | go_rx_inter | go_error_frame | go_overload_frame)
eof_cnt <=#Tp 0;
else if (rx_eof)
eof_cnt <=#Tp eof_cnt + 1'b1;
end
end
// 使能位填充
always @ (posedge clk or posedge rst)
begin
if (rst)
bit_stuff_cnt_en <= 1'b0;
else if (bit_de_stuff_set)
bit_stuff_cnt_en <=#Tp 1'b1;
else if (bit_de_stuff_reset)
bit_stuff_cnt_en <=#Tp 1'b0;
end
//位填充计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
bit_stuff_cnt <= 1;
else if (bit_de_stuff_reset)
bit_stuff_cnt <=#Tp 1;
else if (sample_point & bit_stuff_cnt_en)
begin
if (bit_stuff_cnt == 5)
bit_stuff_cnt <=#Tp 1;
else if (sampled_bit == sampled_bit_q)
bit_stuff_cnt <=#Tp bit_stuff_cnt + 1'b1;
else
bit_stuff_cnt <=#Tp 1;
end
end
// 发送数据的使能位填充
always @ (posedge clk or posedge rst)
begin
if (rst)
bit_stuff_cnt_tx_en <= 1'b0;
else if (bit_de_stuff_set & transmitting)
bit_stuff_cnt_tx_en <=#Tp 1'b1;
else if (bit_de_stuff_reset)
bit_stuff_cnt_tx_en <=#Tp 1'b0;
end
//发送数据的位填充计数
always @ (posedge clk or posedge rst)
begin
if (rst)
bit_stuff_cnt_tx <= 1;
else if (bit_de_stuff_reset)
bit_stuff_cnt_tx <=#Tp 1;
else if (tx_point_q & bit_stuff_cnt_en)
begin
if (bit_stuff_cnt_tx == 5)
bit_stuff_cnt_tx <=#Tp 1;
else if (tx == tx_q)
bit_stuff_cnt_tx <=#Tp bit_stuff_cnt_tx + 1'b1;
else
bit_stuff_cnt_tx <=#Tp 1;
end
end
assign bit_de_stuff = bit_stuff_cnt == 5;
assign bit_de_stuff_tx = bit_stuff_cnt_tx == 5;
//位填充错误
assign stuff_err = sample_point & bit_stuff_cnt_en & bit_de_stuff & (sampled_bit ==
sampled_bit_q);
//产生延迟信号
always @ (posedge clk)
begin
reset_mode_q <=#Tp reset_mode;
node_bus_off_q <=#Tp node_bus_off;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
crc_enable <= 1'b0;
else if (go_crc_enable)
crc_enable <=#Tp 1'b1;
else if (reset_mode | rst_crc_enable)
crc_enable <=#Tp 1'b0;
end
//CRC 校验错误
always @ (posedge clk or posedge rst)
begin
if (rst)
crc_err <= 1'b0;
else if (go_rx_ack)
crc_err <=#Tp crc_in != calculated_crc;
else if (reset_mode | error_frame_ended)
crc_err <=#Tp 1'b0;
end
// 一般错误的条件
assign form_err = sample_point & ( ((~bit_de_stuff) & rx_ide & sampled_bit & (~rtr1)) |
(rx_crc_lim & (~sampled_bit)) | (rx_ack_lim & (~sampled_bit)) | ((eof_cnt < 6) & rx_eof &
(~sampled_bit) & (~tx_state) ) | (& rx_eof & (~sampled_bit) & tx_state));
always @ (posedge clk or posedge rst)
begin
if (rst)
ack_err_latched <= 1'b0;
else if (reset_mode | error_frame_ended | go_overload_frame)
ack_err_latched <=#Tp 1'b0;
else if (ack_err)
ack_err_latched <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
bit_err_latched <= 1'b0;
else if (reset_mode | error_frame_ended | go_overload_frame)
bit_err_latched <=#Tp 1'b0;
else if (bit_err)
bit_err_latched <=#Tp 1'b1;
end
//规则 5
assign rule5 = (~node_error_passive) & bit_err & (error_frame & (error_cnt1 < 7) |
overload_frame & (overload_cnt1 < 7) );
//规则 3
always @ (posedge clk or posedge rst)
begin
if (rst)
rule3_exc1_1 <= 1'b0;
else if (reset_mode | error_flag_over | rule3_exc1_2)
rule3_exc1_1 <=#Tp 1'b0;
else if (transmitter & node_error_passive & ack_err)
rule3_exc1_1 <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
rule3_exc1_2 <= 1'b0;
else if (reset_mode | error_flag_over)
rule3_exc1_2 <=#Tp 1'b0;
else if (rule3_exc1_1)
rule3_exc1_2 <=#Tp 1'b1;
else if ((error_cnt1 < 7) & sample_point & (~sampled_bit))
rule3_exc1_2 <=#Tp 1'b0;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
rule3_exc2 <= 1'b0;
else if (reset_mode | error_flag_over)
rule3_exc2 <=#Tp 1'b0;
else if (transmitter & stuff_err & arbitration_field & sample_point & tx & (~sampled_bit))
rule3_exc2 <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
stuff_err_latched <= 1'b0;
else if (reset_mode | error_frame_ended | go_overload_frame)
stuff_err_latched <=#Tp 1'b0;
else if (stuff_err)
stuff_err_latched <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
form_err_latched <= 1'b0;
else if (reset_mode | error_frame_ended | go_overload_frame)
form_err_latched <=#Tp 1'b0;
else if (form_err)
form_err_latched <=#Tp 1'b1;
end
//接收数据的 CRC 校验
can_crc i_can_crc_rx(
.clk(clk),
.data(sampled_bit),
.enable(crc_enable & sample_point & (~bit_de_stuff)),
.initialize(go_crc_enable),
.crc(calculated_crc)
);
assign no_byte0 = rtr1 | (data_len<1);
assign no_byte1 = rtr1 | (data_len<2);
// 接收数据 FIFO 的写使能
always @ (posedge clk or posedge rst)
begin
if (rst)
wr_fifo <= 1'b0;
else if (reset_wr_fifo)
wr_fifo <=#Tp 1'b0;
else if (go_rx_inter & id_ok & (~error_frame_ended) & ((~tx_state) | self_rx_request))
wr_fifo <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
header_cnt <= 0;
else if (reset_wr_fifo)
header_cnt <=#Tp 0;
else if (wr_fifo & storing_header)
header_cnt <=#Tp header_cnt + 1;
end
//数据计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
data_cnt <= 0;
else if (reset_wr_fifo)
data_cnt <=#Tp 0;
else if (wr_fifo)
data_cnt <=#Tp data_cnt + 1;
end
// 数据的合成并保存到 FIFO 中
always @ (extended_mode or ide or data_cnt or header_cnt or header_len or
storing_header or id or rtr1 or rtr2 or data_len or
tmp_fifo[0] or tmp_fifo[2] or tmp_fifo[4] or tmp_fifo[6] or
tmp_fifo[1] or tmp_fifo[3] or tmp_fifo[5] or tmp_fifo[7])
begin
if (storing_header)
begin
if (extended_mode) // extended mode
begin
if (ide) // extended format
begin
case (header_cnt) // synthesis parallel_case
3'h0 : data_for_fifo <= {1'b1, rtr2, 2'h0, data_len};
3'h1 : data_for_fifo <= id[28:21];
3'h2 : data_for_fifo <= id[20:13];
3'h3 : data_for_fifo <= id[12:5];
3'h4 : data_for_fifo <= {id[4:0], 3'h0};
default: data_for_fifo <= 0;
endcase
end
else // standard format
begin
case (header_cnt) // synthesis parallel_case
3'h0 : data_for_fifo <= {1'b0, rtr1, 2'h0, data_len};
3'h1 : data_for_fifo <= id[10:3];
3'h2 : data_for_fifo <= {id[2:0], 5'h0};
default: data_for_fifo <= 0;
endcase
end
end
else // normal mode
begin
case (header_cnt) // synthesis parallel_case
3'h0 : data_for_fifo <= id[10:3];
3'h1 : data_for_fifo <= {id[2:0], rtr1, data_len};
default: data_for_fifo <= 0;
endcase
end
end
else
data_for_fifo <= tmp_fifo[data_cnt-header_len];
end
// 传输错误帧
always @ (posedge clk or posedge rst)
begin
if (rst)
error_frame <= 1'b0;
else if (reset_mode | error_frame_ended | go_overload_frame)
error_frame <=#Tp 1'b0;
else if (go_error_frame)
error_frame <=#Tp 1'b1;
end
always @ (posedge clk)
begin
if (sample_point)
error_frame_q <=#Tp error_frame;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
error_cnt1 <= 1'b0;
else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)
error_cnt1 <=#Tp 1'b0;
else if (error_frame & tx_point & (error_cnt1 < 7))
error_cnt1 <=#Tp error_cnt1 + 1'b1;
end
assign error_flag_over = ((~node_error_passive) & sample_point & (error_cnt1 == 7) |
node_error_passive & sample_point & (passive_cnt == 5)) & (~enable_error_cnt2);
always @ (posedge clk or posedge rst)
begin
if (rst)
error_flag_over_blocked <= 1'b0;
else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)
error_flag_over_blocked <=#Tp 1'b0;
else if (error_flag_over)
error_flag_over_blocked <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
enable_error_cnt2 <= 1'b0;
else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)
enable_error_cnt2 <=#Tp 1'b0;
else if (error_frame & (error_flag_over & sampled_bit))
enable_error_cnt2 <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
error_cnt2 <= 0;
else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)
error_cnt2 <=#Tp 0;
else if (enable_error_cnt2 & tx_point)
error_cnt2 <=#Tp error_cnt2 + 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
delayed_dominant_cnt <= 0;
else if (reset_mode | enable_error_cnt2 | go_error_frame | enable_overload_cnt2 |
go_overload_frame)
delayed_dominant_cnt <=#Tp 0;
else if (sample_point & (~sampled_bit) & ((error_cnt1 == 7) | (overload_cnt1 == 7)))
delayed_dominant_cnt <=#Tp delayed_dominant_cnt + 1'b1;
end
//被动计数
always @ (posedge clk or posedge rst)
begin
if (rst)
passive_cnt <= 0;
else if (reset_mode | error_frame_ended | go_error_frame | go_overload_frame)
passive_cnt <=#Tp 0;
else if (sample_point & (passive_cnt < 5))
begin
if (error_frame_q & (~enable_error_cnt2) & (sampled_bit == sampled_bit_q))
passive_cnt <=#Tp passive_cnt + 1'b1;
else
passive_cnt <=#Tp 0;
end
end
// 传输超载帧
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_frame <= 1'b0;
else if (reset_mode | overload_frame_ended | go_error_frame)
overload_frame <=#Tp 1'b0;
else if (go_overload_frame)
overload_frame <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_cnt1 <= 1'b0;
else if (reset_mode | overload_frame_ended | go_error_frame | go_overload_frame)
overload_cnt1 <=#Tp 1'b0;
else if (overload_frame & tx_point & (overload_cnt1 < 7))
overload_cnt1 <=#Tp overload_cnt1 + 1'b1;
end
assign overload_flag_over = sample_point & (overload_cnt1 == 7) & (~enable_overload_cnt2);
always @ (posedge clk or posedge rst)
begin
if (rst)
enable_overload_cnt2 <= 1'b0;
else if (reset_mode | overload_frame_ended | go_error_frame | go_overload_frame)
enable_overload_cnt2 <=#Tp 1'b0;
else if (overload_frame & (overload_flag_over & sampled_bit))
enable_overload_cnt2 <=#Tp 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_cnt2 <= 0;
else if (reset_mode | overload_frame_ended | go_error_frame | go_overload_frame)
overload_cnt2 <=#Tp 0;
else if (enable_overload_cnt2 & tx_point)
overload_cnt2 <=#Tp overload_cnt2 + 1'b1;
end
always @ (posedge clk or posedge rst)
begin
if (rst)
overload_frame_blocked <= 0;
else if (reset_mode | go_error_frame | go_rx_id1)
overload_frame_blocked <=#Tp 0;
else if (go_overload_frame & overload_frame) // This is a second sequential
overload
overload_frame_blocked <=#Tp 1'b1;
end
assign send_ack = (~tx_state) & rx_ack & (~err) & (~listen_only_mode);
always @ (posedge clk or posedge rst)
begin
if (rst)
tx <= 1'b1;
else if (reset_mode) // Reset
tx <=#Tp 1'b1;
else if (tx_point)
begin
if (tx_state) // 传输报文
tx <=#Tp ((~bit_de_stuff_tx) & tx_bit) | (bit_de_stuff_tx & (~tx_q));
else if (send_ack) // 应答
tx <=#Tp 1'b0;
else if (overload_frame) //传输超载帧
begin
if (overload_cnt1 < 6)
tx <=#Tp 1'b0;
else
tx <=#Tp 1'b1;
end
else if (error_frame) // 传输错误帧
begin
if (error_cnt1 < 6)
begin
if (node_error_passive)
tx <=#Tp 1'b1;
else
tx <=#Tp 1'b0;
end
else
tx <=#Tp 1'b1;
end
else
tx <=#Tp 1'b1;
end
end
always @ (posedge clk)
begin
if (tx_point)
tx_q <=#Tp tx & (~go_early_tx_latched);
end
//延迟发送数据
always @ (posedge clk)
begin
tx_point_q <=#Tp tx_point;
end
(5)CRC校验模块
assign crc_next = data ^ crc[14];
assign crc_tmp = {crc[13:0], 1'b0};
//CRC 校验
always @ (posedge clk)
begin
if(initialize)
crc <= #Tp 0;
else if (enable)
begin
if (crc_next)
crc <= #Tp crc_tmp ^ 15'h4599;
else
crc <= #Tp crc_tmp;
end
end
(6)FIFO模块
assign write_length_info = (~wr) & wr_q;
//延迟写信号
always @ (posedge clk or posedge rst)
begin
if (rst)
wr_q <= 0;
else if (reset_mode)
wr_q <=#Tp 0;
else
wr_q <=#Tp wr;
end
// 数据长度计数器
always @ (posedge clk or posedge rst)
begin
if (rst)
len_cnt <= 0;
else if (reset_mode | write_length_info)
len_cnt <=#Tp 1'b0;
else if (wr & (~fifo_full))
len_cnt <=#Tp len_cnt + 1'b1;
end
// 写信息指针
always @ (posedge clk or posedge rst)
begin
if (rst)
wr_info_pointer <= 0;
else if (reset_mode)
wr_info_pointer <=#Tp 0;
else if (write_length_info & (~info_full))
wr_info_pointer <=#Tp wr_info_pointer + 1'b1;
end
//读信息指针
always @ (posedge clk or posedge rst)
begin
if (rst)
rd_info_pointer <= 0;
else if (reset_mode)
rd_info_pointer <=#Tp 0;
else if (release_buffer & (~fifo_empty))
rd_info_pointer <=#Tp rd_info_pointer + 1'b1;
end
// 读指针
always @ (posedge clk or posedge rst)
begin
if (rst)
rd_pointer <= 0;
else if (release_buffer & (~fifo_empty))
rd_pointer <=#Tp rd_pointer + length_info;
else if (reset_mode)
rd_pointer <=#Tp 0;
end
// 写指针
always @ (posedge clk or posedge rst)
begin
if (rst)
wr_pointer <= 0;
else if (wr & (~fifo_full))
wr_pointer <=#Tp wr_pointer + 1'b1;
else if (reset_mode)
wr_pointer <=#Tp 0;
end
//锁存
always @ (posedge clk or posedge rst)
begin
if (rst)
latch_overrun <= 0;
else if (reset_mode | write_length_info)
latch_overrun <=#Tp 0;
else if (wr & fifo_full)
latch_overrun <=#Tp 1'b1;
end
//统计在 FIFO 中的数据
always @ (posedge clk or posedge rst)
begin
if (rst)
fifo_cnt <= 0;
else if (wr & (~release_buffer) & (~fifo_full))
fifo_cnt <=#Tp fifo_cnt + 1'b1;
else if ((~wr) & release_buffer & (~fifo_empty))
fifo_cnt <=#Tp fifo_cnt - length_info;
else if (wr & release_buffer & (~fifo_full) & (~fifo_empty))
fifo_cnt <=#Tp fifo_cnt - length_info + 1'b1;
else if (reset_mode)
fifo_cnt <=#Tp 0;
end
assign fifo_full = fifo_cnt == 64;
assign fifo_empty = fifo_cnt == 0;
//统计在 length_fifo 和 overrun_info fifo 中的数据
always @ (posedge clk or posedge rst)
begin
if (rst)
info_cnt <= 0;
else if (write_length_info ^ release_buffer)
begin
if (release_buffer & (~info_empty))
info_cnt <=#Tp info_cnt - 1'b1;
else if (write_length_info & (~info_full))
info_cnt <=#Tp info_cnt + 1'b1;
end
end
assign info_full = info_cnt == 64;
assign info_empty = info_cnt == 0;
//选择用来读数据的 FIFO 的地址
always @ (extended_mode or rd_pointer or addr)
begin
if (extended_mode) // extended mode
begin
read_address <= rd_pointer + (addr - 8'd16);
end
else // normal mode
begin
read_address <= rd_pointer + (addr - 8'd20);
end
end
always @ (posedge clk)
begin
if (wr & (~fifo_full))
fifo[wr_pointer] <=#Tp data_in;
end
//从 FIFO 中读数据
assign data_out = fifo[read_address];
//写到 length_fifo
always @ (posedge clk)
begin
if (write_length_info & (~info_full))
length_fifo[wr_info_pointer] <=#Tp len_cnt;
end
// 读 length_fifo 中的数据
assign length_info = length_fifo[rd_info_pointer];
// overrun_info
always @ (posedge clk)
begin
if (write_length_info & (~info_full))
overrun_info[wr_info_pointer] <=#Tp latch_overrun | (wr & fifo_full);
end
// 读取 overrun
assign overrun = overrun_info[rd_info_pointer]
?
文章来源:https://blog.csdn.net/weixin_66634995/article/details/135230596
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!