fpga项目: uart收发通信 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
1)说明
- 完全自己手画时序图,完全自己实现。
- 采用了状态机的方法。代码是从spi/mcu修改过来的,感觉这种写法可以统一。
- 写一个通用的gen_tx_data.v,每10ms发送一次data和start_pulse,这个可以用于测试任意接口。我们先用它测试uart_tx.v,测试完了后,再用uart_tx.v的输出去测试uart_rx.v,形成一个回环测试。这也算一个小技巧吧。
2)时序图
uart_tx时序图
uart_rx时序图(注意rx_s和rx_ss是用于跨时钟域同步)
3)代码
代码结构
代码如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/08 19:16:41
// Design Name:
// Module Name: rs232
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module rs232(
input clk,
input rst,
input rx,
output tx
);
wire [7:0] pi_data;
wire [7:0] po_data;
assign rst_n=~rst;
uart_tx
#(.FCLK(27_000_000),
.BPS(115200)
)
u_uart_tx(
.clk(clk),
.rst_n(rst_n),
.pi_start_pulse(end_pulse_rx),
.pi_data(po_data),
.tx(tx),
.end_pulse(end_pulse_tx)
);
uart_rx
#(.FCLK(27_000_000),
.BPS(115200)
)
u_uart_rx(
.clk(clk),
.rst_n(rst_n),
.rx(rx),
.po_data(po_data),
.end_pulse(end_pulse_rx)
);
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/08 18:34:12
// Design Name:
// Module Name: uart_rx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_rx(
input clk,
input rst_n,
input rx,
output reg [7:0] po_data,
output reg end_pulse
);
parameter FCLK=50_000_000;
parameter BPS=9600;
parameter CNT_MAX=FCLK/BPS-1;
parameter IDLE=3'b001;
parameter CMD=3'b010;
parameter DATA=3'b100;
reg [12:0] baud_cnt; //50MHz/9600=5208
reg [3:0] bit_cnt;
reg [2:0] state;
reg rx_s;
reg rx_ss;
reg rx_sss;
wire end_pulse_r;
reg [7:0] data_r;
//sync
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
rx_s<=0;
rx_ss<=0;
rx_sss<=0;
end
else begin
rx_s<=rx;
rx_ss<=rx_s;
rx_sss<=rx_ss;
end
//start_pulse
assign start_pulse=(~rx_ss)&rx_sss;
//baud_cnt
always @(posedge clk or negedge rst_n)
if(rst_n==0)
baud_cnt<=0;
else if(start_pulse && state==IDLE)
baud_cnt<=0;
else if(baud_cnt==CNT_MAX)
baud_cnt<=0;
else if(state!=IDLE)
baud_cnt<=baud_cnt+1;
//end_pulse_r
assign end_pulse_r=(bit_cnt==8)&&(baud_cnt==CNT_MAX);
//cnt_bytes
always @(posedge clk or negedge rst_n)
if(rst_n==0)
bit_cnt<=0;
else if(bit_cnt==8 && baud_cnt==CNT_MAX)
bit_cnt<=0;
else if(baud_cnt==CNT_MAX)
bit_cnt<=bit_cnt+1;
//state
always @(posedge clk or negedge rst_n)
if(rst_n==0)
state<=IDLE;
else case(state)
IDLE: if(start_pulse)
state<=DATA;
DATA: if(bit_cnt==8 && baud_cnt==CNT_MAX)
state<=IDLE;
default: state<=state;
endcase
//data_r
always @(posedge clk or negedge rst_n)
if(rst_n==0)
data_r<=8'h00;
else if(state==DATA && baud_cnt==CNT_MAX/2 && (bit_cnt>=1 && bit_cnt<=8))
data_r<={rx_sss,data_r[7:1]};
//po_data
always @(posedge clk or negedge rst_n)
if(rst_n==0)
po_data<=8'h00;
else if(end_pulse_r)
po_data<=data_r;
//end_pulse
always @(posedge clk or negedge rst_n)
if(rst_n==0)
end_pulse<=0;
else
end_pulse<=end_pulse_r;
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/08 16:28:05
// Design Name:
// Module Name: uart_tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_tx(
input clk,
input rst_n,
input pi_start_pulse,
input [7:0] pi_data,
output reg tx,
output end_pulse
);
parameter FCLK=50_000_000;
parameter BPS=9600;
parameter CNT_MAX=FCLK/BPS-1;
parameter IDLE=3'b001;
parameter CMD=3'b010;
parameter DATA=3'b100;
reg [12:0] baud_cnt; //50MHz/9600=5208
reg [3:0] bit_cnt;
reg [2:0] state;
//baud_cnt
always @(posedge clk or negedge rst_n)
if(rst_n==0)
baud_cnt<=0;
else if(pi_start_pulse)
baud_cnt<=0;
else if(baud_cnt==CNT_MAX)
baud_cnt<=0;
else if(state!=IDLE)
baud_cnt<=baud_cnt+1;
//end_pulse
assign end_pulse=(bit_cnt==9)&&(baud_cnt==CNT_MAX);
//cnt_bytes
always @(posedge clk or negedge rst_n)
if(rst_n==0)
bit_cnt<=0;
else if(bit_cnt==9 && baud_cnt==CNT_MAX)
bit_cnt<=0;
else if(baud_cnt==CNT_MAX)
bit_cnt<=bit_cnt+1;
//state
always @(posedge clk or negedge rst_n)
if(rst_n==0)
state<=IDLE;
else case(state)
IDLE: if(pi_start_pulse)
state<=DATA;
DATA: if(bit_cnt==9 && baud_cnt==CNT_MAX)
state<=IDLE;
default: state<=state;
endcase
//tx
always @(posedge clk or negedge rst_n)
if(rst_n==0)
tx<=1;
else if(state==DATA && baud_cnt==1) begin
if(bit_cnt==0 )
tx<=0;
else if(bit_cnt>=1 && bit_cnt<=8)
tx<=pi_data[bit_cnt-1];
else if(bit_cnt==9)
tx<=1;
end
endmodule
4)testbench代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/08 16:44:51
// Design Name:
// Module Name: gen_tx_data
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module gen_tx_data(
output clk,
output rst_n,
output reg po_start_pulse,
output reg [7:0] po_data
);
parameter FCLK=50_000_000;
parameter DLY_MS=FCLK/100;
parameter EVENT_MAX=10;
reg rst_n;
reg clk;
reg [19:0] timer;
reg [5:0] event_t;
reg timer_flag;
wire [5:0] event_o;
initial begin
rst_n=0;
#100;
rst_n=1;
end
initial begin
clk=0;
forever #10 clk=~clk;
end
always @(posedge clk or negedge rst_n)
if(rst_n==0)
timer<=0;
else if(timer==DLY_MS-1)
timer<=0;
else
timer<=timer+1;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
timer_flag<=0;
else if(timer==DLY_MS-2)
timer_flag<=1;
else
timer_flag<=0;
always @(posedge clk or negedge rst_n)
if(rst_n==0)
event_t<=0;
else if(event_t==EVENT_MAX)
event_t<=0;
else if(timer_flag)
event_t<=event_t+1;
assign event_o=timer_flag? event_t: 0; //generate counter-value pulse
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
po_start_pulse<=0;
po_data<=0;
end
else if(event_o)
case(event_o)
1: send_data(8'h11);
2: send_data(8'h29);
3: send_data(8'h3a);
endcase
else
po_start_pulse<=0;
task send_data;
input [7:0] datax;
begin
po_start_pulse<=1;
po_data<=datax;
end
endtask
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/12/08 17:10:04
// Design Name:
// Module Name: tb_uart_tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_uart_tx;
wire [7:0] pi_data;
wire [7:0] po_data;
gen_tx_data
#(.FCLK(50_000))
u_gen_tx_data(
.clk(clk),
.rst_n(rst_n),
.po_start_pulse(pi_start_pulse),
.po_data(pi_data)
);
uart_tx
#(.FCLK(50_000))
u_uart_tx(
.clk(clk),
.rst_n(rst_n),
.pi_start_pulse(pi_start_pulse),
.pi_data(pi_data),
.tx(tx),
.end_pulse(end_pulse_tx)
);
uart_rx
#(.FCLK(50_000))
u_uart_rx(
.clk(clk),
.rst_n(rst_n),
.rx(tx),
.po_data(po_data),
.end_pulse(end_pulse_rx)
);
endmodule
5)tang nano 20k引脚约束
//IO_LOC "clk" 10; //30MHz
//IO_LOC "clk" 11; //5MHz
IO_LOC "clk" 4; //27MHz
IO_LOC "rst" 88;
IO_LOC "rx" 70;
IO_LOC "tx" 69;
6)仿真波形
gen_tx_data.v --> uart_tx.v --> uart_rx.v