UART rx is not properly working - Page 1
Forum section: electronics / general

author: TrikyTex
author_rank: Newbie
timestamp: October 10, 2023, 01:22:19 pm
content: i'm working with FPGA vhdl, UART displaying characters on serial monitorMy logic is,transmission starts when i click "a"transmission stops when i click "z"transmits all ascii characters during transmissionsall ascii characters are displaying in serial monitor without doing anything like a loopreceiving is not happening in the below mentioned codeCode:library IEEE;use IEEE.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity uart_tx_rx isport ( 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 issignal 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;--------------beginclk_Counter: process(tclk)beginif rising_edge(tclk) thenif counterCLK_counter = counterRatio/2-1 thencounterClkout <= not counterClkout;counterCLK_counter <= counterCLK_counter + 1;elsif counterCLK_counter = counterRatio-1 thencounterClkout <= not counterClkout;counterCLK_counter <= 0;elsecounterCLK_counter <= counterCLK_counter + 1;end if;end if;end process;Counter: process (counterClkout)beginif rising_edge(counterClkout) thentemp <= temp + 1;end if;end process;tx_process:process(tclk,tx_en)beginif rising_edge(tclk) thenif tx_en = '1' thenif (index = 1) thentx <= '0'; -- start bitindex <= index+1;tx_num <= 7;elsif (index = 10) thentx <= '1'; -- stop bitindex <= 1;tx_num <= 7;elsetx <= temp (tx_num);tx_num <= tx_num-1;index <= index+1;end if;end if;end if;end process;rx_process:process(clkMCU)beginif (clkMCU'event and clkMCU = '1') thenif (MidSampleCnt_UART = 7) thenMidSampleCnt_UART <= 0;if (indexUartRx_UART >0) thenUARTBufferRx_UART(indexUartRx_UART-1) <= RX;indexUartRx_UART <= indexUartRx_UART + 1;if(indexUartRx_UART = 9) thenindexUartRx_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;elseif(RX = '0' and indexUartRx_UART = 0) thenRxBuf_ready_UART <= 0;MidSampleCnt_UART <= MidSampleCnt_UART + 1;if (MidSampleCnt_UART = 4) thenMidSampleCnt_UART <= 0;indexUartRx_UART <= 1;end if;end if;if(indexUartRx_UART > 0) thenMidSampleCnt_UART <= MidSampleCnt_UART + 1;end if;end if;end if;end process;end arc;please help me to resolve itThanks in advance

author: AK6DN
author_rank: Regular Contributor
timestamp: October 11, 2023, 05:33:41 am
content: 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.

author: TrikyTex
author_rank: Newbie
timestamp: October 11, 2023, 06:35:12 am
content: 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 thisi'm new to VHDL and FPGAneed help to debug this..

author: betocool
author_rank: Regular Contributor
timestamp: October 11, 2023, 11:56:43 am
content: 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

author: hamster_nz
author_rank: Super Contributor
timestamp: October 11, 2023, 11:49:22 pm
content: 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:run 20 msERROR: Index 8 out of bound 7 downto 0Time: 938255 ns Iteration: 1 Process: /tb_uart_tx_rx/uut/rx_processHDL Line: uart.vhd:96This is the code from lines 94 to 96:Code:if (indexUartRx_UART >0) thenUARTBufferRx_UART(indexUartRx_UART-1) <= RX;indexUartRx_UART <= indexUartRx_UART + 1;Here it is the test bench, in case it proves useful:Code:library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.NUMERIC_STD.ALL;entity tb_uart_tx_rx isend tb_uart_tx_rx;architecture Behavioral of tb_uart_tx_rx iscomponent uart_tx_rx isport (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 periodbegin-------------- CLOCKS - both 100 MHz------------processbegintclk <= '0';wait for 5 ns;tclk <= '1';wait for 5 ns;end process;processbeginclkMCU <= '0';wait for 5 ns;clkMCU <= '1';wait for 5 ns;end process;----------------------------------- Generate 9600 baud serial data---------------------------------rx <= rx_sr(0);processbeginrx_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;

author: hamster_nz
author_rank: Super Contributor
timestamp: October 12, 2023, 12:22:22 am
content: 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: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: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.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 12, 2023, 02:56:04 am
content: 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).

author: davep238
author_rank: Contributor
timestamp: October 14, 2023, 12:22:05 am
content: 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-moduleseems to have a good explanation of this, plus code!

author: dietert1
author_rank: Super Contributor
timestamp: October 14, 2023, 07:08:01 am
content: 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