jakubcabal / spi-fpga

SPI master and SPI slave for FPGA written in VHDL

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

A question about sclk edge

Seven-Zeng opened this issue · comments

Hi man,

I have to say that your code looks so comfortable.

I'm a rookie of FPGA designing and have some questions hope that you can help:

  1. would that be a problem to shift data on rising edge of CLK together with checking spi_clk_redge_en level? As the spi_clk_redge_en is derived from spi_clk_reg, which is latch on rising edge of CLK as well, which means the spi_clk_redge_en might alter on rising edge of CLK.
  2. I have viewed many implementations of SPI slave, some of them use synchronized clock to latch or shift data in/out just like yours, while others use the sclk directly, which one would be better? and why?
  3. CAN CS_n be used as RST directly?

Hi,

  1. The shift register (data_shreg) capture incoming data from master in CLK cycle, when a rising edge was detected (spi_clk_redge_en) on the SCLK signal. But I have a bug #5, SCLK should be synchronized (two FFs) to the CKL clock domain. Timing diagram of current implementation:
CLK              _|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_
SCLK (async)     ___________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾|______________
spi_clk_reg      _____________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|___________
spi_clk_redge_en ___________|‾|___________________________
data_shreg       D0...........|D1.........................
  1. Both implementations have advantages and disadvantages. For example my solution does not require a more complex cross domain crossing from SCLK to CLK (asynchronous FIFO) and all FFs are active on the rising edge of the same clock

  2. No, RST is typically a global FPGA reset. CS_N is used to select the SPI slave module. My SPI slave module allows to accept user data to be transmitted even when not active CS_N.

Hi,
The diagram illustrated you intention so clearly, while, forgive my silly, there still one point I haven't gotten:

the code is like:

data_shreg_p : process (CLK)
begin
    if (rising_edge(CLK)) then
        if (load_data_en = '1') then
            data_shreg <= DIN;
        elsif (spi_clk_redge_en = '1' and CS_N = '0') then
            data_shreg <= data_shreg(6 downto 0) & MOSI;
CLK              _|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_
SCLK (async)     ___________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾|______________
spi_clk_reg      _____________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|___________
spi_clk_redge_en ___________|‾|___________________________
data_shreg       D0..............|D1.........................
------------------------------^---------------------------

the bit is latched on the rising edge AND spi_clk_redge_en == '1', but spi_clk_redge_en is reset to '0' at exactly the same rising edge of the CLK, what if spi_clk_redge_en falls to zero before the bit shift condition is checked? Is that gonna be a risk?

Besides, when you say add another FF do you mean implementing it like this:

CLK              _|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_|‾|_
SCLK (async)     ___________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾|______________
spi_clk_reg1     _____________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|___________
spi_clk_reg2     _________________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|___________
spi_clk_redge_en _____________|‾‾‾|___________________________
data_shreg       D0...............|D1.........................

The described situation cannot occur. From sampling theorem: CLK clock must be more than twice as fast as SCLK. For reliable data transmission, I have a much stricter condition on my SPI master (SCLK_FREQ <= CLK_FREQ/10).

The problem may be when spi_clk_redge_en is set at the same time as rising edge of the CLK. This problem can cause metastability (bug #5) and can be solved by adding at least two FFs. Yes your diagram corresponds to an implementation with one FF added.

Got you!
Many thanks !