I have implemented a dummy SPI slave device within an FPGA (Basys 3). The master device is in an MCU.
I'm trying to connect the clock signal generated by the master (MCU) to the slave clock pin (a PMOD pin in the FPGA). However, it seems that Vivado doesn't allow to provide clock signal as an input, and it stops in the implementation step. Unless I comment out this PMOD assignment, in which case it can finish the impl. step.
The error I'm getting is:
[Place 30-574] Poor placement for routing between an IO pin and BUFG. If this sub optimal condition is acceptable for this design, you may use the CLOCK_DEDICATED_ROUTE constraint in the .xdc file to demote this message to a WARNING. However, the use of this override is highly discouraged. These examples can be used directly in the .xdc file to override this clock rule.
< set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets JA_IBUF[3]] >
JA_IBUF[3]_inst (IBUF.O) is locked to IOB_X1Y97
and JA_IBUF_BUFG[3]_inst (BUFG.I) is provisionally placed by clockplacer on BUFGCTRL_X0Y31
and it's caused because I'm using JA[3]
(Pmod pin) as an input clock signal for the SPI slave device.
I know there is a number of ways of fixing this, like generating a fast clock signal within the FPGA and pass the generated MCU clock signal through an edge detector, but do I really need to do this? (I have tried this but breaks my design)
I have read that there should be some pins that are valid for routing clock signals, however I haven't found which ones are in Basys 3.
Is there any way to provide a clock signal as an input to an FPGA?
I have tried to do what the error message says, that is, adding:
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets JA_IBUF[3]]
to the constraints file. This works, but the error message 'highly discourages' doing it. Is there any 'good' way of doing this?
Best Answer
Depending on the speed of your SPI clock, a typical solution to this is to use oversampling and filtering of the incoming SPI clock signal using a higher speed clock already available in the FPGA (e.g. fed in from dedicated clock pin).
The idea is that rather than using the SPI clock as a clock for your SPI shift register logic, you instead use a high speed clock (e.g. 50MHz) to drive everything. The SPI clock signal is fed first through a multi-flop synchroniser (e.g. 2 DFFs driven by the sample clock), then goes into an edge detector to see when it transitions from low-to-high or high-to-low. The edge detector output is then used as a clock enable for the shift register. You can also add a filter as part of the edge detection - e.g. only detect changes after three consecutive samples:
By doing this your SPI clock is no longer treated as a clock by the FPGA tools - it can instead be treated as a data line. In addition it means the rest of the logic the SPI slave connects to (e.g. memories, registers, status flags, etc.) can run on the existing high speed clock without the need for any clock domain crossing. It also means you can have a state machine that can act on both rising and falling edge of the SPI clock (e.g. read value of MOSI on rising edge, update MISO on falling edge) without needing multi-edge sensitivity (which most FPGAs can't do).