Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17254 Discussions

Reading SPI data. The VHDL synchronize problem?

Altera_Forum
Honored Contributor II
3,515 Views

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
0 Kudos
3 Replies
Altera_Forum
Honored Contributor II
2,664 Views

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.

0 Kudos
Altera_Forum
Honored Contributor II
2,664 Views

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
0 Kudos
Altera_Forum
Honored Contributor II
2,664 Views

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;
0 Kudos
Reply