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?