Author Topic: UART rx is not properly working  (Read 2864 times)

0 Members and 1 Guest are viewing this topic.

Offline TrikyTexTopic starter

  • Newbie
  • Posts: 2
  • Country: in
UART rx is not properly working
« on: October 10, 2023, 01:22:19 pm »
i'm working with FPGA vhdl, UART displaying characters on serial monitor


My logic is,
transmission starts when i click "a"
transmission stops when i click "z"
transmits all ascii characters during transmissions
all ascii characters are displaying in serial monitor without doing anything like a loop

receiving is not happening in the below mentioned code
Code: [Select]
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity uart_tx_rx is

port ( tclk,clkMCU: in std_logic;
       RX: in std_logic;
       tx: out std_logic;
       debug_pin :out std_logic:= '1';
       debug_pin2 :out std_logic;
       sync:out std_logic;
       sample_clk: out std_logic);
       
end  uart_tx_rx;

architecture arc of uart_tx_rx is

signal counterCLK_counter : integer range 0 to 31;
signal counterRatio : integer := 10;
signal counterClkout : std_logic;
-----------
signal temp : std_logic_vector (0 to 7) ;
------------
signal txClk_counter : integer range 0 to 255;
signal ratio_3 : integer := 10; 
signal txClkout : std_logic;
----------------
signal index : integer range 1 to 10 := 1 ;
signal tx_finish : std_logic := '1';
signal loop_index : integer range 0 to 162 := 0;
signal tx_num : integer range 0 to 7 := 7  ;
--------------------
signal MidSampleCnt_UART   : integer range 0 to 10      := 0;
signal indexUartRx_UART    : integer range 0 to 9    := 0;
signal UARTBufferRx_UART   : STD_LOGIC_VECTOR (7 downto 0):= "00110110";
signal tx_en : std_logic := '1';
signal RxBuf_ready_UART    : integer range 0 to 1     := 0;
--------------

