Author Topic: UART timing problem  (Read 4713 times)

0 Members and 1 Guest are viewing this topic.

Offline BogdanTopic starter

  • Newbie
  • Posts: 8
  • Country: ro
UART timing problem
« on: August 25, 2015, 09:18:07 am »
Hello everyone !  :D

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)
begin
   if rx = '0' then
      UART_innactive <= '0';
      count <= x"0000";
   elsif rising_edge(clk_s) then
         if count = x"0030" then
            UART_innactive <= '1';
            count <= x"0000";
         else
            count <= 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 rapidly

Thank you

« Last Edit: August 25, 2015, 09:24:14 am by Bogdan »
 

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 4233
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: UART timing problem
« Reply #1 on: August 25, 2015, 09:39:32 am »
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: [Select]
signal count : integer range 0 to 63 := 0;

process (clk_s)
begin

  if rising_edge (clk_s) then
    UART_innactive <= '0';

    if rx = '0' then
      count <= 0;
    else
      if count < 31 then
        count <= count + 1;
      else
        UART_innactive <= '1';
      end if;
    end if;
  end if;

end process;

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26998
  • Country: nl
    • NCT Developments
Re: UART timing problem
« Reply #2 on: August 25, 2015, 10:03:21 am »
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.
Using 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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline BogdanTopic starter

  • Newbie
  • Posts: 8
  • Country: ro
Re: UART timing problem
« Reply #3 on: August 25, 2015, 10:12:47 am »
AndyC
Thank 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)

Nctnico
Can you offer more details ?
How can i sample Rx in clock domain ?
Thank you,
« Last Edit: August 25, 2015, 11:15:36 am by Bogdan »
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26998
  • Country: nl
    • NCT Developments
Re: UART timing problem
« Reply #4 on: August 25, 2015, 01:27:52 pm »
Use something like this with an extra signal which is a sampled version of the external signal.
Code: [Select]

signal rx_sampled : std_logic;

process(clk_s)
begin
  rx_sampled <= rx;  -- sample rx into the clk_s domain using one flipflop

   if rx_sampled = '0' then
      UART_innactive <= '0';
      count <= x"0000";
   elsif rising_edge(clk_s) then
         if count = x"0030" then
            UART_innactive <= '1';
            count <= x"0000";
         else
            count <= std_logic_vector (unsigned(count) + 1);
         end if;
   end if;
end process;
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline BogdanTopic starter

  • Newbie
  • Posts: 8
  • Country: ro
Re: UART timing problem
« Reply #5 on: August 25, 2015, 01:57:48 pm »
well, it doesn't work
i use baud rate 781 250 Hz
clock 1 562 500 Hz

I 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
« Last Edit: August 25, 2015, 02:07:02 pm by Bogdan »
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26998
  • Country: nl
    • NCT Developments
Re: UART timing problem
« Reply #6 on: August 25, 2015, 02:34:22 pm »
Did you measure rx with an oscilloscope? When using a uart the idle state of rx and tx is '1'.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline BogdanTopic starter

  • Newbie
  • Posts: 8
  • Country: ro
Re: UART timing problem
« Reply #7 on: August 25, 2015, 02:48:47 pm »
I don't have one unfortunately  :(
But 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
 

Offline BloodyCactus

  • Frequent Contributor
  • **
  • Posts: 482
  • Country: us
    • Kråketær
Re: UART timing problem
« Reply #8 on: August 25, 2015, 03:22:29 pm »
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?
-- Aussie living in the USA --
 

Offline BogdanTopic starter

  • Newbie
  • Posts: 8
  • Country: ro
Re: UART timing problem
« Reply #9 on: August 25, 2015, 03:43:11 pm »
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.
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: UART timing problem
« Reply #10 on: August 25, 2015, 04:23:24 pm »
I use RealTerm for sending the files. Is it possbile that there is some delay between sending data ?
Probably. 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?
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26998
  • Country: nl
    • NCT Developments
Re: UART timing problem
« Reply #11 on: August 25, 2015, 05:03:49 pm »
I don't have one unfortunately  :(
But 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.
Try 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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline dgtl

  • Regular Contributor
  • *
  • Posts: 183
  • Country: ee
Re: UART timing problem
« Reply #12 on: August 25, 2015, 06:22:10 pm »
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: [Select]
-- clk is 16x UART baud
process(clk, reset)
begin
  if reset = '1' then -- async reset
    rx_d <= '1';
    rx_dd <= '1';
    rx_busy <= '0';
    count <= x"00";
    bit <= x"00";
  elsif rising_edge(clk) then
    rx_d <= rx; -- clock crossing
    rx_dd <= rx_d;
   
    if rx_busy = '0' then
      if rx_dd = '0' then -- edge of start bit
        rx_busy <= '1';
        count <= x"0";
        bit <= x"0";
      end if;
    else
      if count = x"8" then -- half of bit, sample here (counter overflows at 0xF)
        if bit = x"9" then -- stop bit, do something with data here
          rx_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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf