Menu Close

UART的发送器TX的FPGA实现及实验

在上几节内容中介绍了异步串行口的协议,波特率等内容。本节结合开发板PRA006/010介绍如何将UART –TX的各个部分组合在一起在FPGA实现,并通过Tera term, SSCOM等串口测试工具与计算机通信。

  1. 继续使用上节创建的工程,并建立新文件uart.v, 并设为顶层文件
  2. 利用IP Catalog向导生成输入50Mhz, 输出72MHz的PLL,并在uart.v文件里例化
  3. 将上节设计的波特率生成器在uart.v里例化,并将在UART协议一节中设计的tx.v在uart.v文件里例化。例化后的源文件如下:
module uart
#(
    parameter PARITY = "ODD"
)
(
    input        inclk,
    
    input        tx_req,
    input  [7:0] tx_data,
    output       tx_ack,
    
    output       tx,
    input        rx,      //rx 端在本设计中没有实现
    
    input        rx_ack,
    output       rx_rdy,
    output [7:0] rx_data,
    
    output       sys_clk,  //将系统时钟输出,便于测试程序使用
    output       rst
);
 
wire   tx_bd_en;
wire   rx_bd_en;
wire   locked;
assign   rst=!locked;
 
uart_pll   uart_pll_inst
(
    .areset  (1'b0),
    .inclk0  (inclk),             // inclk  ----50M,     
    .c0      (sys_clk),           // sys_clk----72M
    .locked  (locked)         
);
 
baud_rate_en
#(
    .BAUD_RATE (115200),        //波特率:115200
    .FREQUENCY (72000000)       //时钟参数:72M
)   
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_req    (tx_req),
    .tx_ack    (tx_ack),
    .tx        (tx)
);
 
assign rx_rdy = 0;
assign rx_data = 0;
 
endmodule

 

并将波特率发生器程序bd_rate_en.v与串口发送程序tx.v重新列出,如下:

  • bd_rate_en.v
module baud_rate_en
#(
    parameter BAUD_RATE = 115200,
    parameter FREQUENCY = 100000000
)
(
    input      clk,
    input      rst,
    output reg tx_bd_en,
    output reg rx_bd_en
);
 
localparam  TX_DIV_COE = FREQUENCY / (BAUD_RATE) - 1;
localparam  RX_DIV_COE = FREQUENCY / (BAUD_RATE*8) - 1;
 
reg [18:0]  tx_clk_div;
reg [18:0]  rx_clk_div;
 
always@(posedge clk or posedge rst)
if(rst) 
begin
    tx_clk_div <= 0;
    rx_clk_div <= 0;
    tx_bd_en <= 0;
    rx_bd_en <= 0;
end
else 
begin
    tx_bd_en <= 1'b0;
    if(tx_clk_div == TX_DIV_COE)
    begin
        tx_clk_div <= 0;
        tx_bd_en <= 1'b1;
    end
    else 
        tx_clk_div <= tx_clk_div + 1;
 
    rx_bd_en <= 0;
 
    if(rx_clk_div == RX_DIV_COE)
    begin
        rx_clk_div <= 0;
        rx_bd_en <= 1'b1;
    end
    else 
        rx_clk_div <= rx_clk_div + 1;
end
endmodule

 

 

  • tx.v
module tx
#(
    parameter PARITY   = "ODD",   //"ODD"--odd parity, "EVEN"--even parity, others--no parity
    parameter STOP_BIT = 1
)
(
    input       rst,
    input       clk,
    input       tx_bd_en,
    input [7:0] tx_data,
    input       tx_req,
    output reg  tx_ack,
    output reg  tx
);
 
localparam [3:0] 
    IDLE      = 0,
    START     = 1,
    FIRST_BIT = 2,
    SEC_BIT   = 3,
    THIRD_BIT = 4,
    FOUTH_BIT = 5,
    FIF_BIT   = 6,
    SIX_BIT   = 7,
    SEVN_BIT  = 8,
    EIGTH_BIT = 9,
    PAR_BIT   = 10,
    STOP1_BIT = 11,
    STOP2_BIT = 12;
                 
 
reg [7:0] tx_data_r;
 
wire odd = ^tx_data_r;
reg [3:0] tx_st;
 
always@(posedge clk or posedge rst)
if(rst) 
begin
    tx <= 1'b1;
    tx_st <= 0;
    tx_data_r <= 0;
    tx_ack <= 1'b0;
