Verilog - RS-232 receiver - Randomly Halts - Page 1
Forum section: electronics / general

author: pigtwo
author_rank: Regular Contributor
timestamp: January 31, 2016, 10:53:44 pm
content: Hello all,I'm working on a basic RS-232 receiver to work with the basic FTDI usb converter. I've got it to work but I've run into a weird problem. It works perfectly for single reads, but if I have it read a bunch of times(not in a row, maybe a few millisecond gap between data being sent) it will just stop working. The weird part about this is it seems to be random. The number of reads until it breaks is probably 50-100. And the state the it breaks in is seemingly random.*code below for reference.It's kind of hard to describe what I mean by it breaking. It's like it just becomes completely unresponsive. Data comes into the RX line but it never responds. So you would think it's just stuck in some state, but I fairly thoroughly tested to see what state it was getting stuck in but I can't tell. What I did was make an test output and have it assert when it's in that state. This gave me completely random results. It was almost like, if I asserted the test output in a state, it would never fail in that state. I could never get it to consistently fail on a state. Then to make things weirder if if I have it assert in some states it will actually start working completely. But then other states it won't work. Which doesn't really make sense. This test output isn't connected to anything, it just goes high or low and I look at it on a logic analyzer.I know I've given a lot of information but I guess that's because it's very random and I can't see the pattern here. For example, if I remove a state that essentially has it wait for the stop bit to pass, it will actually work. The problem with this is that depending on what the last data bit is, it might confuse it for the start bit and start an invalid read. But I can't see why this is, it all seems random.Ok here's the code. There's a major design flaw so I'm going to rewrite it but I'm just very curious about what would cause this. Also I simulated and it does not exhibit this problem.This code is the RS-232 receiver. It works by checking the RX line for the start bit every cycle, so that it doesn't miss it. Then the rest is just handshaking to give the data to the module that wants it. It's not complete because I ran into this problem.http://pastebin.com/Hrgkjb2rFor reference the module that is driving this one is here. It pretty much just takes the data from it then outputs it to some LEDs.http://pastebin.com/dCeREk3vAny suggestions or thought would be great. I'm very curious about what could cause this because with my limited understanding I don't know of anything that could.

author: miguelvp
author_rank: Super Contributor
timestamp: January 31, 2016, 11:02:11 pm
content: Is this on windows?If so you might want to check your FTDI USB/UART is not a fake chip:https://www.eevblog.com/forum/microcontrollers/ftdi-gate-2-0/

author: pigtwo
author_rank: Regular Contributor
timestamp: January 31, 2016, 11:14:17 pm
content: It is on windows, but the data coming out of the ftdi chip is correct. If I understood that thread correctly if it thinks it's fake it just outputs random data, which mine isn't doing.

author: c4757p
author_rank: Super Contributor
timestamp: January 31, 2016, 11:19:24 pm
content: Have you simulated your design and tested it there?

author: pigtwo
author_rank: Regular Contributor
timestamp: January 31, 2016, 11:27:36 pm
content: Yeah I tried simulating and it doesn't show this problem. The simulation is different in that the data on the real fpga comes in kind of randomly but in the simulation I had it come in consistently. I didn't try putting gaps in the data like there is in the real design, so maybe I'll try that.

