3

I am trying to interface a Virtex 4 (ML401) FPGA and a TIVA C series board using 4 wire SPI (cs, sclk, miso, mosi). The tiva acts as a master and the FPGA as a slave. I am able to receive the SPI data from the master and display the data on the LEDS present on the FPGA (Method 2). However, I need to find the rising and falling transitions of the chip select signal (required for my application for synchronization purposes). I have tried many methods with FIFO's (that work well in simulation) but just don't work on the FPGA, as shown:

NOTE: spi_cs is the asynchronous SPI chip select signal input to the FPGA from the TIVA board, while other signals (spi_cs_s, spi_cs_ss, spi_cs_h2l, spi_cs_l2h, etc) are created internally on the FPGA.

Method 1)

                prc_sync_cs: process(clk)
                begin
                    if (clk'event and clk = '1') then
                        spi_cs_s  <= spi_cs;
                end if; 
                end process prc_sync_cs;

                spi_cs_l2h <= not (spi_cs_s) and spi_cs;
                spi_cs_h2l <= not (spi_cs) and spi_cs_s;

Method 2)

                process (spi_cs)
                begin
                    if (spi_cs = '0' or spi_cs = '1')  then
                        -- update ledss with new MOSI on rising edge of CS
                        spi_cs_ss <= spi_cs_s;
                        spi_cs_s  <= spi_cs;
                        --leds <= spi_wdata; --leds display the received data on the FPGA (saved into spi_wdata in another process)
                                            -- THIS WORKS ON THE FGPA BUT the edge detection doesn't. Why?
                    end if;
                end process;

                spi_cs_h2l <= '1' when (spi_cs_s = '0' and spi_cs_ss = '1') else '0';
                spi_cs_l2h <= '1' when (spi_cs_s = '1' and spi_cs_ss = '0') else '0';
                leds <= "000000" & spi_cs_h2l & spi_cs_l2h; -- ALL leds are off always (i,e both transitions are '0' always).

