Smallest GPL UART

Started by Giuseppe Marullo April 29, 2012
Hi all,
I am searching for the smallest/simpler UART in verilog. I need to 
release the project under GPL and still confused about what are my options.

I would go with micro UART by Jeung Joon Lee but I am unable to 
determine its license.

There are others, like osvudu by Timothy Goddard seems released under 
(a) MIT license, thus compatible with GPL.

I need very simple stuff:

baud rate 9600-115200 with a clock of about 100MHz but should be able to 
run with other clocks, like 12MHz. No buffers and other fancy stuff.

8N1, and possibility (I need some) to have rtx, tx and rx only 
capability (I would like to instantiate just the parts I need).

Don't know if I need fullduplex, possibly yes.

What would you advice to use?

Thanks in advance.

Giuseppe Marullo
"Giuseppe Marullo" <giuseppe.marullonospam@iname.com> wrote in message 
news:jnjvra$1fa$1@speranza.aioe.org...
> Hi all, > I am searching for the smallest/simpler UART in verilog. I need to release > the project under GPL and still confused about what are my options. > > I would go with micro UART by Jeung Joon Lee but I am unable to determine > its license. > > There are others, like osvudu by Timothy Goddard seems released under (a) > MIT license, thus compatible with GPL. > > I need very simple stuff: > > baud rate 9600-115200 with a clock of about 100MHz but should be able to > run with other clocks, like 12MHz. No buffers and other fancy stuff. > > 8N1, and possibility (I need some) to have rtx, tx and rx only capability > (I would like to instantiate just the parts I need). > > Don't know if I need fullduplex, possibly yes. > > What would you advice to use? > > Thanks in advance. > > Giuseppe Marullo
Why not roll your own? For the simple case you have specified it will take less than half a day and the ip is all yours. I'm am constantly amazed by people scratching around for cheap or free ip when it would actually be quicker and more efficient to DIY! Andy
> Why not roll your own? For the simple case you have specified it will take
Thank you Andy, but I need to concentrate on other things, I would pass on serial stuff if I can this time. Giuseppe Marullo
On Sun, 29 Apr 2012 19:18:24 +0100, Andy Bartlett wrote:

