秦韵 FPGA 转载或原创(三)
高云FPGA GW2AR-18
今天就高云的Uart Master IP 的使用写一篇介绍,希望对大家的使用有所帮助。
**1)新建工程,选择器件,如GW2AR-18 **
使用IP Generateor 选择uart Master IP ,波特率可选,默认为9600,然后点击ok,完成ip的编辑。
该部分为ip生成的顶层接口,由于该ip内部封装了sram,故有留出的sram写接口和sram读接口,也支持调制解调功能(Modem),这次不讨论该部分内容,主要来实现uart的收发功能。
UART_MASTER_Top (
I_CLK,
I_RESETN,
I_TX_EN,
I_WADDR,
I_WDATA,
I_RX_EN,
I_RADDR,
O_RDATA,
SIN,
RxRDYn,
SOUT,
TxRDYn,
)
** 2) 关于这部分引脚的定义,可以参考IPUG511-1.4.pdf。 用不到的这里就不作说明了(直接删掉了,也不做例化),主要解释一下需要用到的引脚,串口的收发引脚 SOUT, SIN ,RXRDYn,TXRDYn为接收和发送数据准备好信号,再加上sram的读写接口,基本上可以完成对该ip的操作,在操作该Master IP的同时,有两种方式,一种通过操作寄存器来实现uart在状态的获取,两外一种,可直接通过RXRDY和TXRDY两个信号来实现UART的收发。接下来,不多说了,直接上代码了。**
// ===========Oooo==========================================Oooo========
// = Copyright (C) 2002-2020 WMPself.
// = All rights reserved.
// =====================================================================
//
// __ __ __
// \ \ / \ / /
// \ \ / /\ \ / /
// \ \/ / \ \/ / [File name ] sram_ctrl.v
// \ \/ \/ / [Description ] UART Master Controller
// /\/\ /\/\ [Timestamp ] Thursday Oct 2 19:53:30 2020
// / /\ \ / /\ \ [version ] 1.0.0
// / / \ \/ / \ \
// /_/ \__/ \_\
//
//
// ===========Oooo==========================================Oooo========
// Code Revision History :
// --------------------------------------------------------------------
// Ver: | Author |Mod. Date |Changes Made:
// V1.0 | wmp |10/02/20 |Initial version
// ===========Oooo==========================================Oooo========
`define IF_DATA_WIDTH 8
module sram_ctrl(
input clk,
input rst_n,
input start_cfg,
input start_ier_en,
input start_w,
input start_r,
output I_TX_EN,
output [2:0] I_WADDR,
output [`IF_DATA_WIDTH-1:0] I_WDATA,
output I_RX_EN,
output [2:0] I_RADDR,
input [`IF_DATA_WIDTH-1:0] O_RDATA,
input [`IF_DATA_WIDTH-1:0] i_wr_data,
output reg error_flag,
output receive_flag,
output [`IF_DATA_WIDTH-1:0] o_rd_data,
output o_rd_data_valid
);
//*************************************************************************
localparam CFG_LCR_STR = 0;
localparam CFG_LCR_STP = 1;
localparam CFG_LCR_DON = 2;
localparam CFG_IER_STR = 3;
localparam CFG_IER_STP = 4;
localparam CFG_IER_DON = 5;
localparam WR_IDE = 4'h0;
localparam RW_LSR_IDE = 4'h1;
localparam RW_LSR_STR = 4'h2;
localparam RW_LSR_STP = 4'h3;
localparam RW_LSR_DON = 4'h4;
//localparam W_THR_IDE = 4'h4;
localparam W_THR_STR = 4'h5;
localparam W_THR_STP = 4'h6;
localparam W_THR_DON = 4'h7;
localparam R_LSR_IDE = 4'h8;
localparam R_LSR_STR = 4'h9;
localparam R_LSR_STP = 4'ha;
localparam R_LSR_DON = 4'hb;
localparam R_RBR_IDE = 4'hc;
localparam R_RBR_STR = 4'hd;
localparam R_RBR_STP = 4'he;
localparam R_RBR_DON = 4'hf;
localparam RD_IIR_IDE = 3'h0;
localparam RD_IIR_STR = 3'h1;
localparam RD_IIR_STP = 3'h2;
localparam RD_IIR_DON = 3'h3;
localparam RD_RBR_IDE = 3'h4;
localparam RD_RBR_STR = 3'h5;
localparam RD_RBR_STP = 3'h6;
localparam RD_RBR_DON = 3'h7;
///
reg start_dl;
reg cfg_tx_en;
reg [2:0] cfg_waddr;
reg [7:0] cfg_wdata;
reg [2:0] cfg_state;
reg cfg_done;
reg tx_en;
reg [2:0] waddr;
reg [7:0] wdata;
reg wr_rx_en;
reg [2:0] wr_raddr;
reg [7:0] wr_rdata;
reg [7:0] rdr_data; //使能中断接收后,打开该定义
reg [3:0] wr_state;
reg wr_done;
reg [7:0] wr_data_reg;
reg rd_rx_en;
reg [2:0] rd_raddr;
reg [2:0] rd_state;
reg rdr_valid;
///
assign receive_flag = wr_done;
assign I_TX_EN = cfg_done ? tx_en : cfg_tx_en;
assign I_WADDR = cfg_done ? waddr : cfg_waddr;
assign I_WDATA = cfg_done ? wdata : cfg_wdata;
assign I_RX_EN = cfg_done ? start_ier_en ? rd_rx_en : wr_rx_en : 1'b0;
assign I_RADDR = cfg_done ? start_ier_en ? rd_raddr : wr_raddr : 3'b000;
assign o_rd_data = start_ier_en ? ( rdr_valid ? rdr_data : 8'h0): 8'h0;
assign o_rd_data_valid = start_ier_en ? rdr_valid : 1'b0;
///
always @(posedge clk or negedge rst_n)
if(~rst_n)
start_dl <= 1'b0;
else
start_dl <= start_cfg;
always @(posedge clk or negedge rst_n)
if(~rst_n) begin
cfg_state <= 0;
cfg_tx_en <= 1'b0;
cfg_waddr <= 3'b000;
cfg_wdata <= 8'h00;
cfg_done <= 1'b0;
end
else begin
case(cfg_state)
CFG_LCR_STR:
if((start_dl == 1'b0) && (start_cfg == 1'b1))
begin
cfg_tx_en <= 1'b1;
cfg_waddr <= 3'b011; //0x03,LCR
cfg_wdata <= 8'h2B;
cfg_state <= CFG_LCR_STP;
end
else
begin
cfg_tx_en <= 1'b0;
cfg_state <= CFG_LCR_STR;
end
CFG_LCR_STP:
begin
cfg_tx_en <= 1'b0;
cfg_waddr <= 3'b000;
cfg_wdata <= 8'h00;
cfg_state <= CFG_LCR_DON;
end
CFG_LCR_DON:
begin
if(start_ier_en) begin
cfg_state <= CFG_IER_STR;
end
else begin
cfg_done <= 1'b1;
cfg_state <= CFG_LCR_STR;
end
end
CFG_IER_STR :
begin
cfg_tx_en <= 1'b1;
cfg_waddr <= 3'b001; //0x01,IER
cfg_wdata <= 8'h04;
cfg_state <= CFG_IER_STP;
end
CFG_IER_STP :
begin
cfg_tx_en <= 1'b0;
cfg_waddr <= 3'b000;
cfg_wdata <= 8'h00;
cfg_state <= CFG_IER_DON;
end
CFG_IER_DON :
begin
cfg_state <= CFG_LCR_STR;
cfg_done <= 1'b1;
end
default : cfg_state <= CFG_LCR_STR;
endcase
end
always @(posedge clk or negedge rst_n)
if(~rst_n) begin
wr_state <= 0;
tx_en <= 1'b0;
waddr <= 3'b000;
wdata <= 8'h00;
wr_rx_en <= 1'b0;
wr_raddr <= 3'b000;
wr_rdata <= 8'h00;
wr_done <= 1'b0;
wr_data_reg <= 8'd0;
error_flag <= 1'b0;
end
else begin
case(wr_state)
WR_IDE :
begin
if(cfg_done & start_w) begin
wr_state <= RW_LSR_IDE;
end
else if(cfg_done & start_r) begin
wr_state <= R_LSR_IDE;
end
end
RW_LSR_IDE :
begin
wr_rx_en <= 1'b1;
wr_raddr <= 3'b101; //0x05,LSR
wr_state <= RW_LSR_STR;
end
RW_LSR_STR :
begin
wr_rx_en <= 1'b0;
wr_state <= RW_LSR_STP;
end
RW_LSR_STP :
begin
wr_rdata <= O_RDATA;
wr_state <= RW_LSR_DON;
end
RW_LSR_DON :
begin
if(wr_rdata[6] == 1'b1) begin
wr_state <= W_THR_STR;
end
else if(wr_rdata[5] == 1'b1)
wr_state <= W_THR_STR;
else begin
wr_state <= WR_IDE;
end
end
W_THR_STR :
begin
tx_en <= 1'b1;
waddr <= 3'b000; //0x00,THR
wdata <= i_wr_data;
wr_data_reg <= i_wr_data;
wr_state <= W_THR_STP;
end
W_THR_STP :
begin
tx_en <= 1'b0;
waddr <= 3'b000;
wdata <= 8'h00;
wr_state <= W_THR_DON;
end
W_THR_DON :
begin
wr_state <= WR_IDE;
end
R_LSR_IDE :
begin
wr_rx_en <= 1'b1;
wr_raddr <= 3'b101; //0x05,LSR
wr_state <= R_LSR_STR;
end
R_LSR_STR :
begin
wr_rx_en <= 1'b0;
wr_state <= R_LSR_STP;
end
R_LSR_STP :
begin
wr_rdata <= O_RDATA;
wr_state <= R_LSR_DON;
end
R_LSR_DON :
begin
if(wr_rdata[0] == 1'b1) begin
wr_state <= R_RBR_IDE;
end
else begin
wr_state <= WR_IDE;
end
end
R_RBR_IDE :
begin
wr_rx_en <= 1'b1;
wr_raddr <= 3'b000; //0x000,RBR
wr_state <= R_RBR_STR;
end
R_RBR_STR :
begin
wr_rx_en <= 1'b0;
wr_state <= R_RBR_STP;
end
R_RBR_STP :
begin
wr_rdata <= O_RDATA;
wr_state <= R_RBR_DON;
end
R_RBR_DON :
begin
if(wr_done == 1'b1) begin
if(wr_rdata != wr_data_reg) begin
error_flag <= 1'b1;
end
wr_state <= WR_IDE;
end
else begin
error_flag <= 1'b0;
wr_done <= 1'b1;
wr_state <= R_RBR_IDE;
end
end
default : wr_state <= WR_IDE;
endcase
end
//************************************************
// * define isr[2] == 1'b1 , the regisiter is enable
// **********************************************
always @(posedge clk or negedge rst_n)
if(~rst_n) begin
rd_state <= 0;
rd_rx_en <= 1'b0;
rd_raddr <= 3'b000;
rdr_data <= 8'h00;
rdr_valid <= 1'b0;
end
else begin
case(rd_state)
RD_IIR_IDE :
begin
if(start_ier_en) begin
rd_rx_en <= 1'b1;
rd_raddr <= 3'b010; //0x05,LSR
rd_state <= RD_IIR_STR;
end
end
RD_IIR_STR :
begin
rd_rx_en <= 1'b0;
rd_state <= RD_IIR_STP;
end
RD_IIR_STP :
begin
rdr_data <= O_RDATA;
rd_state <= RD_IIR_DON;
end
RD_IIR_DON :
begin
if(rdr_data[2] == 1'b1) begin
rd_state <= RD_RBR_IDE;
end
else begin
rd_state <= RD_IIR_IDE;
end
end
RD_RBR_IDE :
begin
if(start_ier_en) begin
rd_rx_en <= 1'b1;
rd_raddr <= 3'b000; //0x05,LSR
rd_state <= RD_RBR_STR;
end
end
RD_RBR_STR :
begin
rd_rx_en <= 1'b0;
rd_state <= RD_RBR_STP;
end
RD_RBR_STP :
begin
rdr_data <= O_RDATA;
rdr_valid <= 1'b1;
rd_state <= RD_RBR_DON;
end
RD_RBR_DON :
begin
rdr_valid <= 1'b0;
rd_state <= RD_IIR_IDE;
end
default :
begin
rd_state <= RD_IIR_IDE;
end
endcase
end
endmodule
** 3)直接将驱动层的代码贴上来,可以直接调用来实现ip的控制,该部分我留下了中断方式的接口,未进行验证,如果有兴趣可进行验证,用过查询的方式实现起来比较简单,如果有兴趣,可以在fpga中跑软核,arm-m1或者riscv都欧克, 将该ip封装成AMBA 总线,挂载在AHB或者APB总线接口上,对于这部分的代码,也不算太难,主要是对该部分封装成总线形式。暂时就不上代码了。**
顶层接口module
// ===========Oooo==========================================Oooo========
// = Copyright (C) 2002-2020 WMPself.
// = All rights reserved.
// =====================================================================
//
// __ __ __
// \ \ / \ / /
// \ \ / /\ \ / /
// \ \/ / \ \/ / [File name ] uart.v
// \ \/ \/ / [Description ] UART Master Controller
// /\/\ /\/\ [Timestamp ] Thursday Oct 2 19:53:30 2020
// / /\ \ / /\ \ [version ] 1.0.0
// / / \ \/ / \ \
// /_/ \__/ \_\
//
//
// ===========Oooo==========================================Oooo========
// Code Revision History :
// --------------------------------------------------------------------
// Ver: | Author |Mod. Date |Changes Made:
// V1.0 | wmp |10/02/20 |Initial version
// ===========Oooo==========================================Oooo========
module uart (
input clk, //默认50M
input rst_n,
output tx_o,
input rx_o,
output error_flag //拉到led上显示一下,做个测试。
//usr logic
......
//
)
4)放一个仿真的结果波形吧,做个结束好了