Verilog实现uart串口设计 - FPGA开发者技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

zwjiang 关注 私信

Verilog实现uart串口设计

在设计和验证 FPGA 设计时,硬件描述语言 (HDL) 的使用正成为越来越重要的因素。行为级描述的使用不仅提高了设计生产力,而且在设计验证中提供了独特的优势。当今最主要的 HDL 称为 Verilog 和 VHDL。本应用说明 Verilog 在数字 UART(通用异步接收器和发送器)的设计和验证中的使用。

UART 由两个独立的 HDL 模块组成。一个模块实现发送器,而另一个模块实现接收器。发射器和接收器模块可以在设计的顶层进行组合,以实现所需的发射器和接收器通道的任意组合。数据可写入发送器并从接收器读出,全部通过单个 8 位双向 CPU 接口完成。发送器和接收器通道的地址映射可以轻松构建到设计顶层的接口中。两个模块共享一个名为 mclkx16 的公共主时钟。在每个模块内,mclkx16 被划分为独立的波特率时钟。

以下为相关Verilog代码

rxcver.v文件

/*******************************************************************
 *
 *    DESCRIPTION: UART receiver module. 
 *
 *******************************************************************/
module rxcver (mclkx16, read, rx, reset, rxrdy, parityerr, framingerr, overrun, data);

input		mclkx16;								// Input clock, 16 x baudrate clock used for synchronisation.
input		read;									// Read strobe.
input		rx;										// Receive input line.  
input		reset;									// Global Reset.


// receive status & error signals
output		rxrdy;									// Received data ready to be read.
output		parityerr;		reg	parityerr;			// Receiver parity error detected.
output		framingerr;		reg	framingerr;			// Receiver framing error detected.
output		overrun;		reg	overrun;			// Receiver overrun error detected. 

// 8 bit latched output data bus.
output		[7:0] data;		reg 	[7:0]data;		// 8 bit output data bus

// Internal control signals.
reg			[3:0] rxcnt;							// Count of clock cycles
reg			rx1, read1, read2, idle1, hunt;			// Delayed versions of rx, read, idle, and last hunting for start bit flag.

// Receive shift register bits
reg			[7:0] rhr;								// Receive hold register
reg			[7:0] rsr;								// Receive seriel -> parallel shift register
reg    		rxparity;								// Parity bit of received data
reg   		paritygen;								// Generated parity of received data
reg      	rxstop;									// Stop bit of received data
// wire paritymode = 1'b1; 							// Initializing to 1 = odd parity, 0 = even parity. 

// Receive clock and control signals.
reg			rxclk;									// Receive data shift clock
reg			idle;									// 1'b1 when receiver is idling
reg			rxdatardy;								// 1'b1 when data is ready to be read


// Idle requires async preset since it is clocked by rxclk, and it's  
// value determines whether rxclk gets generated or not. 
// Idle goes low when shifting in data. This is ensured because all bits 
// of rsr are preset to all 1's when idle is high. Idle goes high again 
// when rsr[0] = 0, i.e. when the low "rxstop" bit reach rsr[0]. 
// Next rising edge of rxclk preset idle to high again, and generation of 
// rxclk is disabled.

always @(posedge rxclk or posedge reset)
begin
	if (reset)
		idle <= 1'b1;
	else 
		idle <= !idle && !rsr[0];
end

// Synchronizing rxclk to the centerpoint of low leading startbit.
always @(posedge mclkx16)
begin
	// A start bit is eight clock times with rx=0 after a falling edge of rx. 
	if (reset)
		hunt <= 1'b0;
	else if (idle && !rx && rx1 )	
		hunt <= 1'b1;								// Start hunting when idle and falling edge of rx is found.
	else if (!idle || rx )
		hunt <= 1'b0;								// Stop hunting when shifting in data, or a 1 is found on rx.
	
	if (!idle || hunt)					
		rxcnt <= rxcnt + 1;							// Count clocks when not idle, or hunting for start bit.
	else
		rxcnt <= 4'b0001;							// hold at 1, when idle and waiting for falling edge of rx.
	
	rx1 <= rx;										// delay rx one cycle of mclkx16, used for edge detection.
	
	rxclk <= rxcnt[3]; 								// rxclk = mclkx16 divided by 16. First rising edge of rxclk occures
													// always at the centerpoint of the low leading startbit.
end

// This task reset internal bit of receiver, when no data are received.
task idle_reset;
	begin
		rsr				<= 8'b11111111;				// All 1's ensure that idle stays low during data shifting.
		rxparity		<= 1'b1;					// Preset to high to ensure idle = 0 during data shifting.          
//		paritygen		<= paritymode;				// Preset paritygen to parity mode.
		paritygen		<= 1'b1;					// Preset to 1 => odd parity mode, 0 => even parity mode.
		rxstop			<= 1'b0;					// Forces idle = 1, when rsr[0] gets rxstop bit. 
	end									   
