UART timing problem - Page 1
Forum section: electronics / general

author: Bogdan
author_rank: Newbie
timestamp: August 25, 2015, 09:18:07 am
content: Hello everyone !This is my first post on this forum. I hope this topic is in the right place..So i have this project in which i use the UART serial interface between my Nexys 3 (Spartan 6) FPGA and my PC.I transfer "large" files ( like 1 MB ) to it and i needed a way to detect when the FPGA would stop receiving data(from UART).Pretty simple..right ?I used the fact that the Rx is '1' when inactive and '0' when it starts transmitting data (START bit is '0').So i decided to increment a Counter when Rx = '1' and reset it to '0' when Rx = '0'.If the counter reaches a certain value (depends on the sample rate) then i can say the UART is innactive ( Rx was '1' for a long time)But it doesn't work...The Baud Rate i use = 781250 and the transfer of data works flawlessly ( i sample Rx with a clock = 12,5 Mhz, 16 times per bit transfered) but i don't manage to do this inactivity detection circuit to work.I tested a lot of other baud rates : (sampling 2 times per bit, so the clock frequency = 2 x Baud Rate, it should be enough)300 Works !9600 Works !19200 Works !57600 Nope..781250 Nope..This is the code, clk_s is twice the frequency of the Baud Rate, so i can sample each bit 2 times.So in maximum 20 clock cycles i should encounter at least one zero (the start bit);I put x"0030" = 48 just for good measure...process(clk_s, rx)beginif rx = '0' thenUART_innactive <= '0';count <= x"0000";elsif rising_edge(clk_s) thenif count = x"0030" thenUART_innactive <= '1';count <= x"0000";elsecount <= std_logic_vector (unsigned(count) + 1);end if;end if;end process;So.. i suspect a timing problem coming wither from my bad code or the FPGA.The led i connected UART_innactive to just blinks very rapidlyThank you

author: AndyC_772
author_rank: Super Contributor
timestamp: August 25, 2015, 09:39:32 am
content: Hi,Since you have a continuous, free running clock which is at least as fast as the data bits you're looking for, use that to clock your detection process. At the moment, you're using Rx as an asynchronous clear, which although valid, can make it harder to correctly specify and meet timing constraints.How about this:Code:signal count : integer range 0 to 63 := 0;process (clk_s)beginif rising_edge (clk_s) thenUART_innactive <= '0';if rx = '0' thencount <= 0;elseif count < 31 thencount <= count + 1;elseUART_innactive <= '1';end if;end if;end if;end process;

author: nctnico
author_rank: Super Contributor
timestamp: August 25, 2015, 10:03:21 am
content: Quote from: AndyC_772 on August 25, 2015, 09:39:32 amUsing RX this way can never work. The delays to the various flipflips will always vary so count will jump to weird values. What is needed here is to sample RX into the clock domain and use the sampled version to clear the counter.

author: Bogdan
author_rank: Newbie
timestamp: August 25, 2015, 10:12:47 am
content: AndyCThank you for your reply, but it doesn't work, when i transmit data, the LED i connected to UART_innactive is on but flickers very gently (almost unobservable)NctnicoCan you offer more details ?How can i sample Rx in clock domain ?Thank you,

author: nctnico
author_rank: Super Contributor
timestamp: August 25, 2015, 01:27:52 pm
content: Use something like this with an extra signal which is a sampled version of the external signal.Code:signal rx_sampled : std_logic;process(clk_s)beginrx_sampled <= rx; -- sample rx into the clk_s domain using one flipflopif rx_sampled = '0' thenUART_innactive <= '0';count <= x"0000";elsif rising_edge(clk_s) thenif count = x"0030" thenUART_innactive <= '1';count <= x"0000";elsecount <= std_logic_vector (unsigned(count) + 1);end if;end if;end process;

author: Bogdan
author_rank: Newbie
timestamp: August 25, 2015, 01:57:48 pm
content: well, it doesn't worki use baud rate 781 250 Hzclock 1 562 500 HzI will try different clock frequencys..I use RealTerm for sending the files. Is it possbile that there is some delay between sending data ? after each 10 bits ? (1 start, 8 data, 1 stop) The delay is set to 0...but i don't know