Method 3)

                prc_sync_cs: process(clk)
                begin
                    if (clk'event and clk = '1') then
                        spi_cs_ss <= spi_cs_s;
                        spi_cs_s  <= spi_cs;
                    end if; 
                end process prc_sync_cs;

                prc_edge_cs: process(clk)
                begin
                    if (clk'event and clk = '1') then
                        spi_cs_ss_del <= spi_cs_ss;
                    end if; 
                end process prc_edge_cs;

                spi_cs_h2l <= '1' when (spi_cs_ss_del = '1' and spi_cs_ss = '0') else '0';
                spi_cs_l2h <= '1' when (spi_cs_ss_del = '0' and spi_cs_ss = '1') else '0';

ALL the methods work perfectly in simulation but not when downloaded on the FPGA. I wrote a process to monitor the transitions more closely (to monitor metastable values, if any):

            led_test: process(spi_cs_h2l, spi_cs_l2h)
            begin
                if spi_cs_h2l = '1' or spi_cs_l2h = '1' then
                                leds <= "111100" & spi_cs_h2l & spi_cs_l2h;
                elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or
                        spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then
                                leds <= "00001111";         
                else
                    leds <= "10101010";
                end if;
            end process led_test;

The leds are always "10101010" i.e is the else case where both spi_cs_h2l and spi_cs_l2h are = '0'. What am I missing ?? Any pointers would be very helpful as I am stuck with this issue since many days.

UPDATE

Using method 3 of clock domain crossing (as suggested by Jeff), and by initializing all the leds and signals to zero, the process to light up the leds is changed as follows:

            led_test: process(spi_cs_h2l)
            begin
                if rising_edge(clk) then
                    if spi_cs_h2l = '1' then
                                leds <= "11110011";
                    end if;
                end if; 
            end process led_test;

At least one high to low transition of the chip select pin is expected to light up the leds. The SPI chip select pin is receiving a '1' always and when FPGA is started/reset, the leds light up. How is this possible? How can this false high to low transition occur ?

JagPK
  • 148
  • 1
  • 9
  • is `clk` in your code synchronous to `spi_cs`, or is it just other clock in the FPGA? – scary_jeff Jul 14 '15 at 13:29
  • clk is the global clock of the FPGA. spi_cs is an asynchronous input from the tiva board to the fpga. I need to synchronize the spi_cs to the signal clk for which i need to detect the transition edges. (I edited my post explaining the signals) – JagPK Jul 14 '15 at 13:31
  • What about using xilinx chipscope or a hardware logic analyzer to see what's going on? – mbschenkel Jul 15 '15 at 05:50
  • @mbschenkel - I do not have a jtag debug probe for that. I am using a flash card reader to download the *.ace file to the FPGA. – JagPK Jul 15 '15 at 08:04

1 Answers1

4

Method 1

This does not perform any sort of clock domain crossing on the spi_cs signal, and so is not a reliable circuit.

Method 2

The line if (spi_cs = '0' or spi_cs = '1') then is always true in the synthesised design, I wouldn't expect you to be able to detect an edge using this

Method 3

This does provide clock domain crossing for spi_cs, and in general looks pretty good. The reason you see "10101010" on your LEDs, is because they only show something different to this for one clk period at a time, at the start or end of an SPI transaction. This is probably much faster than you can see with the naked eye on the LEDs.

Additionally, the line elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then will not translate into any real hardware in the FPGA, because the real hardware does not have a way to check for 'U', 'Z', etc.

Method 3 update

It sounds like spi_cs is actually active low. You need to make sure that the initial values for your signals like spi_cs_s and spi_cs_ss are all correct. In this case, I think you should initialise them all to '1', as this seems to be the normal state for spi_cs. So your signal declarations would look like signal spi_cs_s : std_logic := '1'. You should be able to see this behaving properly in simulation.

Community
  • 1
  • 1
scary_jeff
  • 4,314
  • 13
  • 27
  • Hi jeff .. With method 3, all the leds have been initialized to zeros and in the led_test process, I just kept one IF statement stating that if spi_cs_h2l = '1' then leds <= "11110011". So now at least one high to low transition must change the value of leds from all zeros to "11110011" and keep it that way right ?? But the surprising thing that I am observing is that even without any SPI data being sent, (CS is pulled up to '1' always), leds show "11110011" (even after FPGA reset/restart). What could be the reason for this false transition? (all signals have been initialized to zeros) – JagPK Jul 14 '15 at 14:06
  • @JagPK The CS synchronizing flip-flops are initialized with '0' when the FPGA is loaded. Since CS is '1', it will always detect a rising edge and light your leds. You can try initializing your cs regs with `signal spi_cs_ss : std_logic := '1';` – Jonathan Drolet Jul 14 '15 at 14:12
  • @JonathanDrolet - My if condition specifies that a falling edge needs to be detected (spi_cs_h2l ) for leds to change .. So even if a rising edge was detected, it should not change the LEDs .. – JagPK Jul 14 '15 at 14:15
  • @JagPK You seem to have modified that function a lot compared to your original post. Can you show us the new code for that process? – Jonathan Drolet Jul 14 '15 at 14:19
  • @JonathanDrolet - I have mentioned it in my first comment. Restating: With method 3, all the leds have been initialized to zeros and in the 'led_test' process mentioned in my post, I just kept one IF statement stating that `if spi_cs_h2l = '1' then leds <= "11110011" end if;`. So now at least one high to low transition must change the value of leds from all zeros to "11110011". – JagPK Jul 14 '15 at 14:26
  • @JagPK is it embedded in a clock rising_edge clock statement? If it's not, it's likely the synthesis tool will ignore the initial value since your not describing a memory element but a net instead. It's also likely that the assignation to the net would be considered constant. – Jonathan Drolet Jul 14 '15 at 14:33
  • @JonathanDrolet - it was not embedded in a clock rising_edge clock statement. But i modified it and enclosed it in a clk rising edge statement to test it again and the behavior persists :( LEDs still light up. – JagPK Jul 14 '15 at 14:43
  • you should probably update the question with the code you are currently using – scary_jeff Jul 14 '15 at 15:46
  • Assuming you have all your signals properly initialised, I can't see a reason for this not working. If it's looking OK in simulation, then I think the next most likely issue is that your simulation isn't doing the same thing as the real circuit. Perhaps you could probe the real circuit and make 100% sure that the simulation does the exact same thing. – scary_jeff Jul 20 '15 at 08:59
  • Solved. The clock constraints were not properly mentioned causing erratic behaviour. Once I got that right, everything fell into place. – JagPK Oct 15 '15 at 09:43