多字节串口收发IP设计(五)串口模块增加数据位停止位动态配置功能(含源码)
在实际应用时,有数据位和停止位位宽配置的需求,并且需要在PS端进行配置,特此在原设计文件上增加位宽的动态配置功能。
串口接收模块
为适应后级缓存FIFO的位宽,将串口接收模块输出的数据固定为8bit,若配置的数据位位宽小于8bit,则在高位补0,使其组成一个8bit数据,便于后级模块设计。
源代码
`timescale 1ns / 1ps module UART_rx ( input wire i_clk , input wire i_rst , input wire i_uart_rx , input wire [15:0] i_uart_baud_cnt , input wire [ 1:0] i_uart_check , //0-no,1-odd,2-even input wire [ 1:0] i_uart_bit_width , //0-8bit,1-7bit,2-6bit,3-5bit input wire [ 1:0] i_uart_stop_width , //0-1bit,1-1.5bit,2-2bit output reg [ 7:0] o_user_rx_data , output reg o_user_rx_valid , output reg o_user_rx_error ); //////////////////////////////////////////////////////////////////// //reg define reg [ 5:0] r_uart_rx ; reg [15:0] r_cnt_baud ; reg [ 3:0] r_cnt_bit ; reg r_rx_check ; reg r_run ; reg [ 3:0] r_data_width ; reg [ 3:0] r_stop_width ; //wire define wire w_rx_en ; wire w_bit_en ; wire w_start_flag ; wire [ 3:0] w_bit_len ; //////////////////////////////////////////////////////////////////// assign w_rx_en = (r_cnt_baud == (i_uart_baud_cnt >> 1) - 1 ); assign w_bit_en = (r_cnt_baud == i_uart_baud_cnt - 1 ); assign w_start_flag = ~(r_uart_rx[4] | r_uart_rx[3] | r_uart_rx[2] | r_uart_rx[1] | r_uart_rx[0]) ; assign w_bit_len = 2 + r_data_width + r_stop_width ; //start+data+check+stop //////////////////////////////////////////////////////////////////// always @(posedge i_clk )begin if(i_rst) r_uart_rx <= 6'b111111; else r_uart_rx <= {r_uart_rx[4:0],i_uart_rx}; end always @(*) begin case(i_uart_bit_width) 0 : r_data_width = 8 ; 1 : r_data_width = 7 ; 2 : r_data_width = 6 ; 3 : r_data_width = 5 ; default : r_data_width = 8 ; endcase end always @(*) begin case(i_uart_stop_width) 0 : r_stop_width = 1 ; 1 : r_stop_width = 2 ; 2 : r_stop_width = 2 ; default : r_stop_width = 1 ; endcase end always @(posedge i_clk) begin if (i_rst) r_run <= 0 ; else if (o_user_rx_valid) r_run <= 0 ; else if (w_start_flag && !r_run) r_run <= 1 ; end always @(posedge i_clk) begin if (i_rst) r_cnt_baud <= 0 ; else if (r_run && r_cnt_baud < i_uart_baud_cnt - 1) r_cnt_baud <= r_cnt_baud + 1 ; else r_cnt_baud <= 0 ; end always @(posedge i_clk )begin if(i_rst) r_cnt_bit <= 'd0; else if(r_run && r_cnt_bit == r_data_width && i_uart_check == 0 && w_bit_en) r_cnt_bit <= 'd0; else if(r_run && r_cnt_bit == r_data_width +1 && i_uart_check > 0 && w_bit_en) r_cnt_bit <= 'd0; else if(r_run && w_bit_en) r_cnt_bit <= r_cnt_bit + 1; end always @(posedge i_clk )begin if(i_rst) o_user_rx_data <= 'd0; else if(r_run && r_cnt_bit >= 1 && r_cnt_bit <= r_data_width && w_rx_en && (r_data_width==8)) o_user_rx_data <= {r_uart_rx[5],o_user_rx_data[7:1]};//LSB first else if(r_run && r_cnt_bit >= 1 && r_cnt_bit <= r_data_width && w_rx_en && (r_data_width==7)) o_user_rx_data <= {1'b0,r_uart_rx[5],o_user_rx_data[6:1]};//LSB first else if(r_run && r_cnt_bit >= 1 && r_cnt_bit <= r_data_width && w_rx_en && (r_data_width==6)) o_user_rx_data <= {2'b0,r_uart_rx[5],o_user_rx_data[5:1]};//LSB first else if(r_run && r_cnt_bit >= 1 && r_cnt_bit <= r_data_width && w_rx_en && (r_data_width==5)) o_user_rx_data <= {3'b0,r_uart_rx[5],o_user_rx_data[4:1]};//LSB first end always @(posedge i_clk )begin if(i_rst) o_user_rx_valid <= 'd0; else if(r_run && r_cnt_bit == r_data_width && i_uart_check == 0 && w_bit_en) o_user_rx_valid <= 1'd1; else if(r_run && r_cnt_bit == r_data_width + 1 && w_bit_en) o_user_rx_valid <= 1'd1; else if(r_run && r_cnt_bit == r_data_width + 1 && w_bit_en) o_user_rx_valid <= 1'd1; else o_user_rx_valid <= 'd0; end always @(posedge i_clk )begin if(i_rst) o_user_rx_error <= 'd0; else if(r_run && r_cnt_bit == r_data_width && i_uart_check == 0 && w_bit_en) o_user_rx_error <= 1'd0; else if(r_run && r_cnt_bit == r_data_width + 1 && i_uart_check == 1 && r_uart_rx[5] == r_rx_check && w_bit_en) o_user_rx_error <= 1'd1; else if(r_run && r_cnt_bit == r_data_width + 1 && i_uart_check == 2 && r_uart_rx[5] == ~r_rx_check && w_bit_en) o_user_rx_error <= 1'd1; else o_user_rx_error <= 'd0; end always @(posedge i_clk )begin if(i_rst) r_rx_check <= 'd0; else if(r_run && r_cnt_bit >= 1 && r_cnt_bit <= r_data_width && w_rx_en) r_rx_check <= r_rx_check ^ r_uart_rx[5];//异或结果为1说明1个数为奇数 else if (!r_run) r_rx_check <= 'd0; end endmodule |
串口发送模块
为适应前级缓存FIFO的位宽,将串口发送模块输入的数据固定为8bit,若配置的数据位位宽小于8bit,则去掉高位,使其组成一个小于8bit数据。
源代码
`timescale 1ns / 1ps module UART_tx ( input wire i_clk , input wire i_rst , input wire [15:0] i_uart_baud_cnt , input wire [ 1:0] i_uart_check , //0-no,1-odd,2-even input wire [ 1:0] i_uart_bit_width , //0-8bit,1-7bit,2-6bit,3-5bit input wire [ 1:0] i_uart_stop_width , //0-1bit,1-1.5bit,2-2bit input wire [ 7:0] i_user_tx_data , input wire i_user_tx_valid , output reg o_user_tx_ready , output reg o_uart_tx ); //////////////////////////////////////////////////////////////////// //reg define reg [ 7:0] ri_user_tx_data ; reg [ 3:0] r_cnt_bit ; reg [15:0] r_cnt_baud ; reg [ 7:0] r_tx_data ; reg r_tx_check ; reg [ 3:0] r_data_width ; reg [ 3:0] r_stop_width ; //wire define wire w_active ; wire w_tx_en ; wire [ 3:0] w_bit_len ; //////////////////////////////////////////////////////////////////// assign w_active = i_user_tx_valid & o_user_tx_ready ; assign w_tx_en = (r_cnt_baud == i_uart_baud_cnt - 1 ); assign w_bit_len = 2 + r_data_width + r_stop_width ; //start+data+check+stop //////////////////////////////////////////////////////////////////// always @(*) begin case(i_uart_bit_width) 0 : r_data_width = 8 ; 1 : r_data_width = 7 ; 2 : r_data_width = 6 ; 3 : r_data_width = 5 ; default : r_data_width = 8 ; endcase end always @(*) begin case(i_uart_stop_width) 0 : r_stop_width = 1 ; 1 : r_stop_width = 2 ; 2 : r_stop_width = 2 ; default : r_stop_width = 1 ; endcase end always @(posedge i_clk) begin ri_user_tx_data <= i_user_tx_data ; end always @(posedge i_clk) begin if (i_rst) r_cnt_baud <= 0 ; else if (!o_user_tx_ready && r_cnt_baud < i_uart_baud_cnt - 1) r_cnt_baud <= r_cnt_baud + 1 ; else r_cnt_baud <= 0 ; end always @(posedge i_clk ) begin if (i_rst) o_user_tx_ready <= 1 ; else if (w_active) o_user_tx_ready <= 0 ; else if ((i_uart_stop_width==1) && (r_cnt_bit == w_bit_len - 2) && (i_uart_check == 0) && (r_cnt_baud == (i_uart_baud_cnt>>1) - 1 )) o_user_tx_ready <= 1 ; else if ((i_uart_stop_width==1) && (r_cnt_bit == w_bit_len - 1) && (i_uart_check > 0) && (r_cnt_baud == (i_uart_baud_cnt>>1) - 2 )) o_user_tx_ready <= 1 ; else if ((r_cnt_bit == w_bit_len - 2) && (i_uart_check == 0) && (r_cnt_baud == i_uart_baud_cnt - 2 )) o_user_tx_ready <= 1 ; else if ((r_cnt_bit == w_bit_len - 1) && (i_uart_check > 0) && (r_cnt_baud == i_uart_baud_cnt - 2 )) o_user_tx_ready <= 1 ; end always @(posedge i_clk ) begin if (i_rst) r_cnt_bit <= 0 ; else if (o_user_tx_ready) r_cnt_bit <= 0 ; else if (!o_user_tx_ready && w_tx_en) r_cnt_bit <= r_cnt_bit + 1 ; end always @(posedge i_clk ) begin if (i_rst) r_tx_data <= 0 ; else if (w_active) r_tx_data <= ri_user_tx_data ; else if (!o_user_tx_ready && w_tx_en) r_tx_data <= r_tx_data >> 1 ; end always @(posedge i_clk ) begin if (i_rst) o_uart_tx <= 1 ; // idle else if (w_active) o_uart_tx <= 0 ; //send start else if ((r_cnt_bit == r_data_width) && (i_uart_check > 0) && w_tx_en) o_uart_tx <= i_uart_check == 1 ? ~r_tx_check : r_tx_check ; //send check else if ((r_cnt_bit == r_data_width) && (i_uart_check == 0) && w_tx_en) o_uart_tx <= 1 ; //send stop else if ((r_cnt_bit == r_data_width+1) && (i_uart_check > 0) && w_tx_en) o_uart_tx <= 1 ; //send stop else if (!o_user_tx_ready && w_tx_en && (r_cnt_bit < r_data_width)) o_uart_tx <= r_tx_data[0] ; //send data else if (o_user_tx_ready) o_uart_tx <= 1 ; // idle end always @(posedge i_clk) begin if (i_rst) r_tx_check <= 0 ; else if (w_active) r_tx_check <= 0 ; else if (!o_user_tx_ready && w_tx_en && (r_cnt_bit < r_data_width)) r_tx_check <= r_tx_check ^ r_tx_data[0] ; end endmodule |
联合仿真
仿真代码
`timescale 1ns / 1ps module tb_UART( ); reg i_clk ; reg i_rst ; reg [31:0] i_uart_baud_cnt ; reg [ 1:0] i_uart_check ; //0-no,1-odd,2-even reg [ 1:0] i_uart_bit_width ; //0-8bit,1-7bit,2-6bit,3-5bit reg [ 1:0] i_uart_stop_width ; //0-1bit,1-1.5bit,2-2bit reg [ 7:0] i_user_tx_data ; reg i_user_tx_valid ; wire o_user_tx_ready ; wire o_uart_tx ; wire [ 7:0] w_usr_rx_data ; wire w_usr_rx_valid ; wire o_user_rx_error ; reg flag ; wire w_active = i_user_tx_valid & o_user_tx_ready ; initial begin i_clk = 0 ; i_rst = 1 ; i_uart_check = 0 ; i_uart_bit_width = 0 ; i_uart_stop_width= 0 ; i_uart_baud_cnt = 8 ; flag = 0 ; #100; @(posedge i_clk) i_rst = 0 ; #200; @(posedge i_clk); send_data(0,0,0); wait(flag); @(posedge i_clk); send_data(1,0,0); wait(flag); @(posedge i_clk); send_data(2,0,0); wait(flag); @(posedge i_clk); send_data(0,2,0); wait(flag); @(posedge i_clk); send_data(1,2,0); wait(flag); @(posedge i_clk); send_data(2,2,0); wait(flag); @(posedge i_clk); send_data(0,3,1); wait(flag); @(posedge i_clk); send_data(1,3,1); wait(flag); @(posedge i_clk); send_data(2,3,1); end always #5 i_clk = ~i_clk ; task send_data(input [3:0] check, input [3:0] bitwidth, input [3:0] stopwidth); begin: send_data_task flag = 0 ; i_uart_check = check ; i_uart_bit_width = bitwidth ; i_uart_stop_width= stopwidth ; @(posedge i_clk); wait(o_user_tx_ready); @(posedge i_clk); case (bitwidth) 0 : begin i_user_tx_data = 8'hFF ; i_user_tx_valid = 1 ; end 1 : begin i_user_tx_data = 8'h7F ; i_user_tx_valid = 1 ; end 2 : begin i_user_tx_data = 8'h3F ; i_user_tx_valid = 1 ; end 3 : begin i_user_tx_data = 8'h1F ; i_user_tx_valid = 1 ; end endcase @(posedge i_clk); case (bitwidth) 0 : begin i_user_tx_data = 8'hFF ; i_user_tx_valid = 0 ; end 1 : begin i_user_tx_data = 8'h7F ; i_user_tx_valid = 0 ; end 2 : begin i_user_tx_data = 8'h3F ; i_user_tx_valid = 0 ; end 3 : begin i_user_tx_data = 8'h1F ; i_user_tx_valid = 0 ; end endcase @(posedge i_clk); wait(o_user_tx_ready); @(posedge i_clk); case (bitwidth) 0 : begin i_user_tx_data = 8'hAA ; i_user_tx_valid = 1 ; end 1 : begin i_user_tx_data = 8'h2A ; i_user_tx_valid = 1 ; end 2 : begin i_user_tx_data = 8'h2A ; i_user_tx_valid = 1 ; end 3 : begin i_user_tx_data = 8'h0A ; i_user_tx_valid = 1 ; end endcase @(posedge i_clk); case (bitwidth) 0 : begin i_user_tx_data = 8'hAA ; i_user_tx_valid = 0 ; end 1 : begin i_user_tx_data = 8'h2A ; i_user_tx_valid = 0 ; end 2 : begin i_user_tx_data = 8'h2A ; i_user_tx_valid = 0 ; end 3 : begin i_user_tx_data = 8'h0A ; i_user_tx_valid = 0 ; end endcase @(posedge i_clk); wait(o_user_tx_ready); @(posedge i_clk); case (bitwidth) 0 : begin i_user_tx_data = 8'hA8 ; i_user_tx_valid = 1 ; end 1 : begin i_user_tx_data = 8'h28 ; i_user_tx_valid = 1 ; end 2 : begin i_user_tx_data = 8'h28 ; i_user_tx_valid = 1 ; end 3 : begin i_user_tx_data = 8'h08 ; i_user_tx_valid = 1 ; end endcase @(posedge i_clk); case (bitwidth) 0 : begin i_user_tx_data = 8'hA8 ; i_user_tx_valid = 0 ; end 1 : begin i_user_tx_data = 8'h28 ; i_user_tx_valid = 0 ; end 2 : begin i_user_tx_data = 8'h28 ; i_user_tx_valid = 0 ; end 3 : begin i_user_tx_data = 8'h08 ; i_user_tx_valid = 0 ; end endcase @(posedge i_clk); wait(o_user_tx_ready); flag = 1 ; end endtask UART_tx u_UART_tx( .i_clk (i_clk ), .i_rst (i_rst ), .i_uart_baud_cnt (i_uart_baud_cnt ), .i_uart_check (i_uart_check ), .i_uart_bit_width (i_uart_bit_width ), .i_uart_stop_width (i_uart_stop_width ), .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 UART_rx_u ( .i_clk (i_clk ), .i_rst (i_rst ), .i_uart_rx (o_uart_tx ), .i_uart_baud_cnt (i_uart_baud_cnt), .i_uart_check (i_uart_check ), .i_uart_bit_width (i_uart_bit_width ), .i_uart_stop_width (i_uart_stop_width ), .o_user_rx_data (w_usr_rx_data ), .o_user_rx_valid (w_usr_rx_valid ), .o_user_rx_error (o_user_rx_error) ); endmodule |
仿真结果
输入与输出结果一致。