I encounter problems with my UART receiver module. It is supposed to work at 9600 bauds without parity bit and only one stop bit.
The problem is that my UART misses some characters (or to indicate that it received some characters) in a non-deterministic way.
My two main but unsucessful ideas about this problem were
1) a problem with the reception with the clock at 9600Hz, it is maybe not accurate enough or I don't have any error margin. I tried oversampling but it did not solve the problem.
2) A problem with the acknowledge coming from the outside (CPU). I use a little trick with a DFF to let the CPU acknowledge correctly his reading while having a much higher clock that the receiver (50MHz vs 9600Hz).
I am perfectly sure that my clock is at 9600Hz (I am able to receive correctly a lot of characters).
Here is the small code of the receiver I use.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity UART_Receive is
port(
clk_9600Hz : in std_logic;
reset_n : in std_logic;
ackNewData : in std_logic;
ready : out std_logic;
dataToRead : out std_logic_vector(7 downto 0);
Rx : in std_logic
);
end entity UART_Receive;
architecture RTL of UART_Receive is
signal counter : unsigned(3 downto 0);
signal buffer_read : std_logic_vector(7 downto 0);
signal lastData : std_logic_vector(7 downto 0);
signal newDataReady: std_logic;
begin
dataToRead <= lastData;
process(ackNewData, newDataReady)
begin
if(ackNewData = '1') then
ready <= '0';
elsif(rising_edge(newDataReady)) then
ready <= '1';
end if;
end process;
process(clk_9600Hz, reset_n) is
begin
if reset_n = '0' then
lastData <= (others => '0');
counter <= (others => '0');
buffer_read <= (others => '0');
elsif rising_edge(clk_9600Hz) then
if counter = 0 and Rx = '0' then
counter <= counter + 1;
elsif counter = 9 then
counter <= (others => '0');
lastData <= buffer_read;
newDataReady <= '1';
elsif counter /= 0 then
buffer_read <= Rx & buffer_read(7 downto 1);
counter <= counter + 1;
end if;
end if;
end process reg_slow_process;
end architecture RTL