Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

Reading SPI data. The VHDL synchronize problem?

Hi, can anybody help me with this issue. I'm trying to read the SPI data from another device but it seems that I cannot make it synchronized. Briefly, I try to send a constant (16 bit), for instant and easy 1001101, but the signal sometimes is shifted one or two bit around (sometimes the output data is a range of 1001101, but after like 20ms, it's a range of 0011011, or 1100110, in other words, it's not stable).

That problem happens when I used this code:

process(SPI_CS)

begin

if rising_edge(SPI_CS) then

DATA_REG_O <= sdata_reg;

end if;

end process;

process(SPI_SCLK)

begin

if rising_edge(SPI_SCLK) then

sdata_reg <= sdata_reg(len_SPI-2 downto 0) & SPI_DIO;

end if;

end process;

I can't think of any problem with the above code :( the simulation is perfect!

Then I change to this code, which causes bad synchronization when the program start (as it may start in the middle of the 16-bit SPI clock). But the data is always stable (fixed at 11001100, or 1001101, in other words, I received the same signal although it's wrong, but it's always the same)

process(SPI_SCLK)

begin

if rising_edge(SPI_SCLK) then

if position_SPI = len_SPI-1 then

position_SPI <= 0;

DATA_REG_O <= sdata_reg;

sdata_reg <= (others => '0');

else

position_SPI <= position_SPI + 1;

sdata_reg <= sdata_reg(len_SPI-2 downto 0) & SPI_DIO;

end if;

end if;

end process;

Please let me know if you don't understand what I'm trying to say. My English is not very good.

Thanks

Tan

3 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Usually you wouldnt use the SPI_SCLK as a clock, you use it as another signal and synchronise it into your system clock domain (running many times faster). This way you avoid any timing issues. And using SPI_CS as a clock is a very bad idea.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    I think the best way is to synchronize everything that is running on the chip to one central clock, but assuming this SPI function does not have any interface to other VHDL modules, you can also assign a different clock to this "SPI section" of the FPGA. Just as a reminder - if you intend to use different clocks, you either need to ensure the chip has the capability of a second clock distribution network or the second clock can be routed by normal cell interconnects (which would at least lower the max. frequency).

    If the "SPI module" interfaces with the other logic on the chip (e.g. the "sdata_reg" is generated by other logic you need to ensure that sdata_reg cannot change (as being synchronized to another clock) than the SPI-related signals or you can get messed up readings.

    the issue with changing information is also most likely causing your troubles, as your code does not ensure any timing constraints between the SPI_CLK refernced part and the SPI_CS related one.

    Addtionally any glitch on the signal will trigger the code and that causes further problems...

    all of this "real life" stuff is not within your simulation as I assume the timing between SPI_CS and SPI_CLK is ideal like the signals do not have any glitches etc...

    As tricky already mentioned the best is to synchronize all signals like SPI_CS and SPI_CLK to System clock and run the code as a System clock depending process.. Defined a internal Signal like iSPI_CLK that is within the System clock process updated with SPI_CLK provides an Option ot detect rising and falling edges of the Signal by comparing SPI_CLK and iSPI_CLK...

    HTH
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you guys :)

    That really helps!

    My program's working now but seems like I cannot make it the way you told me to not use the SPI clock to shift the register. I tried but my programming skills cannot help with that. I'm still stuck with the timing issue. Or maybe the main clock is not enough. Or whatever happens with FPGA structure.

    MTM: I tried so simulate the SPI clock but I have to use the CS signal to synchronize it. Maybe because of that that I cannot generate it correctly. Then I think the problem is that the CS signal causing timing issue.

    My solution is then, use a higher clock speed as Tricky said to deal with it. And anything works like a charm :D

    process(SPI_SCLK) -- It still works with this small project

    begin

    if rising_edge(SPI_SCLK) then

    sdata_reg <= sdata_reg(len_SPI-2 downto 0) & SPI_DIO;

    end if;

    end process;

    process(RESET,CLOCK_50)

    begin

    if RESET = '1' then

    nSPIstate <= initial;

    elsif rising_edge(CLOCK_50) then

    nSPIstate <= SPIstate;

    if SPIstate = ready then

    DATA_REG_O <= not(sdata_reg(len_SPI-1)) & sdata_reg(len_SPI-2 downto 0);

    end if;

    end if;

    end process;

    process(SPIstate,SPI_CS)

    begin -- To detect the middle of the CS signal (not just rising or falling which causes timing issue)

    end process;