当前位置:网站首页>Design of CAN bus controller based on FPGA (Part 2)
Design of CAN bus controller based on FPGA (Part 2)
2022-06-24 15:33:00 【FPGA technology Jianghu】
be based on FPGA Of CAN Design of bus controller ( in )
Today, I bring you FPGA Of CAN Design of bus controller , Because of the long space , It is divided into three parts . Today brings the second , medium-length ,CAN The realization of communication controller . Don't talk much , Loading .
Reading guide
CAN Bus (Controller Area Network) Is the abbreviation of controller area network , yes 20 century 80 Germany in the early S BOSCH The company has developed a serial data communication protocol to solve the data exchange between many control and test instruments in modern automobiles . at present ,CAN Bus has been listed ISO international standard , be called ISO11898.CAN Bus has become one of the mainstream technologies of industrial data communication .
CAN Bus as a digital serial communication technology , Compared with other similar technologies , In reliability 、 It has unique technical advantages in real-time and flexibility , The main features are as follows :
- CAN A bus is a multi master bus , Any node on the bus can actively send information to other nodes on the network at any time, regardless of primary and secondary , Therefore, free communication between nodes can be realized .
- CAN Bus adopts non-destructive bus arbitration technology . But when multiple nodes send information to the bus at the same time , Nodes with low priority will actively quit sending , The node with the highest priority can continue to transmit data unaffected , Thus, the arbitration time of bus conflicts can be greatly saved . Even when the network load is very heavy, the network will not be paralyzed .
- CAN The communication medium of the bus can be twisted pair 、 Coaxial cable or optical fiber , Choose flexible .
- CAN The communication rate of the bus can reach 1Mbit/s( At this time, the longest communication distance is 40 rice ), The communication distance can be up to 10km( The rate is at 5kbit/s following ).
- CAN The node information on the bus is divided into different priorities , It can meet different levels of real-time requirements , High priority data can be found in 134μs Get transmitted within .
- CAN The bus can realize point-to-point through message filtering 、 Point to multipoint and global broadcasting are used to transmit data , No special scheduling is required .
- CAN The bus data adopts short frame structure , Short transmission time , Low probability of interference , It has excellent error detection effect .
- CAN The bus adopts CRC Check and provide corresponding error handling function , Ensure the reliability of data communication .
- CAN Devices on the bus can be placed in a sleep mode without any internal activity , Equivalent to not connected to the bus , Can effectively reduce system power consumption .
CAN The node on the bus has the function of automatically turning off the output in case of serious error , So that the operation of other nodes on the bus is not affected .CAN Outstanding features of the bus 、 High reliability and unique design , It is especially suitable for the interconnection of monitoring equipment in industrial process , therefore , More and more attention has been paid by the industry , And is recognized as one of the most promising fieldbus . in addition ,CAN The bus protocol has been recognized by the international organization for Standardization , Mature technology , Control chips have been commercialized , High cost performance , It is especially suitable for data communication between distributed measurement and control systems .
CAN The bus plug-in card can be inserted at any time PC AT XT Compatible with on-board , It is convenient to form a distributed monitoring system . therefore , use FPGA Realization CAN Bus communication controller has very important application value . This article will explain the use of... Through an example FPGA Realization CAN Implementation method of bus communication controller .
Part II summary : Introduction CAN The realization of communication controller , Including top-level control procedures 、 Register control 、 Bit sequential logic (Bit Timing Logic)、 Bit stream processor (Bit Stream Processor)、CRC check 、FIFO And so on .
3、 ... and 、CAN The realization of communication controller
The organizational structure of each module is shown in the figure 10 Shown .
chart 10 Program organization structure
3.1 Top level control program ——TOP
TOP The program is at the top of the whole program , Control the normal operation of other parts . The main program code is as follows :
// Connect other modules
// Register module
can_registers i_can_registers (
.clk(clk_i),
.rst(rst),
.cs(cs),
.we(we),
….)
// Connect Bit Timing Logic modular
can_btl i_can_btl (
.clk(clk_i),
.rst(rst),
.rx(rx_i),
…)
// Connect Bit Streaming Processor modular
can_bsp i_can_bsp(
.clk(clk_i),
.rst(rst),
…)
// Choose output fifo Or the data pattern in the register
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
// Output data
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
// Latch address
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
// Generate a delay signal
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
// Combine to get multiple signals , Such as film selection 、 Lifting, etc
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;3.2 Register control
This module is used to complete all register operations in the program , The code is as follows :
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
…
// Mode register
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)
);
// Command register
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
// Status register
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
// Bus timing register 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];
// Bus timing register 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];
// Error prompt register
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)
);
// Clock division register
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);
// Read data from registers
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;
end3.3 Bit sequential logic ——Bit Timing Logic
Bit sequential logic implementation CAN The control of bit synchronization in bus protocol . Bit timing logic monitors serial CAN Bus and handle the bit timing related to the bus . It starts sending messages 、 When the bus level jumps from the recessive value to the dominant value, it is synchronized with CAN Bit data stream on the bus ( Hard sync ), And during the transmission of the message , A resynchronization is performed every time a jump edge from the recessive value to the dominant value is encountered ( Soft synchronization ). Bit timing logic also provides programmable time periods to compensate for propagation delay time and phase drift . The main program code is as follows :
// Counter
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
// Generate a general enable signal that defines the baud rate
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
// Change state
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)));
// When it detects SJW The edge of the field , The synchronization request is latched and executed
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
// A synchronized platform or fragment
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;
// fragment 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
// fragment 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 Counter
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
// When the trailing edge is detected , fragment seg1 Delayed
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
// If the edge appears in this window , Phase errors will be fully compensated
assign sync_window = ((time_segment2 - quant_cnt) < ( sync_jump_width + 1));
// Data sampling
always @ (posedge clk or posedge rst)
begin
if (rst)
sample <= 2'b11;
else if (clk_en)
sample <= {sample[0], rx};
end
// When enabled , Sampling complete
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
// Blocking synchronization
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
// Block resynchronization until a start signal is received
/* 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;
end3.4 Bit stream processor ——Bit Stream Processor
The bit data stream processor is responsible for all data operations in the program . The bit stream processor is actually a sequence generator , It controls the transmit buffer 、 receive FIFO and CAN Data flow between buses , It also performs error detection 、 arbitration 、 Bit padding and CAN Bus error handling function . The program structure of bit data stream processor is shown in the figure 11 Shown .
chart 11 Bit stream processor program structure
The main program code is as follows :
// The initial state of each data transmission
// Receiving data idle state
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
// Receiving data id1 state
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
// Receiving data rtr1 state
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
// Receiving data ide state
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
// Receiving data id2 state
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
// Receiving data rtr2 state
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
// Receiving data r0 state
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
// Receiving data r0 state
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
// Receiving data dlc state
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
// Receive data status
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
// Receiving data crc state
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
// receive data crc Separator status
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
// Response status of received data
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
// Receive data separator status
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
// End of frame state of received data
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
// Interframe space state
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 register
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 position
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 position
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 position
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
// Get data length
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
// Get data
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 Check the data
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
// Counter
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
// End of frame counter
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
// Enable bit fill
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
// Bit fill counter
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
// The enable bit of the transmission data is filled
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
// Bit fill count of transmitted data
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;
// Bit fill error
assign stuff_err = sample_point & bit_stuff_cnt_en & bit_de_stuff & (sampled_bit ==
sampled_bit_q);
// Generate a delay signal
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 Check error
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
// General wrong conditions
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
// The rules 5
assign rule5 = (~node_error_passive) & bit_err & (error_frame & (error_cnt1 < 7) |
overload_frame & (overload_cnt1 < 7) );
// The rules 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
// Receiving data CRC check
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);
// receive data FIFO Writing enables
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
// Data counter
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
// Synthesis of data and saving to FIFO in
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
// Transmit error frame
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
// Passive counting
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
// Transmit overloaded frames
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) // Transmit message
tx <=#Tp ((~bit_de_stuff_tx) & tx_bit) | (bit_de_stuff_tx & (~tx_q));
else if (send_ack) // The reply
tx <=#Tp 1'b0;
else if (overload_frame) // Transmit overloaded frames
begin
if (overload_cnt1 < 6)
tx <=#Tp 1'b0;
else
tx <=#Tp 1'b1;
end
else if (error_frame) // Transmit 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
// Delay sending data
always @ (posedge clk)
begin
tx_point_q <=#Tp tx_point;
end3.5 CRC check
CAN Error detection is set in the node 、 Measures such as calibration and self inspection . There are many ways to detect errors , One of the most commonly used 、 The most effective one is CRC check .CRC The sequence is composed of frame checking sequence obtained by cyclic redundancy check code . In order to achieve CRC Calculation , The divided polynomial coefficients are determined by including the start of the frame 、 Arbitration field 、 Control field 、 The unfilled bit data stream including the data field is given , Its 15 The lowest coefficient is 0.
This polynomial is divided by the following polynomials generated by the generator ( The coefficient is modulus 2 operation ):1 3478101415XXXXXXX +++++++ The remainder of the polynomial division is the number of the bus CRC Sequence . To complete this operation , You can use one 15 Bit shift register CRC-RG(14:0). The divided polynomial bit data stream is given by an unfilled sequence from the beginning of the frame to the end of the data field , If the NXTBIT Mark the next bit of the bit stream , be CRC The sequence can be obtained in the following way :
CRC-RG=0 // Initialize shift register REPEAT CRCNXT = NXTBIT EXOR CRC-RG(14); CRC-RG(14:1) = CRC-RG(13:0) // Shift the register one bit to the left CRC-RG(0) = 0; IF CRCNXT THEN CRC-RG(14:0) = CRC-RG(14:0) EXOR (4599H) END IF UNTIL(CRC The sequence starts or there is an error state )
Complete the data CRC The main verification codes are as follows :
assign crc_next = data ^ crc[14];
assign crc_tmp = {crc[13:0], 1'b0};
//CRC check
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
end3.6 FIFO
To realize the rapid exchange of data , Used FIFO, The code is as follows :
assign write_length_info = (~wr) & wr_q;
// Delay write signal
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
// Data length counter
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
// Write information pointer
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
// Read information pointer
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
// Read pointer
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
// The write pointer
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
// Latch
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
// Statistics in FIFO Data in
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;
// Statistics in length_fifo and overrun_info fifo Data in
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;
// Select the... Used to read data FIFO The address of
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
// from FIFO Middle reading data
assign data_out = fifo[read_address];
// writes length_fifo
always @ (posedge clk)
begin
if (write_length_info & (~info_full))
length_fifo[wr_info_pointer] <=#Tp len_cnt;
end
// read length_fifo Data in
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
// Read overrun
assign overrun = overrun_info[rd_info_pointer]This is the end of this article , The next one is based on FPGA Of CAN Design of bus controller ( Next ), Will introduce the simulation, testing and summary of the program .
边栏推荐
- Which account of Dongfang fortune is safer and better
- Typescript raw data type
- Openinstall joins hands with the book chain to help channel data analysis and create the era of Book Networking
- How to resolve the 35 year old crisis? Sharing of 20 years' technical experience of chief architect of Huawei cloud database
- [log service CLS] initial experience of Tencent cloud CLS log service
- Istio FAQ: 431 request header fields too large
- Application of motion capture system in positioning and mapping of mobile robot in underground tunnel
- How to generate assembly code using clang in Intel syntax- How to generate assembly code with clang in Intel syntax?
- Cvpr2022 | domaine compact adaptable
- 入行 4 年,跳槽 2 次,我摸透了软件测试这一行
猜你喜欢

入行 4 年,跳槽 2 次,我摸透了软件测试这一行

Successfully solved: selenium common. exceptions. SessionNotCreatedException: Message: session not created: This versi
Step by step introduction to sqlsugar based development framework (9) -- Realizing field permission control with WinForm control
Bitmap of redis data structure

测试 H5 和小程序的区别,你真的知道吗?

Keyword of ES mapping; Term query add keyword query; Change mapping keyword type

leetcode. 12 --- integer to Roman numeral
Record the range of data that MySQL update will lock

常见的缺陷管理工具——禅道,从安装到使用手把手教会你

He is also a junior test engineer. Why is his salary high? The interview must be brilliant at these points
随机推荐
Restoring to an earlier version in CVS
MySQL toolset: the official export tool mysqlpump
动作捕捉系统用于地下隧道移动机器人定位与建图
IDEA 插件 Material Theme UI收费后的办法
Is it safe to open a stock account by mobile phone
Teach you how to deploy the pressure test engine on Tencent cloud
Kubernetes practical tips: using ksniff to capture packets
股票网上开户及开户流程怎样?网上开户安全么?
List of PostgreSQL
How to resolve the 35 year old crisis? Sharing of 20 years' technical experience of chief architect of Huawei cloud database
API data interface for announcement of Hong Kong listed companies
07. Tencent cloud IOT device side learning - Data Template
He is also a junior test engineer. Why is his salary high? The interview must be brilliant at these points
Design of vga/lcd display controller system based on FPGA (Part 2)
Two way combination of business and technology to build a bank data security management system
东方财富哪个开户更安全,更好点
Allwinner a40i industrial Internet gateway design scheme, smart site, smart city core gateway
Wide measuring range of jishili electrometer
How about stock online account opening and account opening process? Is it safe to open an account online?
Application of motion capture system in positioning and mapping of mobile robot in underground tunnel