1
votes

I am trying to realize a communication between my FPGA and the HPS on the Altera DE10nano development board. To edit the vhdl i use the Quartus Prime software.

While the communication is working in general (as in i can get some data form the fpga to the hps), i have the issue of creating a proper state-machine which can add a new value to the FIFO with a different clock (in this case 12500Hz) than the base clock of 50MHz. The other clocks (100kHz and 12500Hz) are generated in a different vhdl-module.

The general idea is to write one sample every cycle of the 12,5kHz-Clock. Each cycle i've got a counter that increases as well as some data from a upstream FFT.

I'm using a simple C-Code in the HPS to read my fifo and save the read value into a .csv-file.

Now, the problem: When im using my board to load my design, I'm not getting the proper sample number. I get random values (from "counter_sample") in the .csv-file, while the simulation (with ModelSim) of the state-machine is doing what i want it to do. Also, the design does work good when i use the 100kHz-Clock to trigger the process, but i've been told that's bad practice, since the clocks are not generated by a pll. This also leads me to thinking it is not an issue with the used C-Code.

The random values i get are not successively, but rather 200-300 counter-values apart of each other.

I'm not a veteran in programming vhdl (as you can probably tell) but will copy my state-machine below. I'm happy to hear your input and will provide further information if needed.

The fft_sop and fft_eop signals are start- and endofpacket signal from the upstream fft.

Thanks!

process(Clk_50MHz, in_reset)
begin

    if (in_reset = '1') then 
        f2h_state <= f2h_idle;
        counter_sample <=0;
        counter_wait <=0;
        out_fifo_write <='0';
        out_fifo_writedata <= (others => '0');
        fft_sop_old <= '0';
        fft_eop_old <= '0';
        Clk_12500Hz_alt<='0';
        
    elsif(rising_edge(Clk_50MHz)) then
        fft_sop_old <= in_fft_sop;
        fft_eop_old <= in_fft_eop;
        Clk_12500Hz_old <= Clk_12500Hz;
    
        case f2h_state is

            when f2h_idle =>
                if ((Clk_12500Hz = '1') and (Clk_12500Hz_old = '0')) then
                    counter_wait <= counter_wait + 1;
                    if counter_wait = 8190 then
                        f2h_state <= f2h_wait_start;
                    else 
                        f2h_state <= f2h_idle;
                    end if;
                else
                f2h_state <= f2h_idle;
                end if;
            
            when    f2h_wait_start =>
            
                out_fifo_write <= '0';

                if ((in_fft_sop = '1') and (fft_sop_old = '0')) then
                    out_fifo_write <= '1';
                    out_fifo_writedata(10 downto 0) <= conv_std_logic_vector(1, 11);
                    counter_sample <= 2;
                    out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
                    out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
                    out_fifo_writedata(63 downto 35) <= (others => '0');
                    f2h_state <= f2h_writesample;
                end if;
            
            when    f2h_writesample =>
                
                if ((Clk_12500Hz = '1') and (Clk_12500Hz_old = '0')) then
                    out_fifo_write <= '1';
                    counter_sample <= counter_sample + 1;
                    out_fifo_writedata(10 downto 0) <= conv_std_logic_vector(counter_sample, 11);
                    out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
                    out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
                    out_fifo_writedata(63 downto 35) <= (others => '0');
                    
                    if in_fft_eop = '1' then
                         f2h_state <= f2h_wait_start;
                    end if;

                    f2h_state <= f2h_writesample;
                else
                    out_fifo_write <= '0';
                end if;

                
        end case;
    end if;
end process;
1

1 Answers

0
votes

All three states are rightly synchronised to the system clock clk_50MHz, but the first and third states, F2H_IDLE and F2H_WRITESAMPLE, are looking for the rising edge of clk_12500Hz while your second state F2H_WAIT_START isn't. Instead, it's only looking for the rising edge of in_fft_sop. This means that the first and third states are synchronised to the rising edge of the clk_12500Hz signal, but the second state is not synchronised to the clk_12500Hz signal (only the in_fft_sop signal). Is this what you intended? This could explain why you are getting random values on counter_sample.