> "Giuseppe Marullo" <giuseppe.marullonospam@iname.com> wrote in message > news:jnjvra$1fa$1@speranza.aioe.org... >> Hi all, >> I am searching for the smallest/simpler UART in verilog. I need to >> release the project under GPL and still confused about what are my >> options. >> >> I would go with micro UART by Jeung Joon Lee but I am unable to >> determine its license. >> >> There are others, like osvudu by Timothy Goddard seems released under >> (a) MIT license, thus compatible with GPL. >> >> I need very simple stuff: >> >> baud rate 9600-115200 with a clock of about 100MHz but should be able >> to run with other clocks, like 12MHz. No buffers and other fancy stuff. >> >> 8N1, and possibility (I need some) to have rtx, tx and rx only >> capability (I would like to instantiate just the parts I need). >> >> Don't know if I need fullduplex, possibly yes. >> >> What would you advice to use? >> >> Thanks in advance. >> >> Giuseppe Marullo > > > > Why not roll your own? For the simple case you have specified it will > take less than half a day and the ip is all yours. > > I'm am constantly amazed by people scratching around for cheap or free > ip when it would actually be quicker and more efficient to DIY! > > Andy
I second that. I only an FPGA hacker, and yet an NSUART (not-so universal asynchronous receiver transmitter) is a fairly easy proposition. In fact: here: One serial interface. Easy, simple, and as an added bonus, free of any confusing comments. I'm pretty sure this was for a 25MHz clock and a baud rate of 9600 -- but, since it lacks those comments that might mislead, you'll have to figure that out yourself: `define IDLE_BIT 0 `define START_BIT 1 `define DATA_BIT 2 `define STOP_BIT 3 module asyncTx(clock, reset, data, write, txd, rts, empty); parameter baudDiv = 11'd1280; input clock; input reset; input [7:0] data; input write; output reg txd; output reg rts; output reg empty; reg [7:0] shift; reg [2:0] count; reg [1:0] state; reg [10:0] baud; always @ (state) empty = state == `IDLE_BIT; always @ (posedge reset or posedge clock) begin if (reset) begin rts <= 0; txd <= 1; empty <= 1; state <= `IDLE_BIT; baud <= baudDiv - 1; end else begin if (state != `IDLE_BIT) baud <= baud ? baud - 1 : baudDiv - 1; case (state) `IDLE_BIT: if (write) begin state <= `START_BIT; shift <= data; count <= 7; end `START_BIT: if (!baud) begin txd <= 0; state <= `DATA_BIT; end `DATA_BIT: if (!baud) begin txd <= shift[0]; shift <= {1'bx, shift[7:1]}; count <= count - 1; if (!count) begin state <= `STOP_BIT; end end `STOP_BIT: if (!baud) begin txd <= 1; state <= `IDLE_BIT; end endcase end end endmodule module asyncRx(clock, reset, rxd, read, data, frameError, overflow, ready); parameter baudDiv = 7'd80; input clock; input reset; input rxd; input read; output reg [7:0] data; output reg frameError; output reg overflow; output wire ready; reg intReady; reg [2:0] rxdBuff; // shift register to prevent metastability reg [2:0] count; // bit count (0-7) reg [1:0] state; // receiver state reg [6:0] baud; // baud rate * 16 register reg [3:0] subBaud; // baud rate reg wire rxdBit; assign rxdBit = rxdBuff[2]; assign ready = intReady; always @ (posedge reset or posedge clock) if (reset) begin state <= `IDLE_BIT; rxdBuff <= 0; data <= 0; count <= 7; baud <= baudDiv - 1; subBaud <= 15; overflow <= 0; intReady <= 0; frameError <= 0; end else begin rxdBuff <= {rxdBuff[1:0], rxd}; // shift for metastability prevention if (baud) baud <= baud - 1; else begin baud <= baudDiv - 1; if (state != `IDLE_BIT) subBaud <= subBaud - 1; end if (read && intReady) begin intReady <= 0; frameError <= 0; overflow <= 0; end case (state) `IDLE_BIT: if (!rxdBit) begin state <= `START_BIT; subBaud <= 15; end `START_BIT: begin if (!baud && subBaud == 8) begin if (rxdBit) begin overflow <= intReady; if (!intReady) intReady <= 1; frameError <= 1; state <= `IDLE_BIT; end end if (!baud && subBaud == 0) begin state <= `DATA_BIT; count <= 7; end end `DATA_BIT: begin if (!baud && subBaud == 8) begin data <= {!rxdBit, data[7:1]}; end if (!baud && subBaud == 0) begin if (count == 0) begin state <= `STOP_BIT; end count <= count - 1; end end `STOP_BIT: begin if (!baud && subBaud == 8) begin if (!rxdBit) begin frameError <= 1; state <= `IDLE_BIT; end overflow <= intReady; if (!intReady) intReady <= 1; end if (!baud && subBaud == 0) begin state <= `IDLE_BIT; end end endcase end endmodule -- My liberal friends think I'm a conservative kook. My conservative friends think I'm a liberal kook. Why am I not happy that they have found common ground? Tim Wescott, Communications, Control, Circuits & Software http://www.wescottdesign.com
Giuseppe Marullo <giuseppe.marullonospam@iname.com> wrote:

>Hi all, >I am searching for the smallest/simpler UART in verilog. I need to >release the project under GPL and still confused about what are my options. > >I would go with micro UART by Jeung Joon Lee but I am unable to >determine its license. > >There are others, like osvudu by Timothy Goddard seems released under >(a) MIT license, thus compatible with GPL. > >I need very simple stuff: > >baud rate 9600-115200 with a clock of about 100MHz but should be able to >run with other clocks, like 12MHz. No buffers and other fancy stuff. > >8N1, and possibility (I need some) to have rtx, tx and rx only >capability (I would like to instantiate just the parts I need). > >Don't know if I need fullduplex, possibly yes. > >What would you advice to use?
There is a very simple UART packed togethet with Xilinx's KCPSM. I agree with the others. Open Source UARTs are not always the best solution. I once used the 16550 UART from opencores but it is pretty crappy. Very slow due to an overly complex design. -- Failure does not prove something is impossible, failure simply indicates you are not using the right tools... nico@nctdevpuntnl (punt=.) --------------------------------------------------------------
Giuseppe Marullo wrote:

