⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.v

📁 一个串口的完整FPGA工程
💻 V
字号:
/*********************************************************************************************************
 **                                  All right reserve 2008-2009(C) 
 **                             Created &maintain by http://www.edaok.net
 **=======================================================================================================
 ** 模 块 名:   uart.v
 ** 描    述:   串口的VerilogHDL实现, 包括收, 发器等, 采用状态机方式编写
 ** 原 作 者:   Adeko (http://www.edaok.net)
 ** 参 与 者:   (...welcome you join in)
 **
 **=======================================================================================================
 ********************************************************************************************************/

`define ADDR_WIDTH      4
module uart (
    clk,
    rst_n,

    we, 
    rd_n,
    addr_base,
    addr,
    data_i,
    data_o,

    rxd_xi,
    txd_xo,

    int_o,

    uart_clk
);


input               clk;                                        //  全局时钟线
input               rst_n;                                      //  全局复位

input               we;                                         //  外部总线写有效, 高电平有效
input               rd_n;
input   [15:0]      addr_base;                                  //  寄存器的基地址
input   [15:0]      addr;                                       //  EBI上接收到的地址
input   [7:0]       data_i;                                     //  EBI上接收到的数据
output  [7:0]       data_o;                                     //  将要发送到EBI上的数据, 三态输出

input               rxd_xi;
output              txd_xo; 

output              int_o;

output              uart_clk;


parameter [7 : 0]   VERSION = 8'd100;
                                                                                                        
/*******************************************************************************************************
 ** GPIO寄存器相对地址(将和基地址结合寻址)
 ******************************************************************************************************/
parameter [`ADDR_WIDTH : 0]
    UDR             = {1'b0, `ADDR_WIDTH'h00},                  //  Uart Data Register (UDR)
    UCSRA           = {1'b0, `ADDR_WIDTH'h01},                  //  Uart Control & Status Register A (UCSRA)
    UCSRB           = {1'b0, `ADDR_WIDTH'h02},                  //  Uart Control & Status Register B (UCSRB)
    UCSRC           = {1'b0, `ADDR_WIDTH'h03},                  //  Uart Control & Status Register C (UCSRC)
    UBRRH           = {1'b0, `ADDR_WIDTH'h04},                  //  uart Baud Rate Register Higher (UBRRH)
    UBRRL           = {1'b0, `ADDR_WIDTH'h05},                  //  Uart Bard Rate Register Lower (UBRRL)
    UVER            = {1'b0, `ADDR_WIDTH'h06},                  //  当前的版本号
    UDEBUG          = {1'b0, `ADDR_WIDTH'h07};                  //  调试信息

parameter   
    RXC             = 7,                                        //  接收结束标记, 
    TXC             = 6,                                        //  发送结束标记
    UDRE            = 5,                                        //  发送缓冲空, Uart Data Register Empty
    FE              = 4,                                        //  帧错误标记, Frame Error
    DOR             = 3,                                        //  过速错误标记, Data OverRun
    UPE             = 2,                                        //  检验错误, Parity Error
    U2X             = 1,                                        //  UART 倍速设置
    MPCM            = 0;                                        //  Mutli-Process Communication Mode

parameter
    RXCIE           = 7,                                        //  Rx Completed Interrupt Enable
    TXCIE           = 6,                                        //  Tx Completed Interrupt Enable
    UDRIE           = 5,                                        //  UART Data Register Interrupt Enable
    RXEN            = 4,                                        //  RX Enable
    TXEN            = 3,                                        //  TX Enable
    UCSZ2           = 2,                                        //  UART Char Size[2]
    RXB8            = 1,                                        //  RX Bit[8]
    TXB8            = 0;                                        //  TX Bit[8]

parameter
    UMSEL           = 6,                                        //  UART Mode Select
    UPM1            = 5,                                        //  UART Parity Mode
    UPM0            = 4,
    USBS            = 3,                                        //  UART Stop Bits Select
    UCSZ1           = 2,
    UCSZ0           = 1,
    UCPOL           = 0;

/*******************************************************************************************************
 ** 内部寄存器列表 
 ******************************************************************************************************/
wire    [7:0]       wUDR;
reg     [7:0]       rUDR;
//----------------------------------
//                  UCSRA
//-----------------------------------
wire    [7:0]       wUCSRA;

//                  UCSRB
wire    [7:0]       wUCSRB;
reg                 rRXCIE,
                    rTXCIE,
                    rUDRIE,
                    rRXEN,
                    rTXEN,
                    rUCSZ2;

