0
\$\begingroup\$

I am (re)designing an SPI slave module in VHDL for an ASIC. The SPI domain is faster than the main clock domain (~10MHz and ~1MHz), so the SPI state machine operates in the SPI domain. The previous version had some issues with clock domain crossing because it used only single stage flip-flop synchronisers (to reduce the area). I'm trying to solve this issue with a different approach.

The SPI module operates as such :

  1. Address and data are received and sent by the state machine operating in the SPI clock domain.
  2. Once a command has been fully received, the FSM sends a command request to the controller in the main clock domain.
  3. The controller executes the command and returns data if necessary.
  4. The controller acknowledges the command.

I am trying to synchronise the data between the two clock domains, but using a FIFO would use way too much area, and simples 2DFF would not ensure data coherency. I think I have found a solution, but I am not certain if it is really stable or not.

Because of how this module works, data from the SPI domain never changes when the controller is processing a request (new SPI commands are rejected until the last one has been processed). My idea is to use a kind of handshake mechanism. Only the command start request would be synchronised using a pulse synchoniser, which would set the request to high and start the controller. Data would be directly connected to the controller without any synchroniser in-between, but would be guarenteed to be stable once the start signal has been issued by disabling the SPI FSM. Because the pulse synchoniser introduces a delay, we know metatsabilies has been resolved once the data is being used by the controller.

In the other direction, it is a bit trickier because we don't have enough clock cycles before needing the data. My idea is to use a latch driven by the chip select to prevent changes during a transaction. Because the previous design already required a small delay before enabling the SPI clock, using a latch would ensure any metastabilies have been resolved and no changes can occur. If the Ready signal is low, the SPI domain doesn't use any data from the controller and simply answer with an SPI busy packet to the microcontroller, meaning data from the controller won't be sampled and there are no risks of metastabilities.

Would it work? Are there any subtleties I have missed?

I have included a principle diagram of the synchoniser system :

Principle diagram

\$\endgroup\$
9
  • \$\begingroup\$ frame challenge : why is the main domain so slow? \$\endgroup\$
    – user16324
    Commented Nov 18, 2022 at 17:02
  • 1
    \$\begingroup\$ Although the domains are different speeds, are they synchronous? Is the 1M domain clocked from the 10M domain? If so, you can use this to avoid metastability. You really need to draw us a timing diagram. If you were asking a circuit question, we would need a schematic. For this sort of question, we need the timing diagram. And maybe, in drawing it, you might find the answer to your question. Metastability has attracted a lot of attempts at neat solutions, and none work. The only solutions have a complexity and wait time requirement equivalent or greater than doing it properly. \$\endgroup\$
    – Neil_UK
    Commented Nov 18, 2022 at 17:06
  • \$\begingroup\$ SPI domain is 10 times slower than main domain. That's weird. Don't you have data losses then all the time? Because serial data is continuous on SDI reception for example and cannot be 'stalled', and you don't have buffers. One thumb rule I follow is the core logic works 4x times faster than its SPI interface. \$\endgroup\$
    – Mitu Raj
    Commented Nov 18, 2022 at 20:01
  • \$\begingroup\$ Your description for the command (SPI to controller) sounds fine. But I'm not following why the other direction is any "trickier" -- it can use the exact same principle. The key concept is that the SPI slave can't change the command value between when it sends the command request and when it gets the command acknowledge back. Similarly, the controller cannot change its response value between when it sends the acknowledge and when it gets the next command request. In other words, the protocol can be completely symmetical, despite the large difference in clock speeds. \$\endgroup\$
    – Dave Tweed
    Commented Nov 19, 2022 at 2:20
  • \$\begingroup\$ One other point. You said: "Because the pulse synchroniser introduces a delay, we know metastabilities have been resolved once the data is being used by the controller." But there are no metastabilities on this data, since it is clocked only in the source domain. And it is guaranteed not to be changing at the time it is sampled in the destination domain, so there's no metastability generated there, either. \$\endgroup\$
    – Dave Tweed
    Commented Nov 20, 2022 at 2:23

1 Answer 1

0
\$\begingroup\$

The best solution to the problem was to introduce dummy bits at the beginning of SPI frames and make the design symetrical, as suggested in the comments. The design looks like that now :

Sync mechanism

It works well and simulations show no problem.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.