end
else 
begin
    if(tx_bd_en)  
    begin
        case(tx_st)
        IDLE: 
        begin
            tx_ack <= 1'b0;
            tx <= 1'b1;
 
            if(tx_req)
            begin
                tx_data_r <= tx_data;
                tx_ack <= 1'b1;
                tx_st <= START;
            end
        end
        START: 
        begin
            tx <= 1'b0;
            tx_ack <= 1'b0;
            tx_st <= FIRST_BIT;
        end
        FIRST_BIT: 
        begin
            tx <= tx_data_r[0];
            tx_st <= SEC_BIT;
        end
        SEC_BIT: 
        begin
            tx <= tx_data_r[1];
            tx_st <= THIRD_BIT;
        end
        THIRD_BIT: 
        begin
            tx <= tx_data_r[2];
            tx_st <= FOUTH_BIT;
        end
        FOUTH_BIT: 
        begin
            tx <= tx_data_r[3];
            tx_st <= FIF_BIT;
        end
        FIF_BIT : 
        begin
            tx <= tx_data_r[4];
            tx_st <= SIX_BIT;
        end
        SIX_BIT: 
        begin
            tx <= tx_data_r[5];
            tx_st <= SEVN_BIT;
        end
        SEVN_BIT: 
        begin
            tx <= tx_data_r[6];
            tx_st <= EIGTH_BIT;
        end
        EIGTH_BIT: 
        begin
            tx <= tx_data_r[7];
 
            if( (PARITY=="ODD") || (PARITY=="EVEN") )
                tx_st <= PAR_BIT;
            else
                tx_st <= STOP1_BIT;
        end
        PAR_BIT :
        begin
            tx_st <= STOP1_BIT;
             
            if(PARITY == "ODD") 
                tx <= odd;
            else
                tx <= ~odd;
        end
        STOP1_BIT:
        begin
            tx <= 1'b1;
 
            if( STOP_BIT == 1) 
            begin
                if(tx_req)
                begin
                    tx_data_r <= tx_data;
                    tx_ack <= 1'b1;
                    tx_st <= START;
                end
                else 
                    tx_st <= IDLE;
            end
            else
                tx_st <= STOP2_BIT;
        end
        STOP2_BIT :
        begin
            tx <= 1'b1;
 
            if(tx_req)
            begin
                tx_data_r <= tx_data;
                tx_ack <= 1'b1;
                tx_st <= START;
            end
            else 
                tx_st <= IDLE;
        end
        default: tx_st <= IDLE;
        endcase
    end
end
 
 
endmodule

 

  • 硬件设置

在FII-PRA006/010的开发板上采用了FT2232USB转串口芯片,如图1,

图1-1

图1-2

图1中J2是mini USB接口,可以通过USB传输电缆连接到PC或笔记本上,FT2232的右侧提供了两套TTL接口,分别接到FPGA的JTAG接口,和UART口(JTAG_TXD_O,JTAG_RXD_I)上。在本节内容只是讲解JTAG_TXD_O,JTAG_RXD_I如何使用。这两个管脚在FPGA上的映射如表1所示:

表1

UART名称 RXD TXD
原理图名称 JTAG_TXD_O JTAG_RXD_I
FPGA 管脚 144 143
说明 FPGA接收端 FPGA发送端

 

  • 测试程序

测试目的是提供数据,观察UART的TX是否按照协议进行发送数据。为了观测方便,这里提供的测试数据为秒脉冲计数器,将计数值作为UART的输入数据,并完善tx_req,tx_ack等握手协议,见图2。

图2

程序如下:

module test_uart
(
    input   inclk,
    output  tx
);
 
parameter PARITY = "none";
 
wire       rst;
wire       sys_clk;
 
reg        tx_req;
reg [7:0]  tx_data;
 
wire       tx_ack;
 
reg [27:0] div_sf; //Second division  from 72MHz
reg        s_p  ;//second pulse 
reg [1:0]  tx_st; //
 
always@(posedge sys_clk or posedge rst)
if(rst) 
begin
    div_sf <= 0;
    s_p <= 0;
end
else 
begin
    s_p <= 0;
 
    if(div_sf == 71999999) 
    begin
        s_p <= 1'b1;
        div_sf <= 0;
    end
    else
        div_sf <= div_sf + 1;
end
 
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;
 
        if(s_p)
            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
        if(s_p) 
        begin
            tx_data <= tx_data + 1;
            tx_st <= 1;
        end
    end
    endcase
end
 
 
uart
#(
    .PARITY (PARITY)
)
uart_inst
(
    .inclk    (inclk),
    
    .tx_req   (tx_req),
    .tx_data  (tx_data),
    .tx_ack   (tx_ack),
    
    .tx       (tx),
    .rx       (),
 
    .rx_ack   (),
    .rx_rdy   (),
    .rx_data  (),
    
    .sys_clk  (sys_clk),
    .rst      (rst)
);
 
endmodule

 

仿真工程:

`timescale 1 ns / 1 ps
 
module tb
(
);
 
parameter PERIOD = 20   ; //50Mhz
 
reg   inclk;
wire  tx;
 
initial 
begin
    inclk = 0;
    #(PERIOD/2);
 
    forever 
        #(PERIOD/2) inclk = ~inclk;
end
 
initial 
begin
//    #60000;
//    $stop;
end
 
test_uart   test_uart_inst
(
    .inclk  (inclk),
    .tx     (tx)
);

 
endmodule

 

  • 测试步骤
  • 单击菜单Projects–> Revisions… 在弹出的对话框中设置工程的更新版本,将工程的顶层实体设置为test_UART,如图3,

图3

  • 重新编译,管脚锁定,编译下载。
  • 打开SSCOM 串口调试软件(PC或笔记本上使用),工具设置如图4

图4

注意事项:

    • 由于FT2232在PC上映射的串口端口可能会变化,应注意选择正确的端口号,如图3显示2个端口(COM22,COM23),一般第一个已被JTAG使用,因此选择COM23。如果错误选择了COM22并打开,可能会影响JTAG下载,Signal Tap Logic Analyzer的调试等。
    • 图4是英文版的界面,中文版可以按照同样的方式设置。

 

练习:

(1) 编写testbench 程序,仿真tx的协议发送过程。观察波形。

(2)用Signal Tap Logic Analyzer调试UART 的tx过程,观察波形。

 

Quartus 参考代码:

Posted in FPGA, FPGA 教材教案, Quartus II, Quartus II, Verilog, Verilog, 教材与教案, 文章

2 Comments

发表回复

相关链接