FPGA study notes
1. UART serial port protocol and serial port sender design 2
- Send multiple bytes
1.1 Serial port protocol transmitter design_multi-byte
(1). Overall block diagram of the serial port protocol transmitter
Goal: key-press control serial port to send "HELLO" string
Knowledge points:
- wait function call
- Method of sending character string: control the input data, send each byte (8bits) once, and send multiple times in a row
- Hierarchical reference: call the signal name after instantiation. Variable (in test_bench)
(3). Verilog code
//----top---------------------------------------
module uart_tx_multbyte#(
parameter byte1 = "H",
parameter byte2 = "E",
parameter byte3 = "L",
parameter byte4 = "L",
parameter byte5 = "O",
parameter byte6 = "\n"
)
(
input clk,
input rst_n,
input key0,
output led,
output rs232_tx
);
reg send_en;
reg [7:0] data_byte;
wire key_state0;
wire key_flag0;
reg [2:0] cnt_byte;
wire tx_done;
uart_tx_r0 uut_uart(
.clk(clk),
.rst_n(rst_n),
.send_en(send_en),
.baud_set(3'd4),
.tx_done(tx_done),
.data_byte(data_byte),
.uart_state(led),
.rs232_tx(rs232_tx)
);
fsm_key_filter uut_key(
.clk(clk),
.rst_n(rst_n),
.key(key0),
.key_state(key_state0),
.key_flag(key_flag0)
);
//----counter--------------------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_byte <= 0;
else if(tx_done)
cnt_byte <= cnt_byte + 3'd1;
else if(key_flag0 & ! key_state0)
cnt_byte <= 3'd0;
//---------send_en---------------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
send_en <= 0;
else if(key_flag0 & ! key_state0)//press key
send_en <= 1;
else if(tx_done &(cnt_byte <= 3'd5))
send_en <= 1;
else
send_en <= 0;
//----data----------------------------------------
always@(*)
case(cnt_byte )
3'd0: data_byte <= byte1;
3'd1: data_byte <= byte2;
3'd2: data_byte <= byte3;
3'd3: data_byte <= byte4;
3'd4: data_byte <= byte5;
3'd5: data_byte <= byte6;
default: data_byte <= 0;
endcase
endmodule
//----按键以及抖动滤除----------------------------
module fsm_key_filter#(
parameter IDLE = 4'b0001,
parameter FILTER1 = 4'b0010,
parameter DOWN = 4'b0100,
parameter FILTER2 = 4'b1000
)
(
input clk, //50MHz 20us
input rst_n,
input key,
output key_flag,
output reg key_state
);
reg cnt_en;
reg cnt_full;
reg [19:0] cnt1;
//reg [19:0] cnt2;
reg [3:0] state;
reg key_syn1;
reg key_syn2;
reg key_reg1;
reg key_reg2;
wire pos_edge;
wire neg_edge;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
state <= IDLE;
cnt_en <= 1'b0;
end else
begin
case(state)
IDLE:
begin
if(neg_edge)begin
state <= FILTER1;
cnt_en <= 1'b1;
end else
begin
state <= IDLE;
cnt_en <= 1'b0;
end
end
FILTER1:
begin
if(cnt_full)//20ms
begin
state <= DOWN;
cnt_en <= 1'b0;
end
else if(pos_edge)
begin
state <= IDLE;
cnt_en <= 1'b0;
end else
begin
state <= FILTER1;
cnt_en <= cnt_en;
end
end
DOWN:
begin
if(pos_edge)begin
cnt_en <= 1'b1;
state <= FILTER2;
end else
begin
cnt_en <= 1'b0;
state <= DOWN;
end
end
FILTER2:
begin
if(cnt_full)
state <= IDLE;
else if(neg_edge)begin
cnt_en <= 1'b0;
state <= DOWN;
end
else
state <= FILTER2;
end
default: begin
state <= IDLE;
cnt_en <= 1'b0;
end
endcase
end
//----cnt--------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt1 <= 20'd0;
else if(cnt_en)
cnt1 <= cnt1 + 20'd1;
else
cnt1 <= 20'd0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_full <= 1'b0;
else if(cnt1 == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
end
//----asyn_key-->syn---------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_syn1 <= 1'b0;
key_syn2 <= 1'b0;
end else
begin
key_syn1 <= key;
key_syn2 <= key_syn1;
end
end
//----key edge detect--------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_reg1 <= 1'b0;
key_reg2 <= 1'b0;
end else
begin
key_reg1 <= key_syn2;
key_reg2 <= key_reg1;
end
end
assign neg_edge = (!key_reg1) & key_reg2;
assign pos_edge = key_reg1 & (!key_reg2);
//----key_flag---------------------------------------
assign key_flag = (cnt1 == 20'd999_999)? 1'b1:1'b0;
//----key_state--------------------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
key_state <= 1;
else if(cnt_full)
key_state <= ~key_state;
else
key_state <= key_state;
endmodule
//----单一字节串口发送----------------------------
//请看UART串口协议以及串口发送端设计1
//------------------------------------------------
//----testbench-----------------------------------
`timescale 1ns/1ns
`define clk_period 20
module uart_tx_multbyte_tb;
reg clk;
reg rst_n;
wire key0;
wire rs232_tx;
reg press;
wire led;
uart_tx_multbyte uut(
.clk(clk),
.rst_n(rst_n),
.key0(key0),
.led(led),
.rs232_tx(rs232_tx)
);
key0_model uut_model(
.press(press),
.key(key0)
);
initial
clk = 1;
always begin #(`clk_period/2) clk = ~clk;end
initial begin
rst_n = 0;
press = 0;
#(`clk_period*20+1)
rst_n = 1;
#(`clk_period*20+1);
press = 1;
#(`clk_period*20+1);
press = 0;
wait(uut.tx_done &(uut.cnt_byte == 3'd5));
#(`clk_period*200+1);
$stop;
end
endmodule
//----key0_model-------------------------------
`timescale 1ns/1ns
module key0_model(
input press,
output reg key
);
reg [15:0] myrand;
initial begin
key = 1;//before press
end
always@(posedge press)
press_key;
task press_key;
begin
repeat(50)begin
myrand = {
$random}%65536;//{$random}%6553(0~65535);{random}%65536:(-65535~65535)
#myrand; key = ~key;
end
key = 0;
#50000000;
repeat(50)begin
myrand = {
$random}%65536;//0~65535;
#myrand; key = ~key;
end
key = 1;
#25_000_000;
end
endtask
endmodule
(3). Modelsim simulation
(4). FPGA board-level verification
----The learning content comes from the video of Xiaomei's FPGA [Note]: Personal study notes, if there are mistakes, please
feel free to enlighten me, this is polite~~~