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 :
- Address and data are received and sent by the state machine operating in the SPI clock domain.
- Once a command has been fully received, the FSM sends a command request to the controller in the main clock domain.
- The controller executes the command and returns data if necessary.
- 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 :