begin
   
    clk_Counter: process(tclk)
    begin

        if rising_edge(tclk) then
            if counterCLK_counter = counterRatio/2-1 then     
                counterClkout <= not counterClkout;
                counterCLK_counter <= counterCLK_counter + 1;
            elsif counterCLK_counter = counterRatio-1 then     
                counterClkout <= not counterClkout;
                counterCLK_counter <= 0;                 
            else
                counterCLK_counter <= counterCLK_counter + 1;
            end if;
        end if;
    end process;       
       
    Counter: process (counterClkout)
    begin   
        if rising_edge(counterClkout) then
            temp <= temp + 1;
        end if;     
    end process;
   
   
    tx_process:process(tclk,tx_en)
    begin
        if rising_edge(tclk) then
            if tx_en = '1' then             
                if (index = 1) then
                    tx <= '0'; -- start bit
                    index <= index+1;
                    tx_num <= 7;
                elsif (index = 10) then
                    tx <= '1';  -- stop bit
                    index <= 1;
                    tx_num <= 7;   
                else
                    tx <= temp (tx_num);
                    tx_num <= tx_num-1;
                    index <= index+1;   
                end if;                 
        end if;         
        end if;
    end process;
   
    rx_process:process(clkMCU)
    begin
            if (clkMCU'event and clkMCU = '1') then
               
                if (MidSampleCnt_UART = 7) then
                    MidSampleCnt_UART <= 0;
                    if (indexUartRx_UART >0) then       
                        UARTBufferRx_UART(indexUartRx_UART-1) <= RX;
                        indexUartRx_UART <= indexUartRx_UART + 1;
                        if(indexUartRx_UART = 9) then   
                            indexUartRx_UART <= 0;
                            --Start (a)
                            if(UARTBufferRx_UART(7 downto 0)= "01100001") then
                                --sampling_en <= '1';
                                tx_en <= '1';
                                --key <= '1';                       
                            end if;
                            -- stop (z)
                            if(UARTBufferRx_UART(7 downto 0)= "01111010") then
                                --sampling_en <= '0';   
                                tx_en <= '0';                   
                            end if;
                        end if;
                    end if;         
                else
                    if(RX = '0' and indexUartRx_UART = 0) then
                        RxBuf_ready_UART <= 0;
                        MidSampleCnt_UART <= MidSampleCnt_UART + 1;
                        if (MidSampleCnt_UART = 4) then
                            MidSampleCnt_UART <= 0;
                            indexUartRx_UART <= 1;
                        end if;
                    end if;     
                    if(indexUartRx_UART > 0) then
                        MidSampleCnt_UART <= MidSampleCnt_UART + 1;
                    end if;
                end if;     
        end if;
    end process;
end arc; 



please help me to resolve it

Thanks in advance
 

Offline AK6DN

  • Regular Contributor
  • *
  • Posts: 55
  • Country: us
Re: UART rx is not properly working
« Reply #1 on: October 11, 2023, 05:33:41 am »
Lots of vhdl to read thru (I am a verilog guy myself) so I can't comment much on your code.
BUT, how about you use a logic simulator and waveform display to highlight relevant signals during a simulation.
You might just be able to see what is going on and going wrong, and others may be able to provide some useful comments.
 

Offline TrikyTexTopic starter

  • Newbie
  • Posts: 2
  • Country: in
Re: UART rx is not properly working
« Reply #2 on: October 11, 2023, 06:35:12 am »
thanks for your reply,
while i'm debugging with modelsim i observed that received signal is not transmitting.. i need to know how can i debug this

i'm new to VHDL and FPGA

need help to debug this..
« Last Edit: October 11, 2023, 06:37:17 am by TrikyTex »
 

Offline betocool

  • Regular Contributor
  • *
  • Posts: 95
  • Country: au
Re: UART rx is not properly working
« Reply #3 on: October 11, 2023, 11:56:43 am »
If you have access to Modelsim then you should write a test bench and 'debug' on screen, it will save you lots of time in the long run. Not knowing what FPGA you're using I'm not familiar with any of the tools signal analyzers.

Modelsim may seem a bit difficult at the beginning, but start by adding all your signals and knowing when they must change. If you see something that's not changing where you expect them to, bingo!, update the code and re-run the simulation.

If your project compiles and builds with no timing errors, chances are the simulation will show you a very good snapshot of what's happening in the code.

Cheers,

Alberto
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: UART rx is not properly working
« Reply #4 on: October 11, 2023, 11:49:22 pm »
I wrote a quick test bench - I've got no detail of what the two input signals tclk and clkMCU run at, or what baud rate RX is running at. If you can tell me I'll update my test bench.

My simulation throws an error.

Code: [Select]
run 20 ms
ERROR: Index 8 out of bound 7 downto 0
Time: 938255 ns  Iteration: 1  Process: /tb_uart_tx_rx/uut/rx_process

HDL Line: uart.vhd:96

This is the code from lines 94 to 96:
Code: [Select]
                    if (indexUartRx_UART >0) then       
                        UARTBufferRx_UART(indexUartRx_UART-1) <= RX;
                        indexUartRx_UART <= indexUartRx_UART + 1;

Here it is the test bench, in case it proves useful:

Code: [Select]
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity tb_uart_tx_rx is
end tb_uart_tx_rx;

architecture Behavioral of tb_uart_tx_rx is
    component uart_tx_rx is
    port (
        tclk        : in  std_logic;
        clkMCU      : in  std_logic;
        RX          : in  std_logic;
        tx          : out std_logic;
        debug_pin   : out std_logic:= '1';
        debug_pin2  : out std_logic;
        sync        : out std_logic;
        sample_clk  : out std_logic
    );
    end  component;

    signal tclk        : std_logic;
    signal clkMCU      : std_logic;
    signal RX          : std_logic;
    signal tx          : std_logic;
    signal debug_pin   : std_logic:= '1';
    signal debug_pin2  : std_logic;
    signal sync        : std_logic;
    signal sample_clk  : std_logic;

    signal rx_sr       : std_logic_vector(39 downto 0) := "1" & x"42" & "0"  --  STOP BIT, ASCII C, START BIT   
                                                        & "1" & x"42" & "0"  --  STOP BIT, ASCII B, START BIT   
                                                        & "1" & x"41" & "0"  --  STOP BIT, ASCII A, START BIT   
                                                        & "1" & x"FF" & "1";  -- all ones - idle period
                                                       
begin

------------
-- CLOCKS - both 100 MHz
------------
process
    begin
        tclk <= '0';
        wait for 5 ns;
        tclk <= '1';
        wait for 5 ns;
    end process;

process
    begin
        clkMCU <= '0';
        wait for 5 ns;
        clkMCU <= '1';
        wait for 5 ns;
    end process;
   
---------------------------------
-- Generate 9600 baud serial data
---------------------------------
    rx <=  rx_sr(0);
process
    begin
        rx_sr <= rx_sr(0) & rx_sr(rx_sr'high downto 1);
        wait for (1000000000/9600) * 1ns;
    end process;

-----------------------
-- Unit under test
-----------------------

uut: uart_tx_rx port map (
        tclk        => tclk,
        clkMCU      => clkMCU,
        RX          => rx,
        tx          => tx,
        debug_pin   => debug_pin,
        debug_pin2  => debug_pin2,
        sync        => sync,
        sample_clk  => sample_clk
    );

end Behavioral;
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: UART rx is not properly working
« Reply #5 on: October 12, 2023, 12:22:22 am »
Oh I made an assumption that tclk is the bit clock for the transmit, and it transmitted nothing.

That was because 'temp' was empty.

Code: [Select]
    signal temp : std_logic_vector (0 to 7);

You also never set the values in these, so they stay at "U" during the simulation:
Code: [Select]
    signal counterCLK_counter : integer range 0 to 31;
    signal counterClkout : std_logic;

In FPGAs they will usually get set to 0s, but you might want to think about a reset.

What I would also do is consider incrementing temp when you send the stop bit, rather than have the separate 'counterClkout' clock domain.
« Last Edit: October 12, 2023, 12:27:47 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14124
  • Country: fr
Re: UART rx is not properly working
« Reply #6 on: October 12, 2023, 02:56:04 am »
Other than these initialization issues and potentially indexing errors, while I haven't looked at the code thoroughly, I'm not 100% certain the RX sampling part of the code is fully safe. In particular, as it's layed out in a bit convoluted way, it's hard to tell whether the RX signal goes through at least a chain of 2 flip flops before being read. Asynchronous is asynchronous. So, something to have an eye on.

For the very general code style points, the code contains a mix of styles for some unknown reason (maybe explained by copy and pasting from various sources). For instance, you use 'rising_edge()' in some places and 'clkMCU'event and clkMCU = '1'' in others. Be consistent. rising_edge() is the way to go. Another point is, VHDL is not C, there is absolutely no need to put parentheses around the 'if' clause (and here again, we can see a mix of styles in your code).
 

Offline davep238

  • Contributor
  • Posts: 27
  • Country: us
Re: UART rx is not properly working
« Reply #7 on: October 14, 2023, 12:22:05 am »
In standalone UART chips, the Rx bit stream is sampled 16 times per Rx bit. For a 9600 baud rate, the Rx sample clock is 153600Hz. A byte starts with a start bit, 8 data bits, and 1 or 2 stop bits. The trick is in synchronizing the UART's receive logic to each byte, for *every* byte. This begins with finding the start bit, which begins with a transition from '1' (input idle) to '0'. The logic then counts to 8 (1/2 of a bit), and reads the Rx bit. If it is still a '0', then a start-bit has been detected. If not, then the logic starts over until it detects a start-bit. The idea is to always sample the Rx bit stream in the middle of a bit.
Once the start-bit is detected, then the logic counts to 16 (a full bit) and reads the Rx bit. This is bit-0, which is the least-significant-bit of the byte. This corresponds to your index of 0. The logic counts again to 16 and reads the Rx bit, which is now bit-1. This continues until all 8 bits (0 thru 7) have been read. The logic then counts a final time to 16 and reads the Rx bit, which must be a '1'. This is the stop bit. If the stop bit is not detected, then it's a framing error.
The received byte is transferred into an 8-bit receive register for the CPU to read. A flag (RxReady) is set to show that an entire byte has been read. The logic then starts looking for a start-bit again.
The CPU can then read the receive register, which also clears (0's) the RxReady flag.

https://nandland.com/uart-serial-port-module
seems to have a good explanation of this, plus code!
 

Offline dietert1

  • Super Contributor
  • ***
  • Posts: 1989
  • Country: br
    • CADT Homepage
Re: UART rx is not properly working
« Reply #8 on: October 14, 2023, 07:08:01 am »
Better implement a digital low pass filter to sample asynchronous input.
As an example use an up/down counter that runs between 0 and 7. Unless 0 it decrements when a sampled input bit is 0. Unless 7 it increments when a sampled input bit is 1. Then decrementing from 1 to 0 represents a falling edge - 7 or more cycles in the past.
A counter value of 0 represents a low level and a counter value of 7 represents a high level. All other counter values represent an error condition. Another more noise tolerant partition is 0,1 = low, 2..5 = error and 6,7 = high.
Then implement the UART logic using the filter output.

Regards, Dieter
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf