当前位置:网站首页>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;
  end

3.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;
  end

3.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;
end

3.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
  end

3.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 .

原网站

版权声明
本文为[FPGA technology Jianghu]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/05/20210511192759089S.html