Smallest GPL UART

On May 1, 8:11 pm, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
Tim Wescott <t...@seemywebsite.com> wrote:
On Wed, 02 May 2012 00:46:56 +0200, Frank Buss wrote:
glen herrmannsfeldt wrote:
Frank Buss <f...@frank-buss.de> wrote:
(snip)
But you should latch the rx input, to avoid metastability problems. I
don't know how to do this in Verilog, something like declare another
reg with the name "rx", rename the raw input signal and copy it on
rising clock edge to "rx".
Can you explain the problem that you are considering?

(snip)

Not that slow logic can't have metastability problems,
but in this case I wouldn't expect it.
My experience differs: I've used my simple UART receiver in a design
with 115,200 baud, and without the buffer, the state machine halted
(going to an invalid state, as I debugged with an "other" case branch,
which was logically impossible) once every some hour.

OK, I suppose I could have looked at the actual logic before writing.

Yes, if one isn't careful with a state machine, it can have
metastability problems even with a slow clock.

There is also that Quartus likes to rearrange state machines logic,
such that it isn't like it is written. Some years ago, I found a
bug in Quartus where it converted to a one-hot state machine even
though I was using the state value in the design. (It had four
states, and as written two state bits. Quartus converted to one-hot
and gave two of the four as state bits.)

There was lots of
high-speed logic behind the receiver and I've used only the classic
timing analyzer of an old version of Quartus, so maybe in simpler
designs, and with proper timing constraints for the rx signal, there
would be no problem.
But it is good design practice to buffer just any signal, which is fed
asynchronously to the FPGA, then you don't have such problems, even if
you didn't calculate and define all timing constraints.

Yes, if the design is such that more than one FF latches the same
input, and can fail if different values are latched on the same
clock cycle.

It might be a good practice to have that "other" case statement feeding
a master reset or some other more sensible response to a bad state than
wedging the FPGA, too.

That seems to be the easy way to fix it.

Now, it is likely that one additional clock cycle won't affect much,
but one does have to consider that in terms of the overall logic.

-- glen
Including a "when others => state <= reset"; will not help unless you
turn off state machine optimization, or invoke other "safe" state
machine synthesis settings. One of the optimizations most any
synthesizer worth its salt will do is remove "unreachable" states
(those states that do not have a coded assignment or path to them.)
Thus since "others" is not directly reachable, it gets optimized out,
along with anything it was doing.

There are multiple ways of dealing with this, most depend either on
invoking synthesis tool settings or turning off state machine
optimizations and manually handling it yourself in the RTL (such as
with a "when others". Be careful though; some of the simplest to code
methods result in the worst utilization and performance.

However, it is best to handle the root of the problem, which is an
improperly synchronized asynchronous input.

The term for this problem is not "race condition" it is an "improper
parallel synchronizer", or a circuit that clocks the same
asynchronous input into more than one register in parallel.

A "race condition" is when proper operation requires that one
combinatorial path must be faster than another.

Andy
 
Tim Wescott <tim@seemywebsite.com> writes:

But it is good design practice to buffer just any signal, which is fed
asynchronously to the FPGA, then you don't have such problems, even if
you didn't calculate and define all timing constraints.
Mandatory, I'd say, unless you can make a cast-iron argument as to why it
doesn't matter if it is sampled differently by two different flops.

It might be a good practice to have that "other" case statement feeding a
master reset or some other more sensible response to a bad state than
wedging the FPGA, too.
You'd think, wouldn't you?

But ( at least in VHDL) you also have to be aware that synthesis tools
(unless you do some hoop-jumping) are "clever" enough to "know" that you
can't get to those invalid states (especially in VHDL when using an
enumerated type: in language terms, anything outside the enumeration
doesn't exist!).

So they optimise out your nice recovery logic :(

Quartus has an attribute to make the synth put its own reset logic in for
invalid states, to go back to the reset state.

XST has an attribute to specify the safe state it should go to when
state is invalid. And another to enable that behaviour.

Synplify has an option to generate logic to put things back to the reset
state if an illegal state is detected.

None of which makes the implementation match the code...

Synplify also has an option to create an "exact" state machine, which
does do precisely what your code says (or so it claims) at the expense
of disabling all its clever optimisations for that machine.

Take your pick :)

Cheers,
Martin





Just sayin'
--
martin.j.thompson@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.co.uk/capabilities/39-electronic-hardware
 
In article <pv5y5p9w6uy.fsf@trw.com>,
Martin Thompson <martin.j.thompson@trw.com> writes:
Tim Wescott <tim@seemywebsite.com> writes:

But it is good design practice to buffer just any signal, which is fed
asynchronously to the FPGA, then you don't have such problems, even if
you didn't calculate and define all timing constraints.

Mandatory, I'd say, unless you can make a cast-iron argument as to why it
doesn't matter if it is sampled differently by two different flops.
Even if you are sure it doesn't matter, you aren't out of the water yet.

You still have to consider metastability.

You also have to consider the design lifetime. Will the guy who
changes something in this area several years from now be smart
enough to know that he needs check again? Will he get it right?

--
These are my opinions, not necessarily my employer's. I hate spam.
 
Hal Murray <hal-usenet@ip-64-139-1-69.sjc.megapath.net> wrote:

(snip)
Mandatory, I'd say, unless you can make a cast-iron argument as
to why it doesn't matter if it is sampled differently by
two different flops.

Even if you are sure it doesn't matter, you aren't out of the water yet.

You still have to consider metastability.
In most cases, for slow logic you don't.

Metastability becomes a problem if the logic after the FF is
long enough, and the FF is likely (ever) to be metastable long
enough to cause problems.

Note that you can never get rid of metastability, but only
make it unlikely enough to cause a problem. In high speed
designs, the logic delay is a significant part of a clock cycle,
and even a short metastability can be long enough.

You also have to consider the design lifetime. Will the guy who
changes something in this area several years from now be smart
enough to know that he needs check again? Will he get it right?
As with metastability, there is no way to avoid that.

-- glen
 
In article <jo1lgf$e5r$1@speranza.aioe.org>,
glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:
Hal Murray <hal-usenet@ip-64-139-1-69.sjc.megapath.net> wrote:
....

Even if you are sure it doesn't matter, you aren't out of the water yet.
You still have to consider metastability.

In most cases, for slow logic you don't.
Good point. Thanks.


The key idea being "slow logic" where the metastability settling time
is small relative to the cycle time.

--
These are my opinions, not necessarily my employer's. I hate spam.
 
On Wednesday, May 2, 2012 5:43:02 PM UTC+12, Frank Buss wrote:
Right, this is slightly different from metastability, and maybe was the
reason for the behaviour in my FPGA program, though the bugfix is the
same :)

