- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dears, I'm making a SPI interface in FPGA to interface with the SPI interface of a processor. The details as below:
• SPI of processor will always act as master. Slave for FPGA. • SPI Clk: 25mhz • SPI working mode: SCK polarity=0; Phase=1; • SS Polarity: low effective • Data format: 16bit addr + 16bit data; MSB of addr indicates read(1)/write(0) operation I have finished VHDL code and test bench. (see attachment for source code, test bench and DO file for Modelsim ) RTL simulation has been done in Modelsim. In the simulation,system clock in FPGA was set to 100mhz. After simulation, no error found. Can I anounce that: this design can accept 25mhz SPI data if system clock is 100mhz? Or i ask this question in another way. If SPI clock remainis 25mhz, whaht is the minimum system clock required? What is the criteria?Link Copied
6 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you allow for SPI signal skew, asymmetrical SPI clock and arbitrary clock phase, the system clock frequency probably can't be much lower. You'll find out by adding these real world effects to your testbench.
Alternatively you can run the SPI interface from SCK and perform domain crossing data transfer, e.g. using registers with handshake or DCFIFO. That's my usual choice for SPI clock frequencies in the multi 10 MHz range.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear FvM, Thanks for your reply.
I'm very interested on domain crossing data transfer. Could you show me more details?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
One more question, is there any metastability problem in my design?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- One more question, is there any metastability problem in my design? --- Quote End --- Should be O.K. by double registering of SCK and SS. --- Quote Start --- Could you show me more details? --- Quote End --- Domain crossing data transfer is easy for write data, register the data in the SCK domain, transfer the update event to the sysclock domain, e.g. by a toggle synchronizer. The data can be expected to be stable and consistent when the update event arrives. Read data transfer is more difficult. A suitable method depends on the amount of data (number of different read addresses). A straightforward way is to have registers permanently updated by the sysclock, update is paused while synchronized SS is active. If you have too many data, it can be fetched after the address is decoded, possibly needing a few empty SPI clock cycles between address and data phase.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear FvM, Based on your comments, I have made some code and simulated. See the code below.
The working condition is completely the same as before except that the 7 bits after MSB of address word is used instead of the lower 8 bits.library work ;
use work.package_group.all ;
--------------------------------------------------------------------------------------------
-- ENTITY
--------------------------------------------------------------------------------------------
entity spi is
port
(
clk : in std_logic ;
ce : in std_logic ;
rst : in std_logic ;
-- spi port
SS : in std_logic ;
SCK : in std_logic ;
MOSI : in std_logic ;
MISO : inout std_logic ;
-- Data registers
rstack : in t_RegArray ;
wstack : out t_RegArray
) ;
end entity spi ;
--------------------------------------------------------------------------------------------
-- ARCHITECTURE
--------------------------------------------------------------------------------------------
architecture tran of spi is
signal rst_spi : std_logic;
signal cnt1 : std_logic_vector(4 downto 0);
signal data_shift : std_logic_vector(31 downto 0);
signal addr : std_logic_vector(6 downto 0);
signal w_r : std_logic;--write: 0; read: 1
signal data_out : std_logic_vector(15 downto 0);
--signal data_in : std_logic_vector(15 downto 0);
begin
rst_spi <= rst or SS; -- SS is low effective
-- bit counter
process(SCK,rst_spi)
begin
if rst_spi = '1' then
cnt1 <= "11111";
elsif rising_edge(SCK) then
cnt1 <= cnt1 + 1;
end if;
end process;
--shift in data on MOSI
process(SCK,rst_spi)
begin
if rst_spi = '1' then
data_shift <= (others=>'0');
elsif falling_edge(SCK) then
data_shift(31 - conv_integer(cnt1)) <= MOSI;
end if;
end process;
--identify it's write or read
process(SCK,rst_spi)
begin
if rst_spi = '1' then
w_r <= '0';
elsif rising_edge(SCK) then
if cnt1 = "00001" then
w_r <= data_shift(31);
end if;
end if;
end process;
--get address
process(SCK,rst_spi)
begin
if rst_spi = '1' then
addr <= (others=>'0');
elsif rising_edge(SCK) then
if cnt1 = "00111" then
addr <= data_shift(30 downto 24);
end if;
end if;
end process;
--write data into write-only register array
process(SCK,rst_spi)
begin
if rst = '1' then
wstack (85) <= X"8888" ;
wstack (90) <= X"9999" ;
elsif falling_edge(SCK) then
if cnt1 = "11111" and w_r = '0' then
wstack(conv_integer(addr)) <= data_shift(15 downto 1) & MOSI;
end if;
end if;
end process;
--load data from read-only register array
process(SCK,rst_spi)
begin
if rising_edge(SCK) then
if cnt1 = "01000" and w_r = '1' then
data_out <= rstack(conv_integer(addr));
end if;
end if;
end process;
process(cnt1,data_out)
begin
case cnt1 is
when "10000" =>
MISO <= data_out(15);
when "10001" =>
MISO <= data_out(14);
when "10010" =>
MISO <= data_out(13);
when "10011" =>
MISO <= data_out(12);
when "10100" =>
MISO <= data_out(11);
when "10101" =>
MISO <= data_out(10);
when "10110" =>
MISO <= data_out(9);
when "10111" =>
MISO <= data_out(8);
when "11000" =>
MISO <= data_out(7);
when "11001" =>
MISO <= data_out(6);
when "11010" =>
MISO <= data_out(5);
when "11011" =>
MISO <= data_out(4);
when "11100" =>
MISO <= data_out(3);
when "11101" =>
MISO <= data_out(2);
when "11110" =>
MISO <= data_out(1);
when "11111" =>
MISO <= data_out(0);
when others =>
MISO <= '0';
end case;
end process;
end architecture tran ;
Can you give me some comments? Is there anything not good and can be improved? Compare to the previous solution i made, i feel this new solution you suggested is much better. The 2 advantages are: 1. The spi clock is completely independent of system clock. That means SPI clock can go very high. Maybe the limit for the speed is from the FPGA device itself. 2. Chance to have metastability problem is zero because data is synchronized with SPI clock. Are the statements above correct?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
can anybody help?

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page