endtask

// This task executes sampling & shifting of data, and generates parity result.
task shift_data;
	begin                               														
		rsr				<= rsr >> 1;				// Right shift receive shift register.     
		rsr[7]			<= rxparity;				// Load rsr[7] with rxparity.
		rxparity		<= rxstop;					// Load rxparity with rxstop.
		rxstop			<= rx;						// Load rxstop with rx. At 1'st shift rxstop gets low "start bit". 
		paritygen		<= paritygen ^ rxstop;		// Generate parity as data are shifted.
	end
endtask

// When not idling, sample data at the rx input, and generate parity.
always @(posedge rxclk or posedge reset)
if (reset)
	idle_reset;										// Reset internal bits.
else
	begin												      
		if (idle)
			idle_reset;								// Reset internal bits.
		else
			shift_data;								// Shift data and generate parity.
		end

// Generate status & error flags.
always @(posedge mclkx16 or posedge reset)
if (reset) 
	begin
		rhr				<= 8'h00;
		rxdatardy		<= 1'b0;
		overrun			<= 1'b0;
		parityerr		<= 1'b0;
		framingerr		<= 1'b0;
		idle1			<= 1'b1; 
		read2			<= 1'b1; 
		read1			<= 1'b1; 
	end
else	
	begin
		if (idle && !idle1)							// Look for rising edge of idle and update output registers.
			begin
				if (rxdatardy)
					overrun <= 1'b1;				// Overrun error, if previous data still in holding register.
				else
					begin
						overrun <= 1'b0;			// No overrun error, since holding register is empty.
						rhr <= rsr;					// Update holding register with contens of shift register.
						parityerr <= paritygen;		// paritygen = 1, if parity error.
						framingerr <=  !rxstop;		// Framingerror, if stop bit is not 1.
						rxdatardy <= 1'b1;			// Data is ready for reading flag.
					end
			end
 	   
		if (!read2 &&  read1)
			begin									// Clear error and data registers when data is read.
				rxdatardy  <= 1'b0;
				parityerr  <= 1'b0;
				framingerr <= 1'b0;
				overrun    <= 1'b0;
			end 

		idle1 <= idle;								// idle delayed 1 cycle for edge detect.
		read2 <= read1;								// 2 cycle delayed version of read, used for edge detection.
		read1 <= read;								// 1 cycle delayed version of read, used for edge detection.
	end

assign		rxrdy = rxdatardy;						// Receive data ready output signal

always @(read or rhr)								//Latch data output when read goes low.
if (~read) 
	data = rhr; 

endmodule

txmit.v文件

/*******************************************************************
 *
 *    DESCRIPTION: UART transmitter module.
 *
 *******************************************************************/
module txmit (mclkx16, write, reset, tx, txrdy, data);

input		mclkx16;						// Input clock, 16 x baudrate clock used for synchronization.
input		write;							// Transmit write strobe.
input		reset;							// Global reset.
output		tx;		reg   tx;				// Transmit data output.
		         
output		txrdy;							// Transmitter ready to recieve next byte to be send

input		[7:0] data;						// 8 bit input data bus

reg			write1, write2;					// write signal delayed 1 and 2 cycles.
reg			txdone1;						// txdone signal delayed one cycle.

// Transmit shift register bits
reg			[7:0] thr;							// Transmit hold register
reg			[7:0] tsr;							// Transmit shift register, used for shifting out data to tx.
reg			tag1, tag2;							// Tag bits for used for detecting, when the tsr are empty.
wire		paritymode = 1'b1;					// Initializing to 1 = odd parity, 0 = even parity. 
reg			txparity;							// Parity generation register.


// Transmit clock and other control signals
reg			txclk;							// Transmit clock, i.e. baudrate clock = 1/16'th of mclkx16.
wire		txdone;							// Set to high, when shifting of byte is done.
wire		paritycycle;					// Set to high, one cycle next to last shift cycle.
reg			txdatardy;						// Set to hign, when data is ready in transmit hold register.
reg			[2:0] cnt;						// Counter used for generating the internal baud rate clock.

// Paritycycle = 1 on next to last cycle, this means when tsr[1] gets tag2.
assign		paritycycle = tsr[1] && !(tag2 || tag1 || tsr[7] || tsr[6] || tsr[5] || tsr[4] || tsr[3] || tsr[2]);

// txdone = 1 when done shifting, this means when tx gets tag2.
assign		txdone = !(tag2 || tag1 || tsr[7] || tsr[6] || tsr[5] || tsr[4] || tsr[3] || tsr[2] || tsr[1] || tsr[0]);

// Ready for new date to be written, when no data is in transmit hold register.
assign		txrdy = !txdatardy;

// Latch data[7:0] into the transmit hold register at posedge of write.
always @(write or data)
	if (~write) 
		thr = data; 