I've restructured the logic so that all the states are synchronised to both the system clock clk_50MHz and the clk_12500Hz signal, which is what I understood from your question, and I've assumed that new data is simply clocked into the FIFO when out_fifo_write is high.

I've also added three edge detectors to make the code more readable, and changed the level detector in the third state to a rising edge detector.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity FPGA2HPS is
    port
    (
        clk_50MHz: in std_logic;
        clk_12500Hz: in std_logic;
        in_reset: in std_logic;
        in_fft_sop: in std_logic;
        in_fft_eop: in std_logic;
        in_fft_real: in std_logic_vector(11 downto 0);
        in_fft_imag: in std_logic_vector(11 downto 0);
        out_fifo_write: out std_logic;
        out_fifo_writedata: out std_logic_vector(63 downto 0)
    );
end entity;

architecture V1 of FPGA2HPS is

    type F2H_STATES is (F2H_IDLE, F2H_WAIT_START, F2H_WRITESAMPLE);
    signal f2h_state: F2H_STATES;
    signal rising_edge_clk_12500Hz: std_logic;
    signal rising_edge_in_fft_sop: std_logic;
    signal rising_edge_in_fft_eop: std_logic;
    signal clk_12500Hz_old: std_logic;
    signal fft_sop_old: std_logic;
    signal fft_eop_old: std_logic;
    signal clk_12500Hz_alt: std_logic;
    signal counter_sample: integer;
    signal counter_wait: integer;

begin

    --
    -- Rising edge detectors
    --
    rising_edge_clk_12500Hz <= clk_12500Hz and not clk_12500Hz_old;
    rising_edge_in_fft_sop <= in_fft_sop and not fft_sop_old;
    rising_edge_in_fft_eop <= in_fft_eop and not fft_eop_old;

    process(clk_50MHz, in_reset)
    begin

        if in_reset then

            f2h_state <= F2H_IDLE;
            counter_sample <= 0;
            counter_wait <= 0;
            out_fifo_write <= '0';
            out_fifo_writedata <= (others => '0');
            fft_sop_old <= '0';
            fft_eop_old <= '0';
            clk_12500Hz_alt <= '0';

        elsif rising_edge(clk_50MHz) then

            -- Ensure all the state machine logic works on the rising edge of the clk_12500Hz signal while also synchronised to the clk_50MHz clock.
            if rising_edge_clk_12500Hz then

                fft_sop_old <= in_fft_sop;
                fft_eop_old <= in_fft_eop;
                clk_12500Hz_old <= clk_12500Hz;

                case f2h_state is

                    when F2H_IDLE =>

                        f2h_state <= F2H_IDLE;

                        counter_wait <= counter_wait + 1;
                        if counter_wait = 8190 then
                            f2h_state <= F2H_WAIT_START;
                        end if;

                    when F2H_WAIT_START =>

                        f2h_state <= F2H_WAIT_START;

                        out_fifo_write <= '0';

                        if rising_edge_in_fft_sop then
                            out_fifo_write <= '1';
                            out_fifo_writedata(10 downto 0) <= std_logic_vector(to_unsigned(1, 11));  -- CHANGED
                            counter_sample <= 2;
                            out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
                            out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
                            out_fifo_writedata(63 downto 35) <= (others => '0');
                            f2h_state <= F2H_WRITESAMPLE;
                        end if;

                    when F2H_WRITESAMPLE =>

                        f2h_state <= F2H_WRITESAMPLE;

                        counter_sample <= counter_sample + 1;
                        out_fifo_writedata(10 downto 0) <= std_logic_vector(to_unsigned(counter_sample, 11));  -- CHANGED
                        out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
                        out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
                        out_fifo_writedata(63 downto 35) <= (others => '0');

                        if rising_edge_in_fft_eop then  -- CHANGED: Should this be on the rising edge of in_fft_eop?
                            out_fifo_write <= '0';      -- ADDED: End of write mode?
                            f2h_state <= F2H_WAIT_START;
                        end if;

                end case;
            end if;
        end if;
    end process;

end architecture;

I hope that helps, but without the timing diagrams of the FFT and FIFO nor a test bench, I haven't been able to simulate it.