//                  UCSRC
wire    [7:0]       wUCSRC;
reg                 rUPM1,
                    rUPM0,
                    rUSBS,
                    rUCSZ1,
                    rUCSZ0;

wire    [7:0]       wUBRRH;
wire    [7:0]       wUBRRL;
reg     [11:0]      rUBRR;


reg     [3:0]       rCharSize;                                  //  数据帧字节长低, (5~8个字节)

reg     [7:0]       rDatRdTmp;                                  //  UART读缓冲, 三态输出

reg                 rUartDatRdEn;                               //  标记正在读UART接收寄存器

reg                 rTxDoneClr;                                 //  清除发送完成标记

reg                 rTxBufEmpty;                                //  发送缓冲空标记, '1'表示空

wire                wTxBufRead;                                 //  标记发送缓冲的数据已开始发送

wire                wBaudTick;                                  //  产生UART的时钟脉冲, 16X



assign  wUCSRA[UDRE]    = rTxBufEmpty;
assign  wUCSRA[U2X]     = 1'b0;
assign  wUCSRA[MPCM]    = 1'b0;

assign  wUCSRB[RXCIE]   = rRXCIE;
assign  wUCSRB[TXCIE]   = rTXCIE;
assign  wUCSRB[UDRIE]   = rUDRIE;
assign  wUCSRB[RXEN]    = rRXEN;
assign  wUCSRB[TXEN]    = rTXEN;
assign  wUCSRB[UCSZ2]   = rUCSZ2;
assign  wUCSRB[RXB8]    = 1'b0;
assign  wUCSRB[TXB8]    = 1'b0;

assign  wUCSRC[7]       = 1'b0;
assign  wUCSRC[UMSEL]   = 1'b0;
assign  wUCSRC[UPM1]    = rUPM1;
assign  wUCSRC[UPM0]    = rUPM0;
assign  wUCSRC[USBS]    = rUSBS;
assign  wUCSRC[UCSZ1]   = rUCSZ1;
assign  wUCSRC[UCSZ0]   = rUCSZ0;
assign  wUCSRC[UCPOL]   = 1'b0;

