UART 组装与仿真
上几节内容介绍了UART的组成部分发送(tx.v), 接收(rx.v)以及波特率发生器(bd_rate_en.v)等原理及代码,本节内容介绍如何将各个模块组装在一起形成一个完整的UART收发系统UART.v。
一、rx采用中心对齐的模块。
- UART组装的程序
module UART #( parameter BAUD_RATE = 115200, parameter PARITY = "ODD" ) ( input inclk, input tx_req, input [7:0] tx_data, output tx_ack, output tx, input rx, input rx_ack, output rx_rdy, output [7:0] rx_data, output rst, output sys_clk ); wire tx_bd_en; wire rx_bd_en; wire locked; assign rst = !locked; uart_pll uart_pll_inst ( .areset (1'b0), .inclk0 (inclk), .c0 (sys_clk), //sys_clk 72Mhz .locked (locked) ); baud_rate_en #( .BAUD_RATE (115200), .FREQUENCY (72000000) ) bau_rate_en_inst ( .clk (sys_clk), .rst (rst), .tx_bd_en (tx_bd_en), .rx_bd_en (rx_bd_en) ); tx #( .PARITY (PARITY), .STOP_BIT (1) ) txd_inst ( .rst (rst), .clk (sys_clk), .tx_bd_en (tx_bd_en), .tx_data (tx_data), .tx_rdy (tx_req), .tx_ack (tx_ack), .tx (tx) ); rx_center #( .PARITY (PARITY), //"ODD"--odd parity, "EVEN"--even parity, others--> no parity .STOP_BIT (1) ) rx_certer_inst ( .sys_clk (sys_clk), .rst (rst), .rx (rx), .bd8_rate (rx_bd_en), .rx_data (rx_data), .rx_rdy (rx_rdy) ); endmodule
- 仿真程序
`timescale 1 ns / 1 ps module test_UART ( ); parameter PARITY = "none"; parameter PERIOD = 20; reg inclk; reg rx_ack; wire rx_rdy; wire [7:0] rx_data; initial begin inclk = 0; end always #(PERIOD/2) inclk = ~inclk; wire rst; wire sys_clk; reg tx_req; reg [7:0] tx_data; wire tx_ack; wire tx_rx; reg [1:0] tx_st; //模拟发送协议,生成数据 always@(posedge sys_clk or posedge rst) if(rst) begin tx_st <= 0; tx_req <= 0; tx_data <= 0; end else begin case(tx_st) 0: begin tx_data <= 0; tx_req <= 0; tx_st <= 1; end 1: begin tx_req <= 1'b1; tx_st <= 2; end 2: begin if(tx_ack) begin tx_req <= 1'b0; tx_st <= 3; end end 3: begin tx_data <= tx_data + 1; tx_st <= 1; end default: tx_st <= 0; endcase end always@(posedge sys_clk or posedge rst) if(rst) begin rx_ack = 0; end else begin rx_ack = 0; if(rx_rdy) rx_ack = 1'b1; end UART #( .BAUD_RATE (115200), .PARITY (PARITY) ) UART_inst ( .inclk (inclk), .tx_req (tx_req), .tx_data (tx_data), .tx_ack (tx_ack), .tx (tx_rx), //利用tx_rx,进行回环测试 .rx (tx_rx), .rx_ack (rx_ack), .rx_rdy (rx_rdy), .rx_data (rx_data), .rst (rst), .sys_clk (sys_clk) ); endmodule
- 仿真波形(Modelsim)
图1
从图1的波形可以看出,经过回环测试,接收数据可以正确接收数据。
2. RXD部分用判多替代中心对齐方式
module UART #( parameter BAUD_RATE = 115200, parameter PARITY = "ODD" ) ( input inclk, input tx_req, input [7:0] tx_data, output tx_ack, output tx, input rx, input rx_ack, output rx_rdy, output [7:0] rx_data, output rst, output sys_clk ); wire tx_bd_en; wire rx_bd_en; wire locked; assign rst = !locked; uart_pll uart_pll_inst ( .areset (1'b0), .inclk0 (inclk), .c0 (sys_clk), //sys_clk 72Mhz .locked (locked) ); baud_rate_en #( .BAUD_RATE (115200), .FREQUENCY (72000000) ) bau_rate_en_inst ( .clk (sys_clk), .rst (rst), .tx_bd_en (tx_bd_en), .rx_bd_en (rx_bd_en) ); tx #( .PARITY (PARITY), .STOP_BIT (1) ) txd_inst ( .rst (rst), .clk (sys_clk), .tx_bd_en (tx_bd_en), .tx_data (tx_data), .tx_rdy (tx_req), .tx_ack (tx_ack), .tx (tx) ); rx_more_one #( .PARITY (PARITY), //"ODD"--odd parity, "EVEN"--even parity, others--> no parity .STOP_BIT (1) ) rx_more_one_inst ( .sys_clk (sys_clk), .rst (rst), .rx (rx), .bd8_rate (rx_bd_en), .rx_data (rx_data), .rx_rdy (rx_rdy) ); endmodule
仿真波形:仿真程序依然采用上面的仿真程序,得到波形如图2
图2
加载rx_more_one 变量到仿真波形中,观察其中一位的接收,移位,求和,判多的结果看看是否与预期的设计相符,图3,4显示了停止位的解码过程。
图3
图4
图4的红框标注了sample_bit,count_one,rx_bit与状态机及sam[le_count_cs之间的逻辑与时序关系。最终测试在停止位解码时,count_one得到8个1,提高了判决的冗余度。
练习题:
- 将奇偶校验设为奇校验,重新仿真,并验证接收数据的正确性。
- 分析对照仿真波形rx_r[1],sample_st_cs, sample_count_cs,sample_bit,count_one,rx_bit的时序关系,并分析在判多时为什么要如下语句出现:
sample_count_cs_r <= sample_count_cs; if(sample_count_cs_r == 7) begin //delay one clock case(sample_st_cs) FIRST_BIT: rx_data_tmp[0] = rx_bit; SEC_BIT: rx_data_tmp[1] = rx_bit; THIRD_BIT: rx_data_tmp[2] = rx_bit; FOUTH_BIT: rx_data_tmp[3] = rx_bit; FIF_BIT: rx_data_tmp[4] = rx_bit; SIX_BIT: rx_data_tmp[5] = rx_bit; SEVN_BIT: rx_data_tmp[6] = rx_bit; EIGTH_BIT: begin rx_data_tmp[7] = rx_bit; rx_rdy_tmp = 1'b1; end default:; endcase
而不是直接采用if(sample_count_cs == 7)begin 的方式实现 ?