FPAGA本篇文章参考github网站的开源项目can-FPGA-master编写改进
在调试过程中,发现该项目无法在quartus pro13.0的环境下运行通过,代码存在错误,并且对于EP4系列的芯片来说有太多的IO口,无法在烧录,所以笔者对此进行了改进。
can_top模块
// Extended CAN format
//扩展格式
// 1(SOF)+11(Arb1)+2(SDR,IDE)+11(Arb2)+1(RTR)+1(r1)+1(r0)+4(Control)+64(Data)+15(CRC Field)+1(CRC Delimeter)+2(Ack)+7(EoF)+3(Idle)
//1位+11位ID+1位SDR&1位IDE+18位ID+1位RTR+1位r1+1位1r0+4位control+64位data+15位CRCsequence+CRC界定律+(1位ACK槽+1位ACK界定符)+(7位EOF)
module can_top
#(
parameter CLK_FREQ = 'd9600, //设置波特率
parameter CAN_CLK_FREQ = 'd50_000_000, //设置can信号的波特率
// DMA
parameter DATA_WIDTH = 32, //数据宽度32位*2
parameter ADDR_WIDTH = 20, //设置写入数据的宽度为20
parameter CLK_FREQUENCY = 200_000_000, //
parameter OP_CYCLE_NS = 35, //
//
parameter [5:0] LOCAL_ADDRESS = 6'b000101,
parameter [19:0] ADDR_SETTING_SEND = 20'hA0001, //4'ha表示4位十六进制数字a(二进制1010)
parameter [19:0] ADDR_DATA_SEND_1 = 20'hA0002,
parameter [19:0] ADDR_DATA_SEND_2 = 20'hA0003,
parameter [19:0] addr_setting_recieved = 20'hB0001, //
parameter [19:0] addr_data_recieved_1 = 20'hB0002,
parameter [19:0] addr_data_recieved_2 = 20'hB0003
)(
input rst_i,
input clk_i,
input rx_i,
output rx_busy,
// output rx_received,
output tx_o,
output tx_busy,
input tx_send_i //绑定针脚key1,使得其按下代表开始发送数据
// <DMA> 直接存储器访问
// wire reg [DATA_WIDTH-1 : 0] data_wr, //写入数据
// wire reg [ADDR_WIDTH-1 : 0] addr_wr, //写入地址
// reg wr_en, //写入信号
// wire wr_done, //写入完成
// wire wr_busy, //写入占用
// output reg rd_en, //读取信号
// wire rd_done, //完成
// wire rd_busy, //占用
// wire [63:0] tx_data_i
// tx fields
//input tx_message_type,
//input [5:0] tx_address_remote,
// - output CAN frame LLC/DLC data
// <test>
// output test_clk_can,
// output [2:0] test_can_state,
// output [7:0] test_can_tx_state,
// output [7:0] test_bit_count,
// output [3:0] test_bit_pol_count,
// output reg bit_stuffed,
// output test_last_bit,
// output [7:0] test_rx_state,
// output [11:0] test_rx_quant_count,
// output [7:0] test_rx_bit_count,
// output [3:0] test_rx_bit_pol_count,
// output test_rx_bit_stuffed,
// output [6:0] test_rx_count,
// output test_rx_rx,
// output test_sample
// </test>
);
// <test>
// wire test_arbi;
reg count_rst;
// assign test_sample = ( CAN_STATE == CAN_PAUSE ) ? 1'b0 : 1'b1;
// assign test_can_state = CAN_STATE;
// </test>
wire clk_can;
reg [63:0] data_to_send;
wire [DATA_WIDTH-1 : 0] data_rd; //读取数据
//<input>
reg tx_message_type = 1'b0;
reg [5:0] local_address = 6'b000101; // 6'h2A
reg [5:0] remote_address = 6'b100010;
reg [1:0] tx_handshake = 2'b10;
reg [1:0] tx_atribute = 2'b10;
reg [3:0] tx_expand_count = 4'b1011;
reg [7:0] tx_cmd_data_sign = 8'b1111_0101;
reg [3:0] tx_dlc = 4'b1001;
reg [63:0] tx_data;
reg [31:0] can_send_setting; //后面将其等于data_rd
//</input>
//<output>
reg [63:0] rx_data_reg;
wire [63:0] rx_data;
//</output>
reg tx_start;
reg rx_start;
reg tx_pending; //tx挂起
reg init;
wire tx_o_tx;
wire tx_o_rx;
wire frame_sent;
wire can_is_free;
wire rx_frame_ready;
//<CAN MAIN FLOW>
assign tx_o = CAN_STATE == CAN_TX ? tx_o_tx :
( CAN_STATE == CAN_RX ? tx_o_rx : 1'b1 ); //判断can_state的状态,如果是TX输出则tx_o=tx_o_tx,
//若否则判断是否为RX写入状态,若是则tx_o为tx_o_rx,若否则tx_o=1'b1;
localparam CAN_START_INIT = 0;
localparam CAN_INIT = 1;
localparam CAN_IDLE = 2;
localparam CAN_PAUSE = 3;
localparam CAN_START_RX = 4;
localparam CAN_RX = 5;
localparam CAN_START_TX = 6;
localparam CAN_TX = 7;
localparam CAN_TEST_START = 8;
localparam CAN_TEST = 9;
reg [3:0] CAN_STATE;
reg [10:0] count; //11位的ID?
always @( posedge clk_can or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
end else begin
if ( count_rst == 1'b1 ) begin
count <= 11'd0;
end else begin
count <= count + 1'b1;
end
end
end
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
CAN_STATE <= CAN_IDLE;
tx_start <= 1'b0; //输出和输入的
rx_start <= 1'b0;
count_rst <= 1'b0;
init <= 1'b0;
end else begin
case ( CAN_STATE )
CAN_START_INIT: begin
init <= 1'b1;
CAN_STATE <= CAN_INIT;
end //can初始化 can_state等于can_init
CAN_INIT: begin
init <= 1'b0;
CAN_STATE <= CAN_IDLE; //can变化为can_idle空闲
end
CAN_IDLE: begin
if ( tx_pending == 1'b1 ) begin //如果tx挂起 那么开始tx传输数据
CAN_STATE <= CAN_START_TX; //can开始发送数据
tx_start <= 1'b1;
rx_start <= 1'b0;
end else begin
CAN_STATE <= CAN_START_RX; //can开始接收数据
rx_start <= 1'b1;
end
end
CAN_PAUSE: begin
if ( tx_pending == 1'b1 ) begin //tx挂起
if ( tx_lost_arbitrage == 1'b1 ) begin
if ( count == 11'd11 ) begin
count_rst <= 1'b1;
CAN_STATE <= CAN_START_TX;
end
end else begin
if ( count == 11'd2 ) begin
count_rst <= 1'b1;
CAN_STATE <= CAN_START_TX;
end
end
end else begin
if ( count == 11'd2 ) begin
CAN_STATE <= CAN_START_RX;
end
end
end
CAN_START_RX: begin
if ( rx_busy == 1'b1 ) begin
CAN_STATE <= CAN_RX;
end else begin
CAN_STATE <= CAN_IDLE;
end
end
CAN_RX: begin
if ( rx_busy == 1'b0 ) begin
rx_start <= 1'b0;
count_rst <= 1'b0;
CAN_STATE <= CAN_PAUSE;
end
end
CAN_START_TX: begin
if ( tx_busy == 1'b1 ) begin
CAN_STATE <= CAN_TX;
end
end
CAN_TX: begin
if ( frame_sent == 1'b1 ) begin
tx_start <= 1'b0;
count_rst <= 1'b1;
CAN_STATE <= CAN_PAUSE;
end
end
// CAN_TEST_START: begin
// tx_start <= 1'b1;
// if ( rx_busy == 1'b1 ) begin
// CAN_STATE <= CAN_TEST;
// end
// end
// CAN_TEST: begin
// tx_start <= 1'b0;
// if ( rx_busy == 0 ) begin
// rx_start <= 1'b0;
// end
// end
endcase
end
end
//</CAN MAIN FLOW>
//<TX DATA DMA READ>
localparam TX_READ_IDLE = 0;
localparam TX_START_READ_SETTING = 1;
localparam TX_READ_SETTING = 2;
localparam TX_START_READ_DATA_1 = 3;
localparam TX_READ_DATA_1 = 4;
localparam TX_START_READ_DATA_2 = 5;
localparam TX_READ_DATA_2 = 6;
localparam TX_START_SEND_DATA = 7;
localparam TX_SEND_DATA = 8;
reg [3:0] TX_DMA_STATE;
localparam RX_WRITE_IDLE = 0;
localparam RX_START_WRITE_SETTING = 1;
localparam RX_WRITE_SETTING = 2;
localparam RX_START_WRITE_DATA_1 = 3;
localparam RX_WRITE_DATA_1 = 4;
localparam RX_START_WRITE_DATA_2 = 5;
localparam RX_WRITE_DATA_2 = 6;
localparam RX_START_SEND_DATA = 7;
localparam RX_SEND_DATA = 8;
reg [3:0] RX_DMA_STATE;
//<RX DATA DMA READ>
always @( posedge clk_i or negedge rst_i ) begin
if ( !rst_i ) begin
can_send_setting <= 32'd0;
tx_data <= 64'h0;
// rx_data <= 64'h0;
tx_pending <= 1'b0;
rx_data_reg <= 64'h0;
end
else begin
case ( TX_DMA_STATE )
TX_READ_IDLE: begin
if ( tx_send_i == 1'b1 ) begin
TX_DMA_STATE <= TX_START_READ_SETTING;
end
end
TX_START_READ_SETTING: begin
can_send_setting <= data_rd;
// rd_en <= 1'b1;
TX_DMA_STATE <= TX_READ_SETTING;
end
TX_READ_SETTING: begin
// rd_en <= 1'b0;
TX_DMA_STATE <= TX_START_READ_DATA_1;
end
TX_START_READ_DATA_1: begin
tx_data[63:32] <= data_rd;
// rd_en <= 1'b1;
TX_DMA_STATE <= TX_READ_DATA_1;
end
TX_READ_DATA_1: begin
// rd_en <= 1'b0;
TX_DMA_STATE <= TX_START_READ_DATA_2;
end
TX_START_READ_DATA_2: begin
tx_data[31:0] <= data_rd;
// rd_en <= 1'b1;
TX_DMA_STATE <= TX_READ_DATA_2;
end
TX_READ_DATA_2: begin
// rd_en <= 1'b0;
TX_DMA_STATE <= TX_START_SEND_DATA;
end
TX_START_SEND_DATA: begin
tx_pending <= 1'b1;
TX_DMA_STATE <= TX_SEND_DATA;
end
TX_SEND_DATA: begin
if ( tx_busy ) begin
tx_pending <= 1'b0;
TX_DMA_STATE <= TX_READ_IDLE;
end
end
endcase
end
end
//</TX DATA DMA READ>
/* 错误原因,不能在同一个always的语句中定义reg型的变量 */
always @( posedge clk_i or negedge rst_i ) begin
if ( !rst_i ) begin
rx_data_reg <= 64'h0;
end else begin
case ( RX_DMA_STATE )
RX_WRITE_IDLE: begin
if ( tx_send_i == 1'b1 ) begin
RX_DMA_STATE <= RX_START_WRITE_SETTING;
end
end
RX_START_WRITE_SETTING: begin
//这一块有问题
can_send_setting <= data_rd;
// rd_en <= 1'b1;
RX_DMA_STATE <= RX_WRITE_SETTING;
end
RX_WRITE_SETTING: begin
// rd_en <= 1'b0;
RX_DMA_STATE <= RX_START_WRITE_DATA_1;
end
RX_START_WRITE_DATA_1: begin
rx_data_reg[63:32] <= data_rd;
// rd_en <= 1'b1;
RX_DMA_STATE <= RX_WRITE_DATA_1;
end
RX_WRITE_DATA_1: begin
// rd_en <= 1'b0;
RX_DMA_STATE <= RX_START_WRITE_DATA_2;
end
RX_START_WRITE_DATA_2: begin
rx_data_reg[31:0] <= data_rd;
// rd_en <= 1'b1;
RX_DMA_STATE <= RX_WRITE_DATA_2;
end
RX_WRITE_DATA_2: begin
// rd_en <= 1'b0;
RX_DMA_STATE <= RX_START_SEND_DATA;
end
endcase
end
end
can_tx #(
.CLK_FREQ (CLK_FREQ),
.CAN_CLK_FREQ (CAN_CLK_FREQ)
)can_tx_instance
(
.rst_i (rst_i),
.clk_i (clk_i),
.clk_can_i (clk_can),
.tx_start_i (tx_start),
.tx_lost_arbitrage_o (tx_lost_arbitrage),
.tx_acknowledged_o (tx_acknowledged),
.frame_sent_o (frame_sent),
.rx_i (rx_i),
.tx_o (tx_o_tx),
.tx_busy_o (tx_busy),
.message_type (tx_message_type),
.local_address (local_address),
.remote_address (remote_address),
.handshake (tx_handshake),
.expand_count (tx_expand_count),
.cmd_data_sign (tx_cmd_data_sign),
.dlc (tx_dlc),
.tx_data (tx_data)
//test
// .test_tx_state (test_can_tx_state),
// .test_bit_count (test_bit_count),
// .test_bit_pol_count (test_bit_pol_count),
// .test_arbi (test_arbi)
);
can_rx #(
.CLK_FREQ (CLK_FREQ),
.CAN_CLK_FREQ (CAN_CLK_FREQ)
) can_rx_instance
(
.rst_i (rst_i),
.rx_i (rx_i),
.tx_o (tx_o_rx),
.clk_i (clk_i),
.clk_can_i (clk_can),
.can_clk_sync_o (can_clk_sync),
.rx_start_i (rx_start),
.rx_busy_o (rx_busy),
.init_i (init),
.rx_frame_ready_o (rx_frame_ready),
.local_address (LOCAL_ADDRESS),
//<data_out>
.rx_data (rx_data)
//</data_out>
//test
// .test_rx_state (test_rx_state),
// .test_quant_count (test_rx_quant_count),
// .test_bit_count (test_rx_bit_count),
// .test_bit_pol_count (test_rx_bit_pol_count),
// .test_rx_bit_stuffed (test_rx_bit_stuffed),
// .test_rx_count (test_rx_count),
// .test_rx_rx (test_rx_rx)
//.test_sample_1 (test_sample)
);
can_clk #(
.FREQ_I (CLK_FREQ),
.FREQ_O (CAN_CLK_FREQ)
) can_clk_instance
(
.rst_i (rst_i),
.clk_i (clk_i),
.sync_i (can_clk_sync),
.can_clk_o (clk_can)
);
endmodule
can_tx传输数据模块
module can_tx
#(
parameter CLK_FREQ = 'd9600,
parameter CAN_CLK_FREQ = 'd50_000_000,
parameter QUANTS = CLK_FREQ/CAN_CLK_FREQ
)(
input rst_i,
input clk_i,
input clk_can_i,
input tx_start_i,
output reg frame_sent_o,
output reg tx_lost_arbitrage_o,
output tx_acknowledged_o,
input message_type,
input [5:0] local_address,
input [5:0] remote_address,
input [1:0] handshake,
input [3:0] expand_count,
input [7:0] cmd_data_sign,
input [3:0] dlc,
input [63:0] tx_data,
input rx_i,
output tx_o,
output reg tx_busy_o
//test
// output [7:0] test_tx_state,
// output [7:0] test_bit_count,
// output [2:0] test_bit_pol_count,
// output reg test_arbi
);
//<test>
// assign test_tx_state = TX_STATE;
// assign test_bit_count = bit_count_reg;
// assign test_bit_pol_count = bit_pol_count;
//</test>
reg [6:0] count;
reg [11:0] quant_count;
//<CRC>
wire [14:0] crc;
wire crc_en;
assign crc_en = ( TX_STATE == TX_IDLE ||
TX_STATE == TX_START_OF_FRAME ||
TX_STATE == TX_BIT_STUFF ||
TX_STATE == TX_CRC ) ? 1'b0 : 1'b1;
reg crc_rst_i;
can_crc can_crc_instance
(
.crc_clk_i (clk_can_i),
.rst_i (rst_i),
.data_i (tx_o),
.en_i (crc_en),
.crc_reg_o (crc),
.crc_rst_i (crc_rst_i)
);
//</CRC>
//<bit stuff>
reg [7:0] bit_count_reg;
reg [2:0] bit_pol_count;
reg last_bit;
reg bit_stuff_bit;
//</bit stuff>
// <arbitrage>
// </arbitrage>
// 0xAx - MAC, 0xB-x - LLC
localparam TX_IDLE = 8'h00;
localparam TX_BIT_STUFF = 8'h0B;
localparam TX_START_OF_FRAME = 8'hA1;
localparam TX_MESSAGE_TYPE = 8'hB1;
localparam TX_ADDRESS_LOCAL = 8'hB2;
localparam TX_ADDRESS_REMOTE = 8'hB3;
localparam TX_SRR = 8'hA2;
localparam TX_IDE = 8'hA3;
localparam TX_HANDSHAKING_P = 8'hB4;
localparam TX_ATRIBUTE_RESERVED = 8'hB5;
localparam TX_EXPAND_COUNT = 8'hB6;
localparam TX_CMD_DATA_SIGN = 8'hB7;
localparam TX_RTR = 8'hA4;
localparam TX_RESERVED = 8'hA5;
localparam TX_DLC = 8'hB8;
localparam TX_DATA = 8'hB9;
localparam TX_CRC = 8'hA6;
localparam TX_CRC_DELIMITER = 8'hA7;
localparam TX_ACK_SLOT = 8'hA8;
localparam TX_ACK_DELIMITER = 8'hA9;
localparam TX_END_OF_FRAME = 8'hAA;
reg[7:0] TX_STATE = TX_IDLE;
reg[7:0] NEXT_TX_STATE;
always @( posedge clk_can_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
TX_STATE <= 8'h0;
NEXT_TX_STATE <= TX_IDLE;
bit_count_reg <= 8'd0;
count <= 7'd0;
bit_pol_count <= 3'd1;
bit_stuff_bit <= 1'b0;
last_bit <= 1'b1;
crc_rst_i <= 1'b0;
tx_busy_o <= 1'b0;
frame_sent_o <= 1'b0;
end else begin
if ( TX_STATE != TX_IDLE ) begin
last_bit <= tx_o;
bit_count_reg <= bit_count_reg + 1'b1;
end
case ( TX_STATE )
TX_IDLE: begin
if ( tx_start_i ) begin
tx_busy_o <= 1'b1;
count <= 7'd0;
bit_count_reg <= 8'd0;
frame_sent_o <= 1'b0;
TX_STATE <= TX_START_OF_FRAME;
end
end
// <MAC-level>
// every 5 consequent same polarity bit add one reversed(not for CRC delimiter, ACK field and EOF)
// 1 bit
TX_BIT_STUFF: begin
TX_STATE <= NEXT_TX_STATE;
end
// 1 bit
TX_START_OF_FRAME: begin
TX_STATE <= TX_MESSAGE_TYPE;
NEXT_TX_STATE <= TX_MESSAGE_TYPE;
crc_rst_i <= 1'b0;
end
// IDE and SRR are placed between 18 and 17 bit of 29 bit extended arbitration field
// 1 bit
TX_SRR: begin
TX_STATE <= TX_IDE;
NEXT_TX_STATE <= TX_IDE;
end
// 1 bit
TX_IDE: begin
TX_STATE <= TX_ADDRESS_REMOTE;
NEXT_TX_STATE <= TX_ADDRESS_REMOTE;
end
// -- RTR-bit is 0 in the Data Frame, in the Remote Frame is 1 there and there is no Data Field
// in Remote Frame The DLC field indicates the data length of the requested message (not the transmitted one)
// 1 bit
TX_RTR: begin
TX_STATE <= TX_RESERVED;
NEXT_TX_STATE <= TX_RESERVED;
end
// -- r1, r0 Reserved bits which must be set dominant (0), but accepted as either dominant or recessive
TX_RESERVED: begin
if ( count == 7'd1 ) begin
count <= 7'd0;
TX_STATE <= TX_DLC;
NEXT_TX_STATE <= TX_DLC;
end else begin
count <= count + 1'b1;
end
end
// -- exclude start of the frame bit
// 15 bit
TX_CRC: begin
if ( count == 7'd14 ) begin
count <= 7'd0;
TX_STATE <= TX_CRC_DELIMITER;
crc_rst_i <= 1'b1;
end else begin
count <= count + 1'b1;
end
end
// -- must be 1
// 1 bit
TX_CRC_DELIMITER: begin
TX_STATE <= TX_ACK_SLOT;
end
// -- Each node that receives the frame, without an error, transmits a 0 and thus overrides the 1 of the transmitter.
// If a transmitter detects a recessive level in the ACK slot, it knows that no receiver found a valid frame.
// A receiving node may transmit a recessive to indicate that it did not receive a valid frame,
// but another node that did receive a valid frame may override this with a dominant.
// 1 bit
TX_ACK_SLOT: begin
TX_STATE <= TX_ACK_DELIMITER;
end
// 1 bit(1)
TX_ACK_DELIMITER: begin
TX_STATE <= TX_END_OF_FRAME;
end
// 7 bits(1)
TX_END_OF_FRAME: begin
if ( count == 7'd6 ) begin
count <= 7'd0;
TX_STATE <= TX_IDLE;
frame_sent_o <= 1'b1;
tx_busy_o <= 1'b0;
end else begin
count <= count + 1'b1;
end
end
// </MAC-level>
// <LLC-level>
// <Identificator>
// C/D 1 bit
TX_MESSAGE_TYPE: begin
TX_STATE <= TX_ADDRESS_LOCAL;
NEXT_TX_STATE <= TX_ADDRESS_LOCAL;
end
// Address local 6 bit
TX_ADDRESS_LOCAL: begin
if ( count == 7'd5 ) begin
count <= 7'd0;
TX_STATE <= TX_ADDRESS_REMOTE;
NEXT_TX_STATE <= TX_ADDRESS_REMOTE;
end else begin
count <= count + 1'b1;
end
end
// Address remote 6 bit
TX_ADDRESS_REMOTE: begin
if ( count == 7'd5 ) begin
count <= 7'd0;
TX_STATE <= TX_HANDSHAKING_P;
NEXT_TX_STATE <= TX_HANDSHAKING_P;
end else begin
if ( count == 7'd3 ) begin
count <= count + 1'b1;
TX_STATE <= TX_SRR;
NEXT_TX_STATE <= TX_SRR;
end else begin
count <= count + 1'b1;
end
end
end
// </Identificator>
// <Atribute>
// DataFrame: pointer, CommandFrame: handshaking 2 bit
TX_HANDSHAKING_P: begin
if ( count == 7'd1 ) begin
count <= 7'd0;
TX_STATE <= TX_ATRIBUTE_RESERVED;
NEXT_TX_STATE <= TX_ATRIBUTE_RESERVED;
end else begin
count <= count + 1'b1;
end
end
// DataFrame: reserved 2'b00, CommandFrame: 2'b10 2 bit
TX_ATRIBUTE_RESERVED:begin
if ( count == 7'd1 ) begin
count <= 7'd0;
TX_STATE <= TX_EXPAND_COUNT;
NEXT_TX_STATE <= TX_EXPAND_COUNT;
end else begin
count <= count + 1'b1;
end
end
// DataFrame: frame count, CommandFrame: expand command field 4 bit
TX_EXPAND_COUNT: begin
if ( count == 7'd3 ) begin
count <= 7'd0;
TX_STATE <= TX_CMD_DATA_SIGN;
NEXT_TX_STATE <= TX_CMD_DATA_SIGN;
end else begin
count <= count + 1'b1;
end
end
// DataFrame: type of data, CommandFrame: type of command 8 bit
TX_CMD_DATA_SIGN: begin
if ( count == 7'd7 ) begin
count <= 7'd0;
TX_STATE <= TX_RTR;
NEXT_TX_STATE <= TX_RTR;
end else begin
count <= count + 1'b1;
end
end
// DLC 4 bit
TX_DLC: begin
if ( count == 7'd3 ) begin
count <= 7'd0;
TX_STATE <= TX_DATA;
NEXT_TX_STATE <= TX_DATA;
end else begin
count <= count + 1'b1;
end
end
// Data 0 or 64 bit
TX_DATA: begin
if ( count == 7'd63 ) begin
count <= 7'd0;
TX_STATE <= TX_CRC;
NEXT_TX_STATE <= TX_CRC;
end else begin
count <= count + 1'b1;
end
end
// </LLC-level>
endcase
// <bit stuff check>
if ( TX_STATE != TX_IDLE &&
TX_STATE != TX_CRC_DELIMITER &&
TX_STATE != TX_ACK_SLOT &&
TX_STATE != TX_ACK_DELIMITER &&
TX_STATE != TX_END_OF_FRAME ) begin
if ( tx_o == last_bit ) begin
bit_pol_count <= bit_pol_count + 1'b1;
if ( bit_pol_count == 3'd5 ) begin
if ( tx_o == 1'b0 ) begin
bit_stuff_bit <= 1'b1;
end else begin
bit_stuff_bit <= 1'b0;
end
bit_pol_count <= 3'd1;
TX_STATE <= TX_BIT_STUFF;
end
end else begin
bit_pol_count <= 3'd2;
end
end
// </bit stuff check>
if ( TX_STATE != TX_IDLE &&
TX_STATE != TX_ACK_SLOT ) begin
if ( tx_o != rx_i ) begin
//tx_lost_arbitrage_o <= 1'b1;
//TX_STATE <= TX_IDLE;
end
end
end
end
//<acknowledgement>
reg tx_acknowledged_o_reg;
assign tx_acknowledged_o = tx_acknowledged_o_reg;
always @( posedge clk_can_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
tx_acknowledged_o_reg <= 1'b0;
end else begin
if ( TX_STATE == TX_ACK_SLOT ) begin
if ( rx_i == 1'b0 ) begin
tx_acknowledged_o_reg <= 1'b1;
end
end
end
end
//</acknowledgement>
localparam SAMPLE = QUANTS/2;
localparam STATE_RES = 12'd0;
//<arbitrage>
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
tx_lost_arbitrage_o <= 1'b0;
end else begin
if ( TX_STATE == TX_IDLE ) begin
quant_count <= STATE_RES;
tx_lost_arbitrage_o <= 1'b0;
end else begin
quant_count <= quant_count + 1'b1;
if ( quant_count == SAMPLE ) begin
// test_arbi <= rx_i;
if ( TX_STATE != TX_ACK_SLOT ) begin
if ( tx_o != rx_i ) begin
tx_lost_arbitrage_o <= 1'b1;
end
end
end else begin
if ( quant_count == QUANTS ) begin
quant_count <= STATE_RES;
end
end
end
end
end
//</arbitrage>
localparam [1:0] atribute = 2'b10;
localparam rtr = 1'b0;
assign tx_o = TX_STATE == TX_START_OF_FRAME ? 1'b0 :
( TX_STATE == TX_MESSAGE_TYPE ? message_type :
( TX_STATE == TX_ADDRESS_LOCAL ? local_address [7'd5 - count] :
( TX_STATE == TX_ADDRESS_REMOTE ? remote_address [7'd5 - count] :
( TX_STATE == TX_SRR ? 1'b1 :
( TX_STATE == TX_IDE ? 1'b1 :
( TX_STATE == TX_HANDSHAKING_P ? handshake [7'd1 - count] :
( TX_STATE == TX_ATRIBUTE_RESERVED ? atribute [7'd1 - count] :
( TX_STATE == TX_EXPAND_COUNT ? expand_count [7'd3 - count] :
( TX_STATE == TX_CMD_DATA_SIGN ? cmd_data_sign [7'd7 - count] :
( TX_STATE == TX_RTR ? rtr :
( TX_STATE == TX_RESERVED ? 1'b0 :
( TX_STATE == TX_DLC ? dlc [7'd3 - count] :
( TX_STATE == TX_DATA ? tx_data [7'd63 - count] :
( TX_STATE == TX_CRC ? crc [7'd14 - count] :
( TX_STATE == TX_CRC_DELIMITER ? 1'b1 :
( TX_STATE == TX_ACK_SLOT ? 1'b1 :
( TX_STATE == TX_ACK_DELIMITER ? 1'b1 :
( TX_STATE == TX_END_OF_FRAME ? 1'b1 :
( TX_STATE == TX_BIT_STUFF ? bit_stuff_bit :
( TX_STATE == TX_IDLE ? 1'b1 :
1'b1 ))))))))))))))))))));
endmodule
can_rx接收数据模块
module can_rx
#(
parameter CLK_FREQ = 'd9600,
parameter CAN_CLK_FREQ = 'd50_000_000,
parameter QUANTS = CLK_FREQ/CAN_CLK_FREQ
)(
input rst_i,
input clk_i,
input clk_can_i,
input rx_start_i,
input init_i,
output reg rx_busy_o,
output reg can_clk_sync_o,
output reg rx_frame_ready_o,
input message_type,
input [5:0] local_address,
input [5:0] rx_local_address,
output reg [5:0] remote_address,
output [1:0] handshake,
output [3:0] expand_count,
output [7:0] cmd_data_sign,
output [3:0] dlc,
output reg [63:0] rx_data,
input rx_i,
output tx_o
//test
// output [7:0] test_rx_state,
// output [11:0] test_quant_count,
// output [7:0] test_bit_count,
// output [2:0] test_bit_pol_count,
// output test_rx_bit_stuffed,
// output [6:0] test_rx_count,
// output reg test_sample,
// output reg test_rx_rx,
// output test_sample_1
);
// <test>
// assign test_rx_state = RX_STATE;
// assign test_quant_count = quant_count;
// assign test_bit_count = bit_count_reg;
// assign test_bit_pol_count = bit_pol_count;
// assign test_rx_bit_stuffed = rx_bit_stuffed;
// assign test_rx_count = count;
// reg test_reg_on;
// reg [6:0] test_count;
// always @( posedge clk_can_i or negedge rst_i ) begin
// if ( rst_i == 1'b0 ) begin
// test_count <= 7'd0;
// test_sample <= 1'b1;
// end else begin
// if ( test_reg_on == 1'b1 ) begin
// if ( test_count == 7'd15 ) begin
// test_sample <= 1'b1;
// end else begin
// test_sample <= crc_calc[7'd14 - test_count];
// test_count <= test_count + 1'b1;
// end
// end else begin
// test_sample <= 1'b1;
// test_count <= 7'd0;
// end
// end
// end
// always @( posedge clk_i or negedge rst_i ) begin
// if ( rst_i == 1'b0 ) begin
// test_rx_rx <= 1'b1;
// end else begin
// if ( RX_STATE != RX_IDLE ) begin
// if ( quant_count == SAMPLE ) begin
// test_rx_rx <= rx_i;
// end
// end else begin
// test_rx_rx <= 1'b1;
// end
// end
// end
// assign test_sample_1 = tx_o;
// </test>
reg [5:0] local_adress_reg;
wire [5:0] local_adress;
// <init>
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
local_adress_reg <= 6'h0;
end else begin
if ( init_i == 1'b1 ) begin
local_adress_reg <= local_adress;
end
end
end
// </init>
// <ACK>
reg acknowledged_aux;
assign tx_o = ( RX_STATE == RX_ACK_SLOT && acknowledged_aux ) ? 1'b0 : 1'b1;
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
acknowledged_aux <= 1'b0;
end else begin
if ( RX_STATE == RX_HANDSHAKING_P ) begin
if ( rx_address_remote == local_adress_reg ) begin
acknowledged_aux <= 1'b1;
end
end else begin
if ( RX_STATE == RX_IDLE ) begin
acknowledged_aux <= 1'b0;
end
end
end
end
// </ACK>
//<CRC>
reg [14:0] crc_calc;
wire [14:0] crc;
wire crc_en;
wire crc_clk;
assign crc_en = ( RX_STATE == RX_IDLE ||
RX_STATE == RX_START_OF_FRAME ||
RX_STATE == RX_BIT_STUFF ||
RX_STATE == RX_ACK_SLOT ||
RX_STATE == RX_ACK_DELIMITER ||
RX_STATE == RX_END_OF_FRAME ||
RX_STATE == RX_CRC_DELIMITER ||
RX_STATE == RX_CRC ) ? 1'b0 : 1'b1;
assign crc_clk = ( quant_count == SAMPLE ) ? 1'b1 : 1'b0;
reg crc_rst_i;
can_crc can_crc_instance
(
.crc_clk_i (crc_clk),
.rst_i (rst_i),
.data_i (rx_i),
.en_i (crc_en),
.crc_reg_o (crc),
.crc_rst_i (crc_rst_i)
);
//</CRC>
// <frame regs>
reg rx_message_type;
reg [5:0] rx_address_local;
reg [5:0] rx_address_remote;
reg [1:0] rx_handshaking_p;
reg [1:0] rx_atribute_reserved;
reg [3:0] rx_expand_count;
reg [7:0] rx_cmd_data_sign;
reg [3:0] rx_dlc;
reg [14:0] rx_crc;
// </frame regs>
// <count and aux>
reg [7:0] bit_count_reg ;
reg [6:0] count;
reg [2:0] bit_pol_count;
reg last_bit;
reg bit_stuff_bit;
reg rx_bit_stuffed;
reg rx_i_last;
reg aux_count;
reg [11:0] quant_count;
// </count and aux>
localparam SAMPLE = QUANTS/2;
localparam STATE_RES = 12'd0;
// 0xAx - MAC, 0xB-x - LLC
localparam RX_IDLE = 8'h00;
localparam RX_BIT_STUFF = 8'h0B;
localparam RX_START_OF_FRAME = 8'hA1;
localparam RX_MESSAGE_TYPE = 8'hB1;
localparam RX_ADDRESS_LOCAL = 8'hB2;
localparam RX_ADDRESS_REMOTE = 8'hB3;
localparam RX_SRR = 8'hA2;
localparam RX_IDE = 8'hA3;
localparam RX_HANDSHAKING_P = 8'hB4;
localparam RX_ATRIBUTE_RESERVED = 8'hB5;
localparam RX_EXPAND_COUNT = 8'hB6;
localparam RX_CMD_DATA_SIGN = 8'hB7;
localparam RX_RTR = 8'hA4;
localparam RX_RESERVED = 8'hA5;
localparam RX_DLC = 8'hB8;
localparam RX_DATA = 8'hB9;
localparam RX_CRC = 8'hA6;
localparam RX_CRC_DELIMITER = 8'hA7;
localparam RX_ACK_SLOT = 8'hA8;
localparam RX_ACK_DELIMITER = 8'hA9;
localparam RX_END_OF_FRAME = 8'hAA;
reg[7:0] RX_STATE;
reg[7:0] NEXT_RX_STATE;
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
RX_STATE <= RX_IDLE;
NEXT_RX_STATE <= RX_IDLE;
//<test>
// test_reg_on <= 1'b0;
//</test>
rx_address_local <= 6'd0;
rx_address_remote <= 6'd0;
rx_handshaking_p <= 2'd0;
rx_atribute_reserved <= 2'd0;
rx_expand_count <= 4'd0;
rx_cmd_data_sign <= 8'd0;
rx_dlc <= 4'd0;
rx_crc <= 15'd0;
rx_data <= 64'd0;
bit_count_reg <= 8'd0;
count <= 7'd0;
bit_stuff_bit <= 1'b0;
last_bit <= 1'b0;
crc_rst_i <= 1'b0;
quant_count <= 12'd1;
rx_busy_o <= 1'b0;
aux_count <= 1'b0;
crc_calc <= 15'd0;
rx_i_last <= 1'b0;
aux_count <= 1'b0;
rx_frame_ready_o <= 1'b0;
end else begin
if ( rx_start_i ) begin
if ( RX_STATE != RX_IDLE ) begin
quant_count <= quant_count + 1'b1;
end
case ( RX_STATE )
RX_IDLE: begin
crc_rst_i <= 1'b0;
bit_count_reg <= 8'd0;
// test_reg_on <= 1'b0;
rx_frame_ready_o <= 1'b0;
if ( rx_i == 1'b0 && rx_i_last == 1'b1 ) begin
RX_STATE <= RX_START_OF_FRAME;
quant_count <= 12'd1;
rx_busy_o <= 1'b1;
rx_data <= 64'd0;
end
end
// <MAC-level>
// every 5 consequent same polarity bit add one reversed(not for CRC delimiter, ACK field and EOF)
// 1 bit
RX_BIT_STUFF: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == 12'd0 ) begin
RX_STATE <= NEXT_RX_STATE;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// 1 bit
RX_START_OF_FRAME: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_MESSAGE_TYPE;
NEXT_RX_STATE <= RX_MESSAGE_TYPE;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// IDE and SRR are placed between 18 and 17 bit of 29 bit extended arbitration field
// 1 bit
RX_SRR: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_IDE;
NEXT_RX_STATE <= RX_IDE;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// 1 bit
RX_IDE: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_ADDRESS_REMOTE;
NEXT_RX_STATE <= RX_ADDRESS_REMOTE;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// -- RTR-bit is 0 in the Data Frame, in the Remote Frame is 1 there and there is no Data Field
// in Remote Frame The DLC field indicates the data length of the requested message (not the transmitted one)
// 1 bit
RX_RTR: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_RESERVED;
NEXT_RX_STATE <= RX_RESERVED;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// -- r1, r0 Reserved bits which must be set dominant (0), but accepted as either dominant or recessive
RX_RESERVED: begin
if ( count == 7'd2 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_DLC;
NEXT_RX_STATE <= RX_DLC;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
count <= count + 1'b1;
end
end
end
// -- exclude start of the frame bit
// 15 bit
RX_CRC: begin
if ( count == 7'd15 ) begin
if ( quant_count == STATE_RES ) begin
count <= 7'd0;
RX_STATE <= RX_CRC_DELIMITER;
//
// test_reg_on <= 1'b1;
//
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_crc[7'd14 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// -- must be 1
// 1 bit
RX_CRC_DELIMITER: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_ACK_SLOT;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// -- Each node that receives the frame, without an error, transmits a 0 and thus overrides the 1 of the transmitter.
// If a transmitter detects a recessive level in the ACK slot, it knows that no receiver found a valid frame.
// A receiving node may transmit a recessive to indicate that it did not receive a valid frame,
// but another node that did receive a valid frame may override this with a dominant.
// 1 bit
RX_ACK_SLOT: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_ACK_DELIMITER;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// 1 bit(1)
RX_ACK_DELIMITER: begin
if ( aux_count == 1'b1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_END_OF_FRAME;
aux_count <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
aux_count <= 1'b1;
end
end
end
// 7 bits(1)
RX_END_OF_FRAME: begin
rx_frame_ready_o <= 1'b1;
if ( count == 7'd7 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_IDLE;
crc_rst_i <= 1'b1;
count <= 7'd0;
rx_busy_o <= 1'b0;
end
end else begin
if ( quant_count == SAMPLE ) begin
count <= count + 1'b1;
end
end
end
// </MAC-level>
// <LLC-level>
// <Identificator>
// C/D 1 bit
RX_MESSAGE_TYPE: begin
if ( count == 7'd1 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_ADDRESS_LOCAL;
NEXT_RX_STATE <= RX_ADDRESS_LOCAL;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_message_type <= rx_i;
count <= count + 1'b1;
end
end
end
// Address local 6 bit
RX_ADDRESS_LOCAL: begin
if ( count == 7'd6 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_ADDRESS_REMOTE;
NEXT_RX_STATE <= RX_ADDRESS_REMOTE;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_address_local[7'd5 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// Address remote 6 bit
RX_ADDRESS_REMOTE: begin
if ( count == 7'd6 ) begin
if ( quant_count == STATE_RES) begin
RX_STATE <= RX_HANDSHAKING_P;
NEXT_RX_STATE <= RX_HANDSHAKING_P;
count <= 7'd0;
end
end else begin
if ( count == 7'd4 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_SRR;
NEXT_RX_STATE <= RX_SRR;
end else begin
if ( quant_count == SAMPLE ) begin
rx_address_remote[7'd5 - count] <= rx_i;
count <= count + 1'b1;
end
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_address_remote[7'd5 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
end
// </Identificator>
// <Atribute>
// DataFrame: pointer, CommandFrame: handshaking 2 bit
RX_HANDSHAKING_P: begin
if ( count == 7'd2 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_ATRIBUTE_RESERVED;
NEXT_RX_STATE <= RX_ATRIBUTE_RESERVED;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_handshaking_p[7'd1 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// DataFrame: reserved 2'b00, CommandFrame: 2'b10 2 bit
RX_ATRIBUTE_RESERVED:begin
if ( count == 7'd2 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_EXPAND_COUNT;
NEXT_RX_STATE <= RX_EXPAND_COUNT;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_atribute_reserved[7'd1 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// DataFrame: frame count, CommandFrame: expand command field 4 bit
RX_EXPAND_COUNT: begin
if ( count == 7'd4 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_CMD_DATA_SIGN;
NEXT_RX_STATE <= RX_CMD_DATA_SIGN;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_expand_count[7'd3 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// DataFrame: type of data, CommandFrame: type of command 8 bit
RX_CMD_DATA_SIGN: begin
if ( count == 7'd8 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_RTR;
NEXT_RX_STATE <= RX_RTR;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_cmd_data_sign[7'd7 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// DLC 4 bit
RX_DLC: begin
if ( count == 7'd4 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_DATA;
NEXT_RX_STATE <= RX_DATA;
count <= 7'd0;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_dlc[7'd3 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// Data 0 or 64 bit
RX_DATA: begin
if ( count == 7'd64 ) begin
if ( quant_count == STATE_RES ) begin
RX_STATE <= RX_CRC;
NEXT_RX_STATE <= RX_CRC;
count <= 7'd0;
//
crc_calc <= crc;
end
end else begin
if ( quant_count == SAMPLE ) begin
rx_data[7'd63 - count] <= rx_i;
count <= count + 1'b1;
end
end
end
// </LLC-level>
endcase
// <can clk sync>
if ( rx_i == 1'b0 && rx_i_last == 1'b1 ) begin
can_clk_sync_o <= 1'b1;
end else begin
can_clk_sync_o <= 1'b0;
end
// </can clk sync>
// <bit stuff check>
if ( quant_count == STATE_RES ) begin
if ( rx_bit_stuffed ) begin
RX_STATE <= RX_BIT_STUFF;
end
end
// </bit stuff check>
// <bit count>
if ( RX_STATE != RX_IDLE ) begin
if ( quant_count == SAMPLE ) begin
last_bit <= rx_i;
bit_count_reg <= bit_count_reg + 1'b1;
end
end
// </bit count>
// <quant count>
if ( quant_count == QUANTS ) begin
quant_count <= STATE_RES;
end
// </quant count>
// <quant sync>
if ( rx_i != rx_i_last && RX_STATE != RX_IDLE ) begin
quant_count <= STATE_RES;
end
// </quant sync>
rx_i_last <= rx_i;
end
end
end
// <bit_stuffing>
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
rx_bit_stuffed <= 1'b0;
bit_pol_count <= 1'b0;
end else begin
if ( quant_count == SAMPLE ) begin
if ( RX_STATE != RX_IDLE &&
RX_STATE != RX_CRC_DELIMITER &&
RX_STATE != RX_ACK_SLOT &&
RX_STATE != RX_ACK_DELIMITER &&
RX_STATE != RX_END_OF_FRAME ) begin
if ( rx_i == last_bit ) begin
bit_pol_count <= bit_pol_count + 1'b1;
if ( bit_pol_count == 3'd5 ) begin
bit_pol_count <= 3'd1;
end
end else begin
bit_pol_count <= 3'd1;
end
end
end else begin
if ( quant_count == STATE_RES ) begin
rx_bit_stuffed <= 1'b0;
end else begin
if ( bit_pol_count == 3'd5 && RX_STATE != RX_BIT_STUFF ) begin
rx_bit_stuffed <= 1'b1;
end
end
end
end
end
// </bit stuffing>
endmodule
以下为模块化设计,便于修改CRC校验和CLK时钟信号
can_crc校验模块
module can_crc
(
input crc_clk_i,
input rst_i,
input en_i,
input data_i,
input crc_rst_i,
output reg [14:0] crc_reg_o
);
wire crc_next;
wire [14:0] crc_tmp;
assign crc_next = data_i ^ crc_reg_o[14];
assign crc_tmp = {crc_reg_o[13:0], 1'b0};
always @( posedge crc_clk_i or negedge rst_i or posedge crc_rst_i ) begin
if ( rst_i == 1'b0 || crc_rst_i == 1'b1 ) begin
crc_reg_o <= 15'h0;
end else begin
if ( en_i ) begin
if ( crc_next ) begin
crc_reg_o <= crc_tmp ^ 15'h4599;
end else begin
crc_reg_o <= crc_tmp;
end
end
end
end
endmodule
can_clk时钟模块
module can_clk
#(
parameter FREQ_I = 50_000_000,
parameter FREQ_O = 1_000_000,
parameter END_COUNT = FREQ_I/(FREQ_O*2) - 1
)(
input rst_i,
input clk_i,
input sync_i,
output can_clk_o
);
reg [11:0] count;
reg can_clk_o_reg;
assign can_clk_o = can_clk_o_reg;
always @( posedge clk_i or negedge rst_i ) begin
if ( rst_i == 1'b0 ) begin
can_clk_o_reg <= 1'b1;
count <= 12'd0;
end else begin
if ( sync_i ) begin
count <= 12'd0;
can_clk_o_reg <= 1'b1;
end else if ( count == END_COUNT ) begin
count <= 12'd0;
can_clk_o_reg <= ~can_clk_o_reg;
end else begin
count <= count + 1'b1;
end
end
end
endmodule
can_top_inst模块实例化
can_top can_top_inst
(
.rst_i(rst_i_sig) , // input rst_i_sig
.clk_i(clk_i_sig) , // input clk_i_sig
.rx_i(rx_i_sig) , // input rx_i_sig
// .rx_busy(rx_busy_sig) , // output rx_busy_sig
.tx_o(tx_o_sig) , // output tx_o_sig
// .tx_busy(tx_busy_sig) , // output tx_busy_sig
.data_i(data_i_sig) , // input [7:0] data_i_sig
.data_o(data_o_sig) // output [7:0] data_o_sig
);
注:以下模块本项目已经注释掉了,没有在项目中实际运行,原因:使用了太多的IO口,芯片无法支持。
can_test模块
module can_test
(
input clk_i,
input rx_i,
input rst_i,
output tx_o,
output tx_busy,
output rx_busy,
output test_rx_rx,
output test_sample
);
reg tx_send = 1'b1;
reg [63:0] tx_data = 64'b0011000100110010001100110011010000110101001101100011011100111000;
can_top can_top_inst
(
.rst_i (rst_i),
.clk_i (clk_i),
.rx_i (rx_i),
.rx_busy (rx_busy),
.tx_o (tx_o),
.tx_busy (tx_busy),
.tx_send_i (1'b1),
.tx_data_i (tx_data),
.data_wr (data_wr),
.addr_wr (addr_wr),
.wr_en (wr_en),
.wr_done (wr_done),
.wr_busy (wr_busy)
);
localparam addr_width = 10;
localparam data_width = 32;
localparam [9:0] addr_data_send = 20'hA0001;
localparam [9:0] addr_setting_send = 20'hA0002;
PMRAMIF # (
.DATA_WIDTH (data_width),
.ADDR_WIDTH (addr_width),
.CLK_FREQUENCY (50_000_000),
.OP_CYCLE_NS (35)
) PMRAMIF_inst
(
.clk (clk_i),
.rst (rst_i),
.data_wr (data_wr),
.addr_wr (addr_wr),
.wr_en (wr_en),
.wr_done (wr_done),
.wr_busy (wr_busy),
.data_rd (data_rd),
.addr_rd (addr_rd),
.rd_en (rd_en),
.rd_done (rd_done),
.rd_busy (rd_busy)
);
endmodule
pmramif模块
module PMRAMIF
#(
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 20,
parameter CLK_FREQUENCY = 200_000_000,
parameter OP_CYCLE_NS = 35
)(
input clk,
input rst,
input [DATA_WIDTH-1 : 0] data_wr,
input [ADDR_WIDTH-1 : 0] addr_wr,
input wr_en,
output reg wr_done,
output reg wr_busy,
output reg [DATA_WIDTH-1 : 0] data_rd,
input [ADDR_WIDTH-1 : 0] addr_rd,
input rd_en,
output reg rd_done,
output reg rd_busy,
inout [DATA_WIDTH-1 : 0] mram_data,
output reg [ADDR_WIDTH-1 : 0] mram_addr,
output reg mram_ng,
output reg mram_nw,
output reg mram_nce
);
function integer clog2;
input integer value;
begin
value = value-1;
for ( clog2 = 0; value > 0; clog2 = clog2+1 ) begin
value = value >> 1;
end
end
endfunction
localparam CLK_PERIOD_NS = 1_000_000_000 / CLK_FREQUENCY;
localparam OP_CLK_CYCLES = (OP_CYCLE_NS + CLK_PERIOD_NS - 1) / CLK_PERIOD_NS;
localparam OP_COUNTER_WIDTH = clog2(OP_CLK_CYCLES + 1);
wire op_done;
wire begin_op;
reg [DATA_WIDTH-1 : 0] data_wr_reg;
reg [ADDR_WIDTH-1 : 0] addr_wr_reg;
reg [ADDR_WIDTH-1 : 0] addr_rd_reg;
reg [OP_COUNTER_WIDTH-1 : 0] op_counter = 0;
reg op_counter_en = 1'b0;
assign mram_data = mram_nw ? { DATA_WIDTH {1'bz} } : data_wr_reg;
assign op_done = (op_counter == OP_CLK_CYCLES);
assign begin_op = (op_counter == 0);
always @( posedge clk ) begin
if ( op_counter_en ) begin
if ( op_counter < OP_CLK_CYCLES ) begin
op_counter <= op_counter + 1'b1;
end else begin
op_counter <= 0;
end
end else begin
op_counter <= 0;
end
end
always @( posedge clk ) begin
case (STATE)
IDLE : begin
mram_nce <= 1'b1;
mram_nw <= 1'b1;
mram_ng <= 1'b1;
end
MRAM_WRITE : begin
if ( begin_op ) begin
mram_addr <= addr_wr_reg;
mram_nce <= 1'b0;
mram_ng <= 1'b1;
mram_nw <= 1'b0;
end else begin
if ( op_done ) begin
mram_ng <= 1'b1;
mram_nw <= 1'b1;
end
end
end
MRAM_READ : begin
if ( begin_op ) begin
mram_addr <= addr_rd_reg;
mram_nce <= 1'b0;
mram_ng <= 1'b0;
mram_nw <= 1'b1;
end else begin
if ( op_done ) begin
mram_nce <= 1'b1;
mram_ng <= 1'b1;
end
end
end
default: begin
mram_nce <= 1'b1;
mram_nw <= 1'b1;
mram_ng <= 1'b1;
end
endcase
end
localparam IDLE = 0;
localparam MRAM_WRITE = 1;
localparam MRAM_READ = 2;
reg [1:0] STATE;
always @( posedge clk ) begin
if ( rst ) begin
STATE <= IDLE;
end else begin
case (STATE)
IDLE : begin
if ( wr_en ) begin
data_wr_reg <= data_wr;
addr_wr_reg <= addr_wr;
wr_busy <= 1'b1;
op_counter_en <= 1'b1;
STATE <= MRAM_WRITE;
end else begin
if ( rd_en ) begin
addr_rd_reg <= addr_rd;
rd_busy <= 1'b1;
op_counter_en <= 1'b1;
STATE <= MRAM_READ;
end else begin
wr_done <= 1'b0;
rd_done <= 1'b0;
op_counter_en <= 1'b0;
wr_busy <= 1'b0;
rd_busy <= 1'b0;
data_wr_reg <= 0;
addr_wr_reg <= 0;
addr_rd_reg <= 0;
end
end
end
MRAM_WRITE: begin
if ( op_done ) begin
wr_done <= 1'b1;
wr_busy <= 1'b0;
op_counter_en <= 1'b0;
if ( rd_en ) begin
addr_rd_reg <= addr_rd;
rd_busy <= 1'b1;
op_counter_en <= 1'b1;
STATE <= MRAM_READ;
end else begin
STATE <= IDLE;
end
end
rd_done <= 1'b0;
end
MRAM_READ: begin
if ( op_done ) begin
rd_done <= 1'b1;
rd_busy <= 1'b0;
data_rd <= mram_data;
op_counter_en <= 1'b0;
if ( wr_en ) begin
data_wr_reg <= data_wr;
addr_wr_reg <= addr_wr;
wr_busy <= 1'b1;
op_counter_en <= 1'b1;
STATE <= MRAM_WRITE;
end else begin
STATE <= IDLE;
end
end
wr_done <= 1'b0;
end
default: begin
STATE <= IDLE;
end
endcase
end
end
endmodule
以下为实际运行截图
针脚绑定及IO
使用GCANTOOLS上位机验证传输
波特率为800kps(可在can_top及其他模块中设置)文章来源:https://www.toymoban.com/news/detail-718425.html
文章来源地址https://www.toymoban.com/news/detail-718425.html
到了这里,关于基于FPGA的CAN通讯verilog代码设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!