post一下FPGA的串口驱动代码
总体的设计框图如下

以下是TX模块
module uart_tx#(
parameter P_UART_DATA_WIDTH = 8 , // 5 - 9 bits
parameter P_UART_STOP_WIDTH = 1 , // 1 bit or 2 bits
parameter P_UART_PARITY_MOD = 0 // No check:0 // Odd check:1 // Even check:2
) (
input i_clk ,
input i_rst ,
/*-----------------*USER INTERFACE*-----------------*/
input [ P_UART_DATA_WIDTH - 1 : 0 ] i_user_tx_data ,
input i_user_tx_valid ,
output o_user_tx_ready ,
/*-----------------*DRIVE INTERFACE*-----------------*/
output o_uart_tx
);
/*-----------------*function*-----------------*/
/*-----------------*parameter*----------------*/
/*-----------------*port*---------------------*/
/*-----------------*mechine*------------------*/
/*-----------------*reg*----------------------*/
//INPUT----USER
reg [P_UART_DATA_WIDTH - 1 : 0] r_i_user_tx_data ;
//OUTPUT----USER
reg r_o_user_tx_ready ;
//OUTPUT----DERIVE
reg r_o_uart_tx ;
//COUNTER
reg [ 15 : 0 ] r_cnt ;
//OTHER
reg r_parity ;
/*-----------------*wire*---------------------*/
//Handshake Indication Signal
wire w_uart_active ;
/*-----------------*component*----------------*/
/*-----------------*assign*-------------------*/
//OUTPUT----USER
assign o_user_tx_ready = r_o_user_tx_ready ;
//OUTPUT----DRIVE
assign o_uart_tx = r_o_uart_tx ;
//Handshake Indication Signal
assign w_uart_active = i_user_tx_valid & r_o_user_tx_ready ;
/*-----------------*always*-------------------*/
//COUNTER
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_cnt <= 0;
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH) - 1 && P_UART_PARITY_MOD == 0)begin
r_cnt <= 0;
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH + 1 + P_UART_STOP_WIDTH) - 1 && P_UART_PARITY_MOD >= 1)begin
r_cnt <= 0;
end
else if(!r_o_user_tx_ready)begin
r_cnt <= r_cnt + 1;
end
else begin
r_cnt <= r_cnt;
end
end
//OUTPUT----USER
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_o_user_tx_ready <= 1;
end
else if(w_uart_active)begin
r_o_user_tx_ready <= 0;
end
else if(r_cnt >= (1 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH) - 2 && P_UART_PARITY_MOD == 0)begin
r_o_user_tx_ready <= 1;
end
else if(r_cnt >= (1 + P_UART_DATA_WIDTH + 1 + P_UART_STOP_WIDTH) - 2 && P_UART_PARITY_MOD >= 1)begin
r_o_user_tx_ready <= 1;
end
else begin
r_o_user_tx_ready <= r_o_user_tx_ready;
end
end
//INPUT----USER
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_i_user_tx_data <= 0;
end
else if(w_uart_active)begin
r_i_user_tx_data <= i_user_tx_data;
end
else if(!r_o_user_tx_ready)begin
r_i_user_tx_data <= r_i_user_tx_data >> 1;
end
else begin
r_i_user_tx_data <= r_i_user_tx_data;
end
end
//OUTPUT----DRIVE
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_o_uart_tx <= 1;
end
else if(w_uart_active)begin
r_o_uart_tx <= 0;
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH) - 1 && P_UART_PARITY_MOD == 0)begin
r_o_uart_tx <= 1; //STOP
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH) - 1 && P_UART_PARITY_MOD == 1)begin
r_o_uart_tx <= ~ r_parity;
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH) - 1 && P_UART_PARITY_MOD == 2)begin
r_o_uart_tx <= r_parity;
end
else if (r_cnt >= (1 + P_UART_DATA_WIDTH + 1) - 1 && P_UART_PARITY_MOD >= 1) begin
r_o_uart_tx <= 1; //STOP
end
else if(!r_o_user_tx_ready)begin
r_o_uart_tx <= r_i_user_tx_data[0];
end
else begin
r_o_uart_tx <= 1;
end
end
//Implement parity function
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_parity <= 0;
end
else if(r_cnt <= P_UART_DATA_WIDTH)begin
r_parity <= r_parity ^ r_i_user_tx_data[0];
end
else begin
r_parity <= r_parity;
end
end
endmodule
以下是RX模块
module uart_rx#(
parameter P_UART_DATA_WIDTH = 8 , // 5 - 9 bits
parameter P_UART_STOP_WIDTH = 1 , // 1 bit or 2 bits
parameter P_UART_PARITY_MOD = 0 // No check:0 // Odd check:1 // Even check:2
) (
input i_clk ,
input i_rst ,
/*-----------------*USER INTERFACE*-----------------*/
output [ P_UART_DATA_WIDTH - 1 : 0 ] o_user_rx_data ,
output o_user_rx_valid ,
/*-----------------*DRIVE INTERFACE*-----------------*/
input i_uart_rx
);
/*-----------------*function*-----------------*/
/*-----------------*parameter*----------------*/
/*-----------------*port*---------------------*/
/*-----------------*mechine*------------------*/
/*-----------------*reg*----------------------*/
//INPUT----USER
reg [ P_UART_DATA_WIDTH - 1 : 0 ] r_o_user_rx_data ;
reg r_o_user_rx_valid ;
//OUTPUT----DERIVE
//COUNTER
reg [ 15 : 0 ] r_cnt ;
//OTHER
reg r_parity ;
/*-----------------*wire*---------------------*/
/*-----------------*component*----------------*/
/*-----------------*assign*-------------------*/
//OUTPUT----USER
assign o_user_rx_data = r_o_user_rx_data ;
assign o_user_rx_valid = r_o_user_rx_valid ;
/*-----------------*always*-------------------*/
//COUNTER
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_cnt <= 0;
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH) - 1 && P_UART_PARITY_MOD == 0)begin
r_cnt <= 0;
end
else if(r_cnt == (1 + P_UART_DATA_WIDTH + 1 + P_UART_STOP_WIDTH) - 1 && P_UART_PARITY_MOD >= 1)begin
r_cnt <= 0;
end
else if(r_cnt > 0 || !i_uart_rx)begin
r_cnt <= r_cnt + 1;
end
else begin
r_cnt <= r_cnt;
end
end
//OUTPUT----USER
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_o_user_rx_data <= 0;
end
else if(r_cnt >= 1 && r_cnt <= P_UART_DATA_WIDTH)begin
r_o_user_rx_data <= {i_uart_rx,r_o_user_rx_data[P_UART_DATA_WIDTH - 1 : 1]};
end
else begin
r_o_user_rx_data <= r_o_user_rx_data;
end
end
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_o_user_rx_valid <= 0;
end
else if(r_cnt == P_UART_DATA_WIDTH + P_UART_STOP_WIDTH - 1 && P_UART_PARITY_MOD == 0)begin
r_o_user_rx_valid <= 1;
end
else if(r_cnt == P_UART_DATA_WIDTH + P_UART_STOP_WIDTH && P_UART_PARITY_MOD == 1 && !r_parity == i_uart_rx)begin
r_o_user_rx_valid <= 1;
end
else if(r_cnt == P_UART_DATA_WIDTH + P_UART_STOP_WIDTH && P_UART_PARITY_MOD == 2 && r_parity == i_uart_rx)begin
r_o_user_rx_valid <= 1;
end
else begin
r_o_user_rx_valid <= 0;
end
end
//Implement parity function
always @(posedge i_clk , posedge i_rst) begin
if(i_rst)begin
r_parity <= 0;
end
else if(r_cnt >= 1 && r_cnt <= P_UART_DATA_WIDTH)begin
r_parity <= r_parity ^ i_uart_rx;
end
else begin
r_parity <= 0;
end
end
endmodule
module_uart_drive#(
parameter P_SYSTEM_CLK = 100_000_000 , // system clock
parameter P_UART_BAUDRATE = 115200 , // 9600、19200 、38400 、57600 、115200、230400、460800、921600
parameter P_UART_DATA_WIDTH = 8 , // 5 - 9 bits
parameter P_UART_STOP_WIDTH = 1 , // 1 bit or 2 bits
parameter P_UART_PARITY_MOD = 0 // No check:0 // Odd check:1 // Even check:2
) (
input i_clk ,
input i_rst ,
/*-----------------*USER INTERFACE*-----------------*/
output o_user_clk ,
output o_user_rst ,
input [ P_UART_DATA_WIDTH - 1 : 0 ] i_user_tx_data ,
input i_user_tx_valid ,
output o_user_tx_ready ,
output [ P_UART_DATA_WIDTH - 1 : 0 ] o_user_rx_data ,
output o_user_rx_valid ,
/*-----------------*DRIVE INTERFACE*-----------------*/
output o_uart_tx ,
input i_uart_rx
);
/*-----------------*function*-----------------*/
/*-----------------*parameter*----------------*/
/*-----------------*port*---------------------*/
/*-----------------*mechine*------------------*/
/*-----------------*reg*----------------------*/
//Metronome ---- The first beat eliminates metastability and the second beat aligns the data with the clock of this module.
reg [ P_UART_DATA_WIDTH - 1 : 0 ] r_user_rx_data_1d ;
reg r_user_rx_valid_1d ;
reg [ P_UART_DATA_WIDTH - 1 : 0 ] r_user_rx_data_2d ;
reg r_user_rx_valid_2d ;
/*-----------------*wire*---------------------*/
//INPUT
wire w_rst ;
//OTHER
wire [ P_UART_DATA_WIDTH - 1 : 0 ] w_user_rx_data ;
wire w_user_rx_valid ;
wire w_uart_tx_clk ;
wire w_uart_tx_rst ;
wire w_uart_rx_clk ;
wire w_uart_rx_rst ;
/*-----------------*component*----------------*/
baudrate_gen #(
.P_SYSTEM_CLK (P_SYSTEM_CLK ),
.P_UART_BAUDRATE (P_UART_BAUDRATE )
)u_baudrate_gen(
.i_clk (i_clk ),
.i_rst (w_rst ),
.i_uart_rx (i_uart_rx ),
.i_user_rx_valid (w_user_rx_valid ),
.o_uart_tx_clk (w_uart_tx_clk ),
.o_uart_tx_rst (w_uart_tx_rst ),
.o_uart_rx_clk (w_uart_rx_clk ),
.o_uart_rx_rst (w_uart_rx_rst )
);
uart_tx #(
.P_UART_DATA_WIDTH (P_UART_DATA_WIDTH ), // 5 - 9 bits
.P_UART_STOP_WIDTH (P_UART_STOP_WIDTH ), // 1 bit or 2 bits
.P_UART_PARITY_MOD (P_UART_PARITY_MOD ) // No check:0 // Odd check:1 // Even check:2
)u_uart_tx(
.i_clk (w_uart_tx_clk ),
.i_rst (w_uart_tx_rst ),
.i_user_tx_data (i_user_tx_data ),
.i_user_tx_valid (i_user_tx_valid ),
.o_user_tx_ready (o_user_tx_ready ),
.o_uart_tx (o_uart_tx )
);
uart_rx #(
.P_UART_DATA_WIDTH (P_UART_DATA_WIDTH ), // 5 - 9 bits
.P_UART_STOP_WIDTH (P_UART_STOP_WIDTH ), // 1 bit or 2 bits
.P_UART_PARITY_MOD (P_UART_PARITY_MOD ) // No check:0 // Odd check:1 // Even check:2
)u_uart_rx(
.i_clk (w_uart_rx_clk ),
.i_rst (w_uart_rx_rst ),
.o_user_rx_data (w_user_rx_data ),
.o_user_rx_valid (w_user_rx_valid ),
.i_uart_rx (i_uart_rx )
);
/*-----------------*assign*-------------------*/
//INPUT ---- USER
assign w_rst = ~i_rst ;
//OUTPUT ---- USER
assign o_user_clk = w_uart_tx_clk ;
assign o_user_rst = w_uart_rx_rst ;
assign o_user_rx_data = r_user_rx_data_2d ;
assign o_user_rx_valid = r_user_rx_valid_2d ;
/*-----------------*always*-------------------*/
//Metronome ---- The first beat eliminates metastability and the second beat aligns the data with the clock of this module.
always @(posedge i_clk , posedge w_rst)
begin
if(w_rst)
begin
r_user_rx_data_1d <= 0 ;
r_user_rx_valid_1d <= 0 ;
r_user_rx_data_2d <= 0 ;
r_user_rx_valid_2d <= 0 ;
end else begin
r_user_rx_data_1d <= w_user_rx_data ;
r_user_rx_valid_1d <= w_user_rx_valid ;
r_user_rx_data_2d <= r_user_rx_data_1d ;
r_user_rx_valid_2d <= r_user_rx_valid_1d ;
end
end
endmodule
具体测评控制等之后再补充
全部评论