// Toggle txclk every 8 counts, which divides the clock by 16, to generate the baud clock
always @(posedge mclkx16 or posedge reset)
	if (reset)
		begin
			txclk <= 1'b0;
			cnt <= 3'b000;
		end
	else
		begin
			if (cnt == 3'b000)  
				txclk <= !txclk; 
			cnt <= cnt + 1;
		end

task idle_reset;
	begin									// Apply pseudo Idle state, equal to end of transmission.
		tsr			<= 8'h00;				// Reset transmit shift register.
		tag2		<= 1'b0;				// Reset tag bit. 
		tag1		<= 1'b0;				// Reset tag bit.
//		txparity	<= paritymode;			// Set parity mode for even or odd parity.
		txparity	<= 1'b0;				// Reset txparty bit.
		tx			<= 1'b1;				// At pseudo idle set Start bit high.
	end
endtask

task load_data;
	begin									// Initialize registers and load next byte of data.
		tsr			<= thr;					// Load tsr from thr.
		tag2		<= 1'b1;				// Set tag bits for detecting when shifting is done. 
		tag1		<= 1'b1;				// Set tag bits for detecting when shifting is done.
		txparity	<= paritymode;			// Set parity mode bit, 0 = even parity, 1 = odd parity
		tx			<= 1'b0;				// Set start bit low.
	end
endtask

task shift_data;
	begin
		tsr			<= tsr >> 1;			// Right shift tsr by one.
		tsr[7]		<= tag1;				// Set tsr[7] = tag1.   
		tag1		<= tag2;				// Set tag1 = tag2.
		tag2		<= 1'b0;				// Set tag2 = 0. 
		txparity	<= txparity ^ tsr[0];	// Generate parity.
	end
endtask

// Shifting out data to tx.
always @(posedge txclk or posedge reset)
if (reset)
	idle_reset;								// Reset internal bits of transmitter.
else
	begin
		if (txdone && txdatardy)
			load_data;						// Load new data to tsr.
		else
			begin   
				shift_data;					// Shift contents of tsr to tx output.	
											// Shift out data or parity bit or stop/idle bit.
				if (txdone )
					tx <= 1'b1;				// Output stop/idle bit.
				else if (paritycycle)
					tx <= txparity;			// Output parity bit.
				else
					tx <= tsr[0];			//Shift out data bit.
			end
	end

always @(posedge mclkx16 or posedge reset)
if (reset) 
	begin
		txdatardy <= 1'b0;
		write2 <= 1'b1;
		write1 <= 1'b1;		
		txdone1 <= 1'b1;		            // Set equal to txdone at reset.
	end
else
	begin
		if (write1 &&  !write2)
			txdatardy  <= 1'b1;				// At risign edge of write, new data are latched in thr, and txdatardy are set.
		else if (!txdone &&  txdone1)
			txdatardy  <= 1'b0;				// At falling edge of txdone, the thr has been loaded into tsr, so txdatardy are reset.
											// Generate delayed versions of write and txdone signals for edge detection.
		write2 <= write1;
		write1 <= write;
		txdone1 <= txdone;
	end 

endmodule

uart.v文件

/*******************************************************************
 *
 *    DESCRIPTION: UART top level module implements full duplex UART function.
 *
 *******************************************************************/
//Includes Verilog HDL sources for Transmitter & receiver modules
`include "txmit.v"
`include "rxcver.v"

module uart (mclkx16, reset, read, write, data, rx, tx, rxrdy, txrdy, parityerr, framingerr, overrun);
                
input       mclkx16;								// Input clock, 16 x baud rate clock used for synchronisation.
input       read;									// read strobe input.
input       write;									// write strobe input.
input		reset;									// Master reset input.

inout 		[7:0] data;								// Bidirectional data bus for writing to transmitter & reading from receiver.

// Receiver input signal, error and status flags.
input		rx;										// Receive  data line input
output		rxrdy;			wire	rxrdy;			// Data ready to be read.
output		parityerr;		wire	parityerr;		// Parity error flag.
output		framingerr;		wire	framingerr;		// Framing error flag.
output		overrun;		wire	overrun;		// Overrun error flag. 
wire        [7:0] rxdata;							// Intermediate output signals from receiver. 

// Transmitter output signal and status flag.
output		tx;				wire	tx;				// Transmit data line output
output		txrdy;			wire	txrdy;			// Transmitter ready for next byte.

//Instantiation of the transmitter module. 
txmit tx_1 (mclkx16, write, reset, tx, txrdy, data);

// Instantiation of the receiver module.
rxcver  rx_1 (mclkx16, read, rx, reset, rxrdy, parityerr, framingerr, overrun, rxdata);

//Drives the databus during data read, otherwise tri-state the data bus.
assign		data = !read ? rxdata : 8'bzzzzzzzz;

endmodule

更多回帖

×
发帖