> I am searching for the smallest/simpler UART in verilog. I need to > release the project under GPL and still confused about what are my options.
This was one of my first projects for learning VHDL: http://www.frank-buss.de/vhdl/spartan3e.html Most programs can use VHDL and Verilog, so I guess you could integrate it in your Verilog project. I released it under the BSD License, so do whatever you want with it, but mention me as an author. You should add a (clocked) input latch to the rx signal for the receiver, to avoid metastability problems. Something I learned the hard way years ago, by searching mysterious and rare occuring events, which resulted in invalid state machine states. -- Frank Buss, http://www.frank-buss.de electronics and more: http://www.youtube.com/user/frankbuss
On Mon, 30 Apr 2012 00:22:50 +0000, Nico Coesel wrote:

> Giuseppe Marullo <giuseppe.marullonospam@iname.com> wrote: > >>Hi all, >>I am searching for the smallest/simpler UART in verilog. I need to >>release the project under GPL and still confused about what are my >>options. >> >>I would go with micro UART by Jeung Joon Lee but I am unable to >>determine its license. >> >>There are others, like osvudu by Timothy Goddard seems released under >>(a) MIT license, thus compatible with GPL. >> >>I need very simple stuff: >> >>baud rate 9600-115200 with a clock of about 100MHz but should be able to >>run with other clocks, like 12MHz. No buffers and other fancy stuff. >> >>8N1, and possibility (I need some) to have rtx, tx and rx only >>capability (I would like to instantiate just the parts I need). >> >>Don't know if I need fullduplex, possibly yes. >> >>What would you advice to use? > > There is a very simple UART packed togethet with Xilinx's KCPSM. I agree > with the others. Open Source UARTs are not always the best solution. I > once used the 16550 UART from opencores but it is pretty crappy. Very > slow due to an overly complex design.
A design that did a good job of emulating the 16550 would have to be a lot more complex than just a good asynchronous receiver-transmitter. pair. Particularly if you can hard-code the division ratio, bit count, etc., they are easy-peasy thing to write. Certainly "overly complex" if you just need a serial interface -- but maybe not so if you must have compatibility with existing software. (Note: I don't know at what point in the process one loses the "universal" moniker -- but hard-coding all the bits that are normally software programmable would seem to be it). -- My liberal friends think I'm a conservative kook. My conservative friends think I'm a liberal kook. Why am I not happy that they have found common ground? Tim Wescott, Communications, Control, Circuits & Software http://www.wescottdesign.com
On 29/04/12 19:04, Giuseppe Marullo wrote:
> Hi all, > I am searching for the smallest/simpler UART in verilog. I need to > release the project under GPL and still confused about what are my > options.
I have just completed a very simple UART model to communicate with a FPGA dev board. The package has been tested with an integrated test harness which runs Tx & Rx back to back. Also tested in real hardware with a CP2102 USB to serial adapter. Requirements: Python with MyHDL package, see http://myhdl.org Exports: VHDL or Verilog Jan Coombs -- (email valid at present)
Tim Wescott <tim@seemywebsite.com> wrote:

>On Mon, 30 Apr 2012 00:22:50 +0000, Nico Coesel wrote: > >> Giuseppe Marullo <giuseppe.marullonospam@iname.com> wrote: >> >>>Hi all, >>>I am searching for the smallest/simpler UART in verilog. I need to >>>release the project under GPL and still confused about what are my >>>options. >>> >>>I would go with micro UART by Jeung Joon Lee but I am unable to >>>determine its license. >>> >>>There are others, like osvudu by Timothy Goddard seems released under >>>(a) MIT license, thus compatible with GPL. >>> >>>I need very simple stuff: >>> >>>baud rate 9600-115200 with a clock of about 100MHz but should be able to >>>run with other clocks, like 12MHz. No buffers and other fancy stuff. >>> >>>8N1, and possibility (I need some) to have rtx, tx and rx only >>>capability (I would like to instantiate just the parts I need). >>> >>>Don't know if I need fullduplex, possibly yes. >>> >>>What would you advice to use? >> >> There is a very simple UART packed togethet with Xilinx's KCPSM. I agree >> with the others. Open Source UARTs are not always the best solution. I >> once used the 16550 UART from opencores but it is pretty crappy. Very >> slow due to an overly complex design. > >A design that did a good job of emulating the 16550 would have to be a >lot more complex than just a good asynchronous receiver-transmitter. >pair. Particularly if you can hard-code the division ratio, bit count, >etc., they are easy-peasy thing to write. > >Certainly "overly complex" if you just need a serial interface -- but >maybe not so if you must have compatibility with existing software.
I designed a 16550 clone before and trust me: it was waaaaaaaaaay more simple and faster than the one from Opencores. The one I designed is running in over 10.000 products 24/7. The thing is that you can't take designs from one employer to the other. Where the Opencores design failes is using two clocks and asynchronous FIFOs. Besides that the I/O for the registers is also asynchronous while it doesn't need to be. -- Failure does not prove something is impossible, failure simply indicates you are not using the right tools... nico@nctdevpuntnl (punt=.) --------------------------------------------------------------
Jan, Frank, Tim, Nico and Andy,
many thanks for your answer. I would like to stick with Verilog, at the 
moment I am trying with the following code:

// Documented Verilog UART
// Copyright (C) 2010 Timothy Goddard (tim@goddard.net.nz)
// Distributed under the MIT licence.
//
// Permission is hereby granted, free of charge, to any person obtaining 
a copy
// of this software and associated documentation files (the "Software"), 
to deal
// in the Software without restriction, including without limitation the 
rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be 
included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 
SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
module uart(
     input clk, // The master clock for this module
     input rst, // Synchronous reset.
     input rx, // Incoming serial line
     output tx, // Outgoing serial line
     input transmit, // Signal to transmit
     input [7:0] tx_byte, // Byte to transmit
     output received, // Indicated that a byte has been received.
     output [7:0] rx_byte, // Byte received
     output is_receiving, // Low when receive line is idle.
     output is_transmitting, // Low when transmit line is idle.
     output recv_error // Indicates error in receiving packet.
     );

//parameter CLOCK_DIVIDE = 1302; // clock rate (50Mhz)  / (baud rate 
(9600)   * 4)
parameter   CLOCK_DIVIDE = 2604; // clock rate (100Mhz) / (baud rate 
(9600)   * 4) by G. Marullo
// parameter   CLOCK_DIVIDE = 217;  // clock rate (100Mhz) / (baud rate 
(115200) * 4) by G. Marullo