author: hamster_nz
author_rank: Super Contributor
timestamp: February 01, 2016, 12:07:02 am
content: I had a quick look, and didn't see anything obvious, but the logic is a bit more involved than I usually use for RS232/serial in my hacksHowever - MAKE SURE YOU SYNCHRONIZE YOUR RX SIGNALe.g.always @(posedge CLOCK_50)beginrx_safe_to_use <= rx_not_quite_safe_to_userx_not_quite_safe_to_use <= RX;endAnd NEVER use RX anywhere else in your design's logic. (Verilog is all foreign to me, so excuse my poor code!)Also - 50MHz clock, 3MHz data rate... um... 16.666 cycles per bit?I would not use a FSM, and instead use something bomb-proof (in very bad pseudo code)Code:every clock cyclewhen counter = 1.5*50/3 shift in bit 0when counter = 2.5*50/3 shift in bit 1when counter = 3.5*50/3 shift in bit 2when counter = 4.5*50/3 shift in bit 3when counter = 5.5*50/3 shift in bit 4when counter = 6.5*50/3 shift in bit 5when counter = 7.5*50/3 shift in bit 6when counter = 8.5*50/3 shift in bit 7 and assert deif counter = 9.5*50/3 then(((waiting for start bit)))if rx_safe_to_use = '0' thencounter = 0elseelsecounter <= counter + 1;end if;Using 50 because the design's clock is 50 MHz and 3 because the serial data rate is 3 Mb/s. Because of the high data rate counter only needs to be an 8 bit counter, so it isn't too fugly.

author: kc8apf
author_rank: Regular Contributor
timestamp: February 01, 2016, 12:22:18 am
content: Why did you put all of your logic in a combinatorial section? As hamster_nz said, in the behavioral section, synchronize the RX and look for edges:always @(posedge CLOCK_50) beginrx_d1 <= rx;rx_d2 <= rx_d1;if (rx_d1 & ~rx_d2) begin # Found an RX positive edge# If in Idle, move to Start.endendUsually you look for the edge of the start bit and then start a counter that runs off the system clock (CLOCK_50). Figure out how many CLOCK_50 ticks will happen per RX bit. When the counter hits that value, sample the RX input and reset the counter. Repeat until all the bits have been read.

author: pigtwo
author_rank: Regular Contributor
timestamp: February 01, 2016, 01:04:45 am
content: You guys were right, it was me not synchronizing the RX line. I literally just read about this too. I am surprised by the result though, I thought it would just oscillate between one and zero for a while but eventually would settle (whether it would settle correctly would be random).@hamster_nzYou're right my design is a little complicated. The problem I ran into was how to always watch for the start bit but also feed the received data out.In you're psudo code you say "when counter = 1.5*50/3". For the 1.5*50/3, would I just round this to the closest integer? Or would actually be like a float?@kc8apfI did it like that because that's the way my book taught me but I've really been meaning to learn how to use sequential logic better. I kind of just use it to create flip-flops for the registers then do all the real work with combinational logic. This is a good example of how the way I'm doing it is bad.Thanks for the help!

author: hamster_nz
author_rank: Super Contributor
timestamp: February 01, 2016, 01:39:24 am
content: Quote from: pigtwo on February 01, 2016, 01:04:45 amYeah, and what you are reading is most likely be incorrect too. It will waffle on about metastability, but that isn't the cause of your problem.Your design uses that signal as the same asynchronous input to more than once - let's just say it is used to reset a multi-bit counter to zero.From the pin, the signal might make the 'closest' bit of the counter in 5.00ns, and to the 'furthest' bit of the counter in 5.05ns. If your design clocks at 50 MHz (20ns) That gives a 0.05ns /20.0ns = 1 in 400 chance that the two parts of the design are seeing the signal as having different values each time the RX signal transitions. Enough to get a few characters through, but not a long stream.If it was a true metastability error it would more likely be a one-in-a-billion event (e.g. once every 20 seconds or so (or even longer) at 50 MHz), especially with a relatively slow design as the 20ns cycle gices a lot of time for a flipflop to snap to a stable state.I've run an experiments with an async 50 MHz signals into a 200 MHz clock domain, and I had to wait hours for any metastability events to be seen.Quote from: pigtwo on February 01, 2016, 01:04:45 amYep, just round down to the closet integer. It might be more technically correct to subtract one also, but hey! you've got sixteen or so clock edges per bit, so being off by one or two isn't going to break it. :-)

author: kc8apf
author_rank: Regular Contributor
timestamp: February 01, 2016, 04:21:27 am
content: Alternatively, you could use a phase accumulator for better jitter. Conceptually, you want to create a clock running at the baud rate. When the start bit shows up, you enable the clock and use its edges to read RX.