assign  wUBRRH[7:0]     = {4'h0, rUBRR[11:8]};

assign  wUBRRL[7:0]     = rUBRR[7:0];


wire    [7:0]       wRxDebugInfo;
        
wire                wUartEn = rRXEN | rTXEN;                    //  UART使能线, 启动波特率发生器


/*******************************************************************************************************
 ** 接收EBI外部总线上的数据 
 ******************************************************************************************************/
wire                wAddrMatch = (addr_base[15 : `ADDR_WIDTH] == addr[15 : `ADDR_WIDTH]);
wire    wWrValid_n = ~(we & wAddrMatch);

always @(posedge clk or negedge rst_n)
begin
    if (~rst_n) begin
        rUDR[7:0]   <= 8'h0;

        rRXCIE  <= 1'b0;
        rTXCIE  <= 1'b0;
        rUDRIE  <= 1'b0;
        rRXEN   <= 1'b0;
        rTXEN   <= 1'b0;
        rUCSZ2  <= 1'b0;

        rUPM1   <= 1'b0;
        rUPM0   <= 1'b0;
        rUSBS   <= 1'b0;
        rUCSZ1  <= 1'b0;
        rUCSZ0  <= 1'b0;

        rUBRR[11:0] <= 12'h00;

        rTxBufEmpty <= 1'b1;
    end
    else begin

        rTxDoneClr  <= 1'b0;

        if (wTxBufRead) begin
            rTxBufEmpty <= 1'b1;
        end

        if (~wWrValid_n) begin
            case (addr[3:0])

            UDR: begin
                rUDR[7:0]   <= data_i[7:0];
                rTxBufEmpty <= 1'b0;
            end

            UCSRA: begin
                rTxDoneClr  <= data_i[TXC];
            end

            UCSRB: begin
                rRXCIE  <= data_i[RXCIE];
                rTXCIE  <= data_i[TXCIE];
                rUDRIE  <= data_i[UDRIE];
                rRXEN   <= data_i[RXEN];
                rTXEN   <= data_i[TXEN];
                rUCSZ2  <= data_i[UCSZ2];
            end

            UCSRC: begin
                rUPM1   <= data_i[UPM1];
                rUPM0   <= data_i[UPM0];
                rUSBS   <= data_i[USBS];
                rUCSZ1  <= data_i[UCSZ1];
                rUCSZ0  <= data_i[UCSZ0];
            end
            
            UBRRH:      rUBRR[11:8] <= data_i[3:0];

            UBRRL:      rUBRR[7:0]  <= data_i[7:0];

            endcase
        end
    end
end


/*******************************************************************************************************
 ** 根据地址数据的寻址, 向数据总线发送被寻址寄存器的值, 空闲时输出高阻, 即为三态输出
 ******************************************************************************************************/
always @(
    wAddrMatch or
    rd_n or
    addr or
    wUDR or
    wUCSRA or
    wUCSRB or
    wUCSRC or
    wUBRRH or
    wUBRRL or
    wRxDebugInfo
    )
begin

    rUartDatRdEn    <= 1'b0;

    case ({~wAddrMatch, addr[`ADDR_WIDTH-1 : 0]})

    UDR: begin
        rDatRdTmp       <= wUDR;
        rUartDatRdEn    <= 1'b1 & (~rd_n);                      //  标记UDR寄存器的数据已被读出
    end
    
    UCSRA:          rDatRdTmp <= wUCSRA;
    
    UCSRB:          rDatRdTmp <= wUCSRB;

    UCSRC:          rDatRdTmp <= wUCSRC;

    UBRRH:          rDatRdTmp <= wUBRRH;

    UBRRL:          rDatRdTmp <= wUBRRL;

    UVER:           rDatRdTmp <= VERSION;

    UDEBUG:         rDatRdTmp <= wRxDebugInfo;

    default:        rDatRdTmp <= 8'hzz;

    endcase
end


/********************************************************************************************************
 ** 选择数据帧的字节长度, (5bits ~ 8bits)
 ********************************************************************************************************/
always @(
    rUCSZ2 or
    rUCSZ1 or
    rUCSZ0
    )
begin
    case ({rUCSZ2, rUCSZ1, rUCSZ0})

    3'b000:         rCharSize[3:0]  <= 4'h6;
    
    3'b001:         rCharSize[3:0]  <= 4'h7;

    3'b010:         rCharSize[3:0]  <= 4'h8;

    3'b011:         rCharSize[3:0]  <= 4'h9;

    default:        rCharSize[3:0]  <= 4'h6;

    endcase
end


/********************************************************************************************************
 ** 输出UART的中断信号, 低电平有效
 ********************************************************************************************************/
reg                 rFlgInt;
always @(posedge clk or negedge rst_n)
begin : UART_INTERRUPT_OUTPUT
    if (~rst_n) begin
        rFlgInt <= 1'b1;
    end
    else begin
        if (rRXCIE & wUCSRA[RXC]) begin
            rFlgInt <= 1'b0;
        end 
        else if (rTXCIE & wUCSRA[TXC]) begin
            rFlgInt <= 1'b0;
        end
        else if (rUDRIE & wUCSRA[UDRE]) begin
            rFlgInt <= 1'b0;
        end
        else begin
            rFlgInt <= 1'b1;
        end
    end
end


/********************************************************************************************************
 ** 波特率发生器模块
 ********************************************************************************************************/
divider U_divider (
    .clk            (clk),
    .rst_n          (rst_n),
    .enable         (wUartEn),
    .factor         (rUBRR[11:0]),
    .tick_out       (wBaudTick)
);


/********************************************************************************************************
 ** UART 接收模块实例化
 ********************************************************************************************************/
rxd U_receiver (
    .clk            (clk),
    .rst_n          (rst_n),

    .clk_en         (wBaudTick & rRXEN),
    .data_o         (wUDR),

    .rxd_xi         (rxd_xi),

    .ctrl_i         ({rUPM1, rUPM0, rUartDatRdEn}),
    .frame_bits_i   (rCharSize[3:0]),
    .stat_o         ({wUCSRA[FE], wUCSRA[DOR], wUCSRA[UPE], wUCSRA[RXC]}),
    
    .enable         (rRXEN),

    .debug_o        (wRxDebugInfo)
);


/********************************************************************************************************
 ** UART 发送模块实例化
 ********************************************************************************************************/
txd U_transmitter (
    .clk            (clk), 
    .rst_n          (rst_n), 
    
    .clk_en         (wBaudTick & rTXEN),
    .data_i         (rUDR),
    .enable         (rTXEN),

    .txd_xo         (txd_xo),

    .ctrl_i         ({rUPM1, rUPM0, rUSBS, rTxDoneClr, ~rTxBufEmpty}),
    .frame_bits_i   (rCharSize[3:0]),
    .stat_o         ({wUCSRA[TXC], wTxBufRead})
);

assign  data_o      = rDatRdTmp;

//assign  uart_clk    = wBaudTick;
assign  uart_clk    = wRxDebugInfo[0];

assign  int_o       = rFlgInt;

endmodule

/*********************************************************************************************************
 ** End Of File
 ********************************************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -