Library of reusable VHDL components
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
8.0 KiB

  1. -- Copyright (c) 2014 - 2022 by Torsten Meissner
  2. --
  3. -- Licensed under the Apache License, Version 2.0 (the "License");
  4. -- you may not use this file except in compliance with the License.
  5. -- You may obtain a copy of the License at
  6. --
  7. -- https://www.apache.org/licenses/LICENSE-2.0
  8. --
  9. -- Unless required by applicable law or agreed to in writing, software
  10. -- distributed under the License is distributed on an "AS IS" BASIS,
  11. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. -- See the License for the specific language governing permissions and
  13. -- limitations under the License.
  14. library ieee;
  15. use ieee.std_logic_1164.all;
  16. use ieee.numeric_std.all;
  17. entity SpiMasterE is
  18. generic (
  19. G_DATA_WIDTH : positive := 8; --* data bus width
  20. G_DATA_DIR : natural range 0 to 1 := 0; --* start from lsb/msb 0/1
  21. G_SPI_CPOL : natural range 0 to 1 := 0; --* SPI clock polarity
  22. G_SPI_CPHA : natural range 0 to 1 := 0; --* SPI clock phase
  23. G_SCLK_DIVIDER : positive range 6 to positive'high := 10 --* SCLK divider related to system clock
  24. );
  25. port (
  26. --+ system if
  27. Reset_n_i : in std_logic;
  28. Clk_i : in std_logic;
  29. --+ SPI slave if
  30. SpiSclk_o : out std_logic;
  31. SpiSte_o : out std_logic;
  32. SpiMosi_o : out std_logic;
  33. SpiMiso_i : in std_logic;
  34. --+ local VAI if
  35. Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
  36. DataValid_i : in std_logic;
  37. DataAccept_o : out std_logic;
  38. Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
  39. DataValid_o : out std_logic;
  40. DataAccept_i : in std_logic
  41. );
  42. end entity SpiMasterE;
  43. architecture rtl of SpiMasterE is
  44. type t_spi_state is (IDLE, WRITE, READ, CYCLE, STORE, SET_STE);
  45. signal s_spi_state : t_spi_state;
  46. signal s_send_register : std_logic_vector(G_DATA_WIDTH-1 downto 0);
  47. signal s_recv_register : std_logic_vector(G_DATA_WIDTH-1 downto 0);
  48. signal s_miso_d : std_logic_vector(1 downto 0);
  49. signal s_mosi : std_logic;
  50. signal s_sclk : std_logic;
  51. signal s_ste : std_logic;
  52. signal s_data_valid : std_logic;
  53. signal s_data_accept : std_logic;
  54. signal s_transfer_valid : boolean;
  55. signal s_sclk_rising : boolean;
  56. signal s_sclk_falling : boolean;
  57. signal s_read_edge : boolean;
  58. signal s_write_edge : boolean;
  59. alias a_miso : std_logic is s_miso_d(s_miso_d'left);
  60. constant C_BIT_COUNTER_START : natural := (G_DATA_WIDTH-1) * G_DATA_DIR;
  61. constant C_BIT_COUNTER_END : natural := (G_DATA_WIDTH-1) * to_integer(not(to_unsigned(G_DATA_DIR, 1)));
  62. begin
  63. --* Sync asynchronous SPI inputs with 2 stage FF line
  64. SpiSyncP : process (Reset_n_i, Clk_i) is
  65. begin
  66. if (Reset_n_i = '0') then
  67. s_miso_d <= (others => '0');
  68. elsif rising_edge(Clk_i) then
  69. s_miso_d <= s_miso_d(0) & SpiMiso_i;
  70. end if;
  71. end process SpiSyncP;
  72. --* Save local data input when new data is provided and
  73. --* we're not inside a running SPI transmission
  74. SendRegisterP : process (Reset_n_i, Clk_i) is
  75. begin
  76. if (Reset_n_i = '0') then
  77. s_send_register <= (others => '0');
  78. s_data_accept <= '0';
  79. elsif rising_edge(Clk_i) then
  80. s_data_accept <= '0';
  81. if (DataValid_i = '1' and s_spi_state = IDLE) then
  82. s_send_register <= Data_i;
  83. s_data_accept <= '1';
  84. end if;
  85. end if;
  86. end process SendRegisterP;
  87. --* Spi master control FSM
  88. SpiControlP : process (Reset_n_i, Clk_i) is
  89. variable v_bit_counter : natural range 0 to G_DATA_WIDTH-1;
  90. variable v_sclk_counter : natural range 0 to G_SCLK_DIVIDER-1;
  91. begin
  92. if (Reset_n_i = '0') then
  93. s_recv_register <= (others => '0');
  94. v_bit_counter := C_BIT_COUNTER_START;
  95. v_sclk_counter := G_SCLK_DIVIDER-1;
  96. s_transfer_valid <= false;
  97. s_sclk <= std_logic'val(G_SPI_CPOL+2);
  98. s_mosi <= '1';
  99. s_spi_state <= IDLE;
  100. elsif rising_edge(Clk_i) then
  101. case s_spi_state is
  102. when IDLE =>
  103. s_sclk <= std_logic'val(G_SPI_CPOL+2);
  104. s_mosi <= '1';
  105. s_recv_register <= (others => '0');
  106. v_bit_counter := C_BIT_COUNTER_START;
  107. v_sclk_counter := G_SCLK_DIVIDER/2-1;
  108. s_transfer_valid <= false;
  109. if(DataValid_i = '1' and s_data_accept = '1') then
  110. s_spi_state <= WRITE;
  111. end if;
  112. when WRITE =>
  113. if (G_SPI_CPHA = 0 and v_bit_counter = C_BIT_COUNTER_START) then
  114. s_mosi <= s_send_register(v_bit_counter);
  115. s_spi_state <= READ;
  116. else
  117. if (v_sclk_counter = 0) then
  118. v_sclk_counter := G_SCLK_DIVIDER/2-1;
  119. s_sclk <= not(s_sclk);
  120. s_mosi <= s_send_register(v_bit_counter);
  121. s_spi_state <= READ;
  122. else
  123. v_sclk_counter := v_sclk_counter - 1;
  124. end if;
  125. end if;
  126. when READ =>
  127. if (v_sclk_counter = 0) then
  128. s_sclk <= not(s_sclk);
  129. s_recv_register(v_bit_counter) <= a_miso;
  130. v_sclk_counter := G_SCLK_DIVIDER/2-1;
  131. if (v_bit_counter = C_BIT_COUNTER_END) then
  132. if (G_SPI_CPHA = 0) then
  133. s_spi_state <= CYCLE;
  134. else
  135. s_spi_state <= STORE;
  136. end if;
  137. else
  138. if (G_DATA_DIR = 0) then
  139. v_bit_counter := v_bit_counter + 1;
  140. else
  141. v_bit_counter := v_bit_counter - 1;
  142. end if;
  143. s_spi_state <= WRITE;
  144. end if;
  145. else
  146. v_sclk_counter := v_sclk_counter - 1;
  147. end if;
  148. when CYCLE =>
  149. if (v_sclk_counter = 0) then
  150. s_sclk <= not(s_sclk);
  151. v_sclk_counter := G_SCLK_DIVIDER/2-1;
  152. s_spi_state <= STORE;
  153. else
  154. v_sclk_counter := v_sclk_counter - 1;
  155. end if;
  156. when STORE =>
  157. if (v_sclk_counter = 0) then
  158. s_transfer_valid <= true;
  159. v_sclk_counter := G_SCLK_DIVIDER/2-1;
  160. s_spi_state <= SET_STE;
  161. else
  162. v_sclk_counter := v_sclk_counter - 1;
  163. end if;
  164. when SET_STE =>
  165. s_transfer_valid <= false;
  166. if (v_sclk_counter = 0) then
  167. s_spi_state <= IDLE;
  168. else
  169. v_sclk_counter := v_sclk_counter - 1;
  170. end if;
  171. when others =>
  172. s_spi_state <= IDLE;
  173. end case;
  174. end if;
  175. end process SpiControlP;
  176. --* Provide received SPI data to local interface
  177. --* Output data is overwritten if it isn't fetched
  178. --* until next finished SPI transmission
  179. RecvRegisterP : process (Reset_n_i, Clk_i) is
  180. begin
  181. if (Reset_n_i = '0') then
  182. Data_o <= (others => '0');
  183. s_data_valid <= '0';
  184. elsif rising_edge(Clk_i) then
  185. if (s_transfer_valid) then
  186. Data_o <= s_recv_register;
  187. s_data_valid <= '1';
  188. end if;
  189. if (DataAccept_i = '1' and s_data_valid = '1') then
  190. s_data_valid <= '0';
  191. end if;
  192. end if;
  193. end process RecvRegisterP;
  194. --+ internal signals
  195. s_ste <= '1' when s_spi_state = IDLE or s_spi_state = SET_STE else '0';
  196. --+ Output port connections
  197. DataValid_o <= s_data_valid;
  198. DataAccept_o <= s_data_accept;
  199. SpiSte_o <= s_ste;
  200. SpiSclk_o <= s_sclk;
  201. SpiMosi_o <= s_mosi when s_ste = '0' else '1';
  202. assert G_SCLK_DIVIDER rem 2 = 0
  203. report "WARNING: " & SpiMasterE'instance_name & LF & "G_SCLK_DIVIDER " & integer'image(G_SCLK_DIVIDER) &
  204. " rounded down to next even value " & integer'image(G_SCLK_DIVIDER-1)
  205. severity warning;
  206. -- psl default clock is rising_edge(Clk_i);
  207. --
  208. -- psl assert always (s_spi_state = IDLE or s_spi_state = WRITE or s_spi_state = READ or
  209. -- s_spi_state = CYCLE or s_spi_state = SET_STE or s_spi_state = STORE);
  210. -- psl assert always (s_data_valid and DataAccept_i) -> next not(s_data_valid);
  211. end architecture rtl;