Is there a technical term for this special kind of problem?
My preference is to call it an Aperture Effect, as it is actually a small, but finite time window, and you can even calculate the width (in ns/ps) of this Aperture, given a large enough data-set sample size.
 
Note that this has nothing to do with metastability.
Houston we have a problem.

I am implementing this stuff on a LX9 board that has a direct USB serial
interface. I tried to run it at 9600 baud, and it seemed to work fine.

I Implemented a small FSM that would echo a char back, maybe with a
little modification, ie send 'a' get back a 'c' (+2).

It worked but not if I kept sending char (a key always pressed down),
after about 20 chars there was some strange char back.

Thinking about baud rate tolerance and/or problem sending back fast the
char it received, I fiddled with the stop bits, hoping that it would
allow more time to "process" the incoming char.

No dice.

I tried to slow down the pace at which I would send chars, like 1 every
second or so, but every 15-20 char max, there was a very different char
back.

I was unable to debug with a LA (there is not much where I could connect
between the pc and the fpga) I tried to simulate a workbench
to exercise the fsm. It was rather difficult for me (several tasks in
parallel and so on) but the simulation seemed to work.

I tried to send the char it received from my pc to a serial LCD, and
there was even more errors on the output of the LCD.


At the end, I added this to the rx pin:

reg [2:0] rx_buffer;
wire rx_clean = rx_buffer[2];
always @(posedge clk)
rx_buffer <= {rx_buffer[1:0], rx};

It is working perfectly so far. Metastability, noise or whatever there
is something I don't get here. I have a very fast clock (100MHz) so
maybe it would benefit from a oversampling approach but the difference
with this metastabilitywhatever dirty fix is very noticeable.


Giuseppe Marullo
 
Giuseppe Marullo <giuseppe.marullonospam@iname.com> wrote:

Note that this has nothing to do with metastability.
Houston we have a problem.

I am implementing this stuff on a LX9 board that has a direct USB serial
interface. I tried to run it at 9600 baud, and it seemed to work fine.

I Implemented a small FSM that would echo a char back, maybe with a
little modification, ie send 'a' get back a 'c' (+2).

It worked but not if I kept sending char (a key always pressed down),
after about 20 chars there was some strange char back.

Thinking about baud rate tolerance and/or problem sending back fast the
char it received, I fiddled with the stop bits, hoping that it would
allow more time to "process" the incoming char.
Add one more stop bit to the device sending to your board.

Also, your board should start counting bits half way through the
start bit, such that it looks at the center of each bit.

You should be ready to start a new character after the middle of
the stop bit, though there really should be a whole stop bit.

As you note, because of clock tolerance, data might be coming in
faster than you can send it out. You could add a fifo, but eventually
you will fill it up unless you send data slower than it comes back.

-- glen
 
On Thursday, May 17, 2012 11:00:53 AM UTC+12, Giuseppe Marullo wrote:
I tried to run it at 9600 baud, and it seemed to work fine.
I tried to slow down the pace at which I would send chars, like 1 every
second or so, but every 15-20 char max, there was a very different char
back.

At the end, I added this to the rx pin:

reg [2:0] rx_buffer;
wire rx_clean = rx_buffer[2];
always @(posedge clk)
rx_buffer <= {rx_buffer[1:0], rx};

It is working perfectly so far. Metastability, noise or whatever there
is something I don't get here. I have a very fast clock (100MHz) so
maybe it would benefit from a oversampling approach but the difference
with this metastabilitywhatever dirty fix is very noticeable.
Did you also add a majority vote on those samples ?

it does seem strange from a random sampling angle - if you are running 9600 baud, and you get failures of 1 in 25, that suggests an error window equivalent of around 4us.

Things may not be random, I'd look around for something else wrong.
(ie you may not have fully fixed a problem, just moved it slightly)

Samples should be ~52us clear of any edges, and Stop bit should flip to start edge polling, at 50% stop time (this gives margin for baud rate skews)
( Shipping UARTS have made this mistake, you can also check by sending two stop bits )
You could output a pulse when you sample, and another when ready-for-Start, and scope that - at least a 1:25 failure is often enough, to be easy to catch.
 

Welcome to EDABoard.com

Sponsor

Back
Top