// States for the receiving state machine.
// These are just constants, not parameters to override.
parameter RX_IDLE = 0;
parameter RX_CHECK_START = 1;
parameter RX_READ_BITS = 2;
parameter RX_CHECK_STOP = 3;
parameter RX_DELAY_RESTART = 4;
parameter RX_ERROR = 5;
parameter RX_RECEIVED = 6;

// States for the transmitting state machine.
// Constants - do not override.
parameter TX_IDLE = 0;
parameter TX_SENDING = 1;
parameter TX_DELAY_RESTART = 2;

reg [11:0] rx_clk_divider = CLOCK_DIVIDE;
reg [11:0] tx_clk_divider = CLOCK_DIVIDE;

reg [2:0] recv_state = RX_IDLE;
reg [5:0] rx_countdown;
reg [3:0] rx_bits_remaining;
reg [7:0] rx_data;

reg tx_out = 1'b1;
reg [1:0] tx_state = TX_IDLE;
reg [5:0] tx_countdown;
reg [3:0] tx_bits_remaining;
reg [7:0] tx_data;

assign received = recv_state == RX_RECEIVED;
assign recv_error = recv_state == RX_ERROR;
assign is_receiving = recv_state != RX_IDLE;
assign rx_byte = rx_data;

assign tx = tx_out;
assign is_transmitting = tx_state != TX_IDLE;