author: nctnico
author_rank: Super Contributor
timestamp: August 25, 2015, 02:34:22 pm
content: Did you measure rx with an oscilloscope? When using a uart the idle state of rx and tx is '1'.

author: Bogdan
author_rank: Newbie
timestamp: August 25, 2015, 02:48:47 pm
content: I don't have one unfortunatelyBut the UART works great, i managed to send an entire image to the FPGA with 781250 Baud Rate..so i doubt anything is wrong with the interface.But the problem has something to do with the frequency..i mean it WORKS at 300, 9600, 19200 baud rates

author: BloodyCactus
author_rank: Frequent Contributor
timestamp: August 25, 2015, 03:22:29 pm
content: it might work at 300, 9600, 19200, but by the time you get to 57600 your probably outside the baud rate error window. have you done the baud calculations to know what your error rate% is at for each connection?

author: Bogdan
author_rank: Newbie
timestamp: August 25, 2015, 03:43:11 pm
content: No, i didn't do the calculations for the error rate.. is the first time i hear of something like that .Can you explain what that is or direct me to a link where i can find out more ?I don't think i have any errors...i mean i transfered a 1 MB image to the fpga (using UART 781250) and displayed it on a screen... and the image looks perfect .The UART interface works great at BAUD rates over 57600...its just this peticular circuit of innactivity detection that doesn't work.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: August 25, 2015, 04:23:24 pm
content: Quote from: Bogdan on August 25, 2015, 01:57:48 pmProbably. At high baud rates it may not be able to keep the transmit buffer filled continuously, then there will be gaps between characters.Try increasing the the count from 48 to something much larger (eg. 256). Does it now work at a higher baud rate?

author: nctnico
author_rank: Super Contributor
timestamp: August 25, 2015, 05:03:49 pm
content: Quote from: Bogdan on August 25, 2015, 02:48:47 pmTry and test for rx_sampled=1 instead of 0. I strongly suggest to get something like a logic analyser or oscilloscope. Now you are just walking in the dark.

author: dgtl
author_rank: Regular Contributor
timestamp: August 25, 2015, 06:22:10 pm
content: First, re-clock the rx signal to your clock domain to avoid metastability. For this purpose, add some flipflops to the signal.Then, use sampling clock, that is more than twice as fast to capture the edge of the start bit a bit more precisely. Then, capture data bits at the center of the bits (1.5 bits after edge of start bit). For more noise tolerance, you may add triple-sampling etc, but at that low speeds you'll be fine without. Also write proper timing constraints to the signals and clocks so that the timings can be considered in the synthesis.Also, do your math about the tolerance of the baud rate. If the clock rates of sender and receiver are off, the problems start when the sampling point of the last (stop) bit moves from the midpoint to the edge of the bit. A good implementation can handle both fast and slow baud mismatch (ie it does not wait the end of stop bit after sampling point in case the next start bit comes early). As a rule of thumb, a uart can tolerate up to +/-5% baud rate error (half bit of 10 bits). Leave half of it to the other side - your clock rate error shall be no more than 2.5%.The VHDL code can look something like this:Code:-- clk is 16x UART baudprocess(clk, reset)beginif reset = '1' then -- async resetrx_d <= '1';rx_dd <= '1';rx_busy <= '0';count <= x"00";bit <= x"00";elsif rising_edge(clk) thenrx_d <= rx; -- clock crossingrx_dd <= rx_d;if rx_busy = '0' thenif rx_dd = '0' then -- edge of start bitrx_busy <= '1';count <= x"0";bit <= x"0";end if;elseif count = x"8" then -- half of bit, sample here (counter overflows at 0xF)if bit = x"9" then -- stop bit, do something with data hererx_busy <= '0';end if;rx_data <= rx_dd & rx_data(7 downto 1);bit <= bit + 1;end if;count <= count + 1;end if;end if;end process;To improve this, verify start and stop bits at their capture. You may also capture 3 times around the sampling point and take the majority vote for some more noise tolerance.