异步串行通信(UART)接口之RS232接口协议,现主要应用于模块间通信;
这里完成一次串口回传功能仿真及验证,完成后的模块可嵌入其他应用系统;
RS232接口使用双线通信,波特率9600;
a. rx 表示PC 端的串口发送端(对于FPGA 端,为串口的接收端),在串口空闲状态时,rx 一直处于高电平。若PC 端需要通过串口发送数据,则需要将rx 从高拉低,表示串口发送的起始位,接着依次发送8bit 的数据(最低位优先),发送完最后1bit 数据后,rx 保持高电平(无校验位);
b. 由于PC 端与FPGA 端处于两个时钟域,所以在FPGA 端需要进行跨时钟域处理,即对rx 进行打两拍处理(rx_t,rx_tt),rx_ttt 是rx 的3 级寄存器;
c. rx_flag 是串口处于接收状态的标志信号,rx_flag 拉高的条件是rx 从空闲状态发送起始位的下降沿,拉低条件是接收完一帧串口数据(8bit);
d. baud_cnt 为波特率计数器,FPGA 使用时钟为50MHz,所以串口发送1bit的数据占用的时钟周期为:(1/9600)x109÷20≈5208,该计数器自加的条件为rx_flag 为高,当计数满5207 时,自动清零;
e. bit_flag 为检测rx 上串口数据的标志信号,只有当baud_cnt 计数到2603时,bit_flag 才会拉高。选在baud_cnt 计数器的中间值来检测串口数据,是为提高检测数据的可靠性;
f. bit_cnt 为已接收一帧串口数据的bit 数,其自加条件为bit_flag,当计数到8,即表示接收完一帧数据后清零;
g. rx_data 是接收串口数据的寄存器,位宽为8,该寄存器使用了位拼接操作,其目的是对接收到的串口数据进行移位,将接收到的1bit 数据构造成8bit 的数据,也可以理解成串转并的一个操作;
h. po_flag 为接收完一帧串口数据的标志信号,用于提供给外部模块检测接收到的串口数据,即rx_data 寄存器的值。
发送模块设计:
module rs232_t( //system signals input sclk , input s_rst_n , //input signals input [ 7:0] tx_data , input pi_flag , //output signals output reg tx ); //===================================================================\ // ========= Define Parameter and Internal Signals ========== //===================================================================/ parameter BOUND = 5208 ; reg flag_tx ; reg [12:0] bound_cnt ; reg bit_flag ; reg [ 8:0] bit_cnt ; reg [ 7:0] data ; //=========================================================================== // ************** Main Code ************** //=========================================================================== // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) flag_tx <= 1'b0; else if(pi_flag == 1'b1 && flag_tx == 1'b0) flag_tx <= 1'b1; else if(bit_cnt >= 'd8 && bound_cnt >= BOUND) flag_tx <= 1'b0; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) bound_cnt <= 'd0; else if(bound_cnt >= BOUND) bound_cnt <= 'd0; else if(flag_tx ==1'b1) bound_cnt <= bound_cnt + 1'b1; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) bit_flag <= 1'b0; else if(bound_cnt == BOUND) bit_flag <= 1'b1; else bit_flag <= 1'b0; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) bit_cnt <= 'd0; else if(bit_cnt >= 'd8 && bit_flag == 1'b1) bit_cnt <= 'd0; else if(bit_flag ==1'b1) bit_cnt <= bit_cnt + 1'b1; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) data <= 'd0; else if(pi_flag == 1'b1) data <= tx_data; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) tx <= 1'b1; else if(pi_flag == 1'b1) tx <= 1'b0; else if(bit_flag == 1'b1 && flag_tx == 1'b1) tx <= data[bit_cnt]; else if(flag_tx == 1'b0) tx <= 1'b1; end endmodule
接收模块设计:
module rs232_r( //system signals input sclk , input s_rst_n , //input signals input rx , //output signals output reg [ 7:0] rx_data , output reg po_flag ); //===================================================================\ // ========= Define Parameter and Internal Signals ========== //===================================================================/ parameter BOUND = 5208 ; reg rx_r1 ; reg rx_r2 ; reg rx_r3 ; reg flag_rx ; reg [12:0] bound_cnt ; reg bit_flag ; reg [ 8:0] bit_cnt ; //=========================================================================== // ************** Main Code ************** //=========================================================================== // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) begin rx_r1 <= 1'b1; rx_r2 <= 1'b1; rx_r3 <= 1'b1; end else begin rx_r1 <= rx; rx_r2 <= rx_r1; rx_r3 <= rx_r2; end end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) flag_rx <= 1'b0; else if(rx_r2 == 1'b0 && rx_r3 == 1'b1) flag_rx <= 1'b1; else if(bit_cnt == 'd0 && bound_cnt >= BOUND) flag_rx <= 1'b0; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) bound_cnt <= 'd0; else if(bound_cnt >= BOUND) bound_cnt <= 'd0; else if(flag_rx ==1'b1) bound_cnt <= bound_cnt + 1'b1; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) bit_flag <= 1'b0; else if(bound_cnt == BOUND/2) bit_flag <= 1'b1; else bit_flag <= 1'b0; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) bit_cnt <= 'd0; else if(bit_cnt >= 'd8 && bit_flag == 1'b1) bit_cnt <= 'd0; else if(bit_flag ==1'b1) bit_cnt <= bit_cnt + 1'b1; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) rx_data <= 'b0; else if(bit_flag == 1'b1) rx_data <= {rx_r3,rx_data[7:1]}; end // always @(posedge sclk or negedge s_rst_n) begin if(s_rst_n == 1'b0) po_flag <= 1'b0; else if(bit_flag == 1'b1 && bit_cnt >= 'd8) po_flag <= 1'b1; else po_flag <= 1'b0; end endmodule
为方便仿真和验证,设计顶层模块将发送接收模块封装:
module test( //system signals input sclk , input s_rst_n , input rx , output wire tx ); //===================================================================\ // ========= Define Parameter and Internal Signals ========== //===================================================================/ wire [ 7:0] rx_data ; wire pi_flag ; //=========================================================================== // ************** Main Code ************** //=========================================================================== rs232_t rs232_t_inst( .sclk (sclk ), .s_rst_n (s_rst_n ), .tx_data (rx_data ), .pi_flag (pi_flag ), .tx (tx ) ); rs232_r rs232_r_inst( .sclk (sclk ), .s_rst_n (s_rst_n ), .rx (rx ), .rx_data (rx_data ), .po_flag (pi_flag ) ); endmodule
发送模块的仿真模块设计:
`timescale 1ns/1ns module tb_rs232_t; reg sclk; reg s_rst_n; wire [ 7:0] tx_data; reg pi_flag; wire tx; assign tx_data = 8'b00101010; initial begin sclk = 1'b1; s_rst_n<= 1'b0; pi_flag<= 1'b0; #100 s_rst_n<= 1'b1; pi_flag<= 1'b1; #20 pi_flag<= 1'b0; end always #10 sclk = ~sclk; defparam rs232_t_inst.BOUND = 6; rs232_t rs232_t_inst( .sclk (sclk ), .s_rst_n (s_rst_n ), .tx_data (tx_data ), .pi_flag (pi_flag ), .tx (tx ) ); endmodule
顶层模块的仿真模块设计:
`timescale 1ns/1ns module tb_test; reg sclk; reg s_rst_n; reg pi_flag; reg rx; wire tx; initial begin sclk = 1'b1; s_rst_n <= 1'b0; rx <= 1'b1; #100 s_rst_n <= 1'b1; #20 rx <= 1'b0; #140 rx <= 1'b0; #140 rx <= 1'b0; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b0; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b0; #140 rx <= 1'b0; #140 rx <= 1'b0; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b1; #140 rx <= 1'b0; end always #10 sclk = ~sclk; defparam test_inst.rs232_t_inst.BOUND = 6; defparam test_inst.rs232_r_inst.BOUND = 6; test test_inst( .sclk (sclk ), .s_rst_n (s_rst_n ), .rx (rx ), .tx (tx ) ); endmodule
下载到芯片完成功能验证时,可使用COM接口或转USB接口与上位机进行通信验证;
。。。。。。。。。。。。。。。待续。。。