always @(posedge clk) begin
	if (rst) begin
		recv_state = RX_IDLE;
		tx_state = TX_IDLE;
	end
	
	// The clk_divider counter counts down from
	// the CLOCK_DIVIDE constant. Whenever it
	// reaches 0, 1/16 of the bit period has elapsed.
    // Countdown timers for the receiving and transmitting
	// state machines are decremented.
	rx_clk_divider = rx_clk_divider - 1'b1;
	if (!rx_clk_divider) begin
		rx_clk_divider = CLOCK_DIVIDE;
		rx_countdown = rx_countdown - 1'b1;
	end
	tx_clk_divider = tx_clk_divider - 1'b1;
	if (!tx_clk_divider) begin
		tx_clk_divider = CLOCK_DIVIDE;
		tx_countdown = tx_countdown - 1'b1;
	end
	
	// Receive state machine
	case (recv_state)
		RX_IDLE: begin
			// A low pulse on the receive line indicates the
			// start of data.
			if (!rx) begin
				// Wait half the period - should resume in the
				// middle of this first pulse.
				rx_clk_divider = CLOCK_DIVIDE;
				rx_countdown = 2;
				recv_state = RX_CHECK_START;
			end
		end
		RX_CHECK_START: begin
			if (!rx_countdown) begin
				// Check the pulse is still there
				if (!rx) begin
					// Pulse still there - good
					// Wait the bit period to resume half-way
					// through the first bit.
					rx_countdown = 4;
					rx_bits_remaining = 8;
					recv_state = RX_READ_BITS;
				end else begin
					// Pulse lasted less than half the period -
					// not a valid transmission.
					recv_state = RX_ERROR;
				end
			end
		end
		RX_READ_BITS: begin
			if (!rx_countdown) begin
				// Should be half-way through a bit pulse here.
				// Read this bit in, wait for the next if we
				// have more to get.
				rx_data = {rx, rx_data[7:1]};
				rx_countdown = 4;
				rx_bits_remaining = rx_bits_remaining - 1'b1;
				recv_state = rx_bits_remaining ? RX_READ_BITS[2:0] : RX_CHECK_STOP[2:0];
			end
		end
		RX_CHECK_STOP: begin
			if (!rx_countdown) begin
				// Should resume half-way through the stop bit
				// This should be high - if not, reject the
				// transmission and signal an error.
				recv_state = rx ? RX_RECEIVED[2:0] : RX_ERROR[2:0];
			end
		end
		RX_DELAY_RESTART: begin
			// Waits a set number of cycles before accepting
			// another transmission.
			recv_state = rx_countdown ? RX_DELAY_RESTART[2:0] : RX_IDLE[2:0];
		end
		RX_ERROR: begin
			// There was an error receiving.
			// Raises the recv_error flag for one clock
			// cycle while in this state and then waits
			// 2 bit periods before accepting another
			// transmission.
			rx_countdown = 8;
			recv_state = RX_DELAY_RESTART;
		end
		RX_RECEIVED: begin
			// Successfully received a byte.
			// Raises the received flag for one clock
			// cycle while in this state.
			recv_state = RX_IDLE;
		end
	endcase
	
	// Transmit state machine
	case (tx_state)
		TX_IDLE: begin
			if (transmit) begin
				// If the transmit flag is raised in the idle
				// state, start transmitting the current content
				// of the tx_byte input.
				tx_data = tx_byte;
				// Send the initial, low pulse of 1 bit period
				// to signal the start, followed by the data
				tx_clk_divider = CLOCK_DIVIDE;
				tx_countdown = 4;
				tx_out = 0;
				tx_bits_remaining = 8;
				tx_state = TX_SENDING;
			end
		end
		TX_SENDING: begin
			if (!tx_countdown) begin
				if (tx_bits_remaining) begin
					tx_bits_remaining = tx_bits_remaining - 1'b1;
					tx_out = tx_data[0];
					tx_data = {1'b0, tx_data[7:1]};
					tx_countdown = 4;
					tx_state = TX_SENDING;
				end else begin
					// Set delay to send out 2 stop bits.
					tx_out = 1;
					tx_countdown = 8;
					tx_state = TX_DELAY_RESTART;
				end
			end
		end
		TX_DELAY_RESTART: begin
			// Wait until tx_countdown reaches the end before
			// we send another transmission. This covers the
			// "stop bit" delay.
			tx_state = tx_countdown ? TX_DELAY_RESTART[1:0] : TX_IDLE[1:0];
		end
	endcase
end

endmodule

I had to massage it a bit (a counter was some bits shorter than I 
expected, arrgh), and with some warnings but seems to fit my needs. I 
need up to 4 uarts in a small design, they need to connect the FPGA with 
the pc(diagnostic), USB Host (2) from HobbyTronics for a USB stick and a 
USB keyboard and a serial LCD display (Nice Stuff!).

All can run either 9600 or 115200, and some needs just tx or rx, so I 
could run rtx, rx-only or tx-only versions.

Proably it could be fun to compare the several suggestions you offered 
to decide which is better, but sadly I need to code several other stuff, 
so if this one will work I would not furhter investigate at the moment.

I am testing with the pc, sending simple chars and getting them back 
from the fpga sligtly modified.

Many thanks for the help you give me while I explore this hobby, I would 
be really lost without this group.

Giuseppe Marullo