📄 uart.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 + -