0
votes

I have a VHDL component that is connected to a UART receiver. The uart has 2 output signals, one for the byte received and one for a flag that is set to 1 when the byte is done being received.

I have written the following module that should increment a counter for every new char and show it lighting up some leds.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;

entity test is
port (
  clk : in std_logic;
  rst : in std_logic;
  ena : in std_logic;
  rx :  in std_logic;
  led0 : out std_logic;
  led1 : out std_logic;
  led2 : out std_logic;
  led3 : out std_logic;
  led4 : out std_logic;
  led5 : out std_logic;
  led6 : out std_logic;
  led7 : out std_logic
);
end test;

architecture arch of test is
    component UART_RX
    generic (
        g_CLKS_PER_BIT : integer := 115     -- Needs to be set correctly
    );
    port (
        i_Clk       : in  std_logic;
        i_RX_Serial : in  std_logic;
        o_RX_DV     : out std_logic;
        o_RX_Byte   : out std_logic_vector(7 downto 0)
    );
   end component;

   signal sig_Din   : std_logic_vector(7 downto 0);
   signal sig_Dout  : std_logic_vector(7 downto 0);
   signal sig_RxErr : std_logic;
   signal sig_RxRdy : std_logic;
   signal sig_TxBusy    : std_logic;
   signal sig_StartTx: std_logic;

   begin

     UUT : UART_RX
     generic map (
        g_CLKS_PER_BIT => 434
     )
     port map (
        i_clk       => clk,
        i_rx_serial => rx,
        o_rx_dv     => sig_RxRdy,
        o_rx_byte   => sig_Dout
    );

    process(clk)
        variable position : integer := 0;
        variable position_v : std_logic_vector(7 downto 0) := "00000000";
    begin
        if(sig_RxRdy = '1') then
            position := position + 1;
            position_v := std_logic_vector((unsigned(position_v1), 1));
            led0 <= position_v(0);
            led1 <= position_v(1);
            led2 <= position_v(2);
            led3 <= position_v(3);
            led4 <= position_v(4);
            led5 <= position_v(5);
            led6 <= position_v(6);
            led7 <= position_v(7);
        end if;
    end process;


end arch;

Is there any problem with the implementation? Every new char i send ends up incrementing the counter by more than 1. And is not even the same value every time. I must not be understanding how FPGAs actually work because this is simple and I can't get it to work.

1
Your process is not sensitive to any particular clock edge. I don;t know if this is the solution, but you definitely should add if rising_edge(clk) or if falling_edge(clk) so that process launches only on one clock edge. - Staszek
Code is incomplete. Where is position_v1? What is std_logic_vector((unsigned(position_v1), 1)) supposed to mean anyhow. Please post a WORKING minimal reproducible example. - JHBonarius
Your code has errors and isn't valid syntactically or semantically. Instead of position_v := std_logic_vector((unsigned(position_v1), 1)); it appears you should have position_v := std_logic_vector(to_unsigned(position, 8)); Also your RTL does not synthesize to using the rising edge of clk, instead creating a relaxation oscillator gated by sig_RxRdy used as a latch enable for position with delay provide by the carry chain for the increment, noting that will always invert at least one bit. See the XST user guide for recognized sequential logic sensitive to the rising edge. - user1155120
Sorry about my code, i know it was not complete but i think it was enough so that you could understand my issue. Thanks a lot, i was able to fix it. The problem was that i was not checking any clock edge. I added that condition and now it works like a charm. - user3013172

1 Answers

1
votes

You are using sig_RxRdy as condition for incrementing. But we can not see how that signal behaves as it comes out of a module for which we have no code.

From the behavior you describe the o_rx_dv output (where sig_RxRdy comes from) is likely to be high for more then one of your clk cycles. As the UART input comes from an external source the time it is high may be variable which makes that you counter increment differs.

Solution is to detect a rising edge on sig_RxRdy by using a delayed version:

prev_sig_RxRdy <= sig_RxRdy; 
sig_RxRdy_rising <= sig_RxRdy and not prev_sig_RxRdy;

Then increment your counters on that signal. This only works if o_rx_dv is already synchronous to your clock.