spimaster.vhd 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. --+-----------------------------------+-------------------------------------+--
  2. --| ___ ___ | (c) 2013-2014 William R Sowerbutts |--
  3. --| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |--
  4. --| / __|/ _ \ / __|_ / _ \| | | | | |--
  5. --| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |--
  6. --| |___/\___/ \___/___\___/ \___/ | |--
  7. --| | http://sowerbutts.com/ |--
  8. --+-----------------------------------+-------------------------------------+--
  9. --| A rudimentary SPI master peripheral |--
  10. --+-------------------------------------------------------------------------+--
  11. library IEEE;
  12. use IEEE.STD_LOGIC_1164.ALL;
  13. use IEEE.NUMERIC_STD.ALL;
  14. entity spimaster is
  15. port ( clk : in std_logic;
  16. reset : in std_logic;
  17. cpu_address : in std_logic_vector(2 downto 0);
  18. cpu_wait : out std_logic;
  19. data_in : in std_logic_vector(7 downto 0);
  20. data_out : out std_logic_vector(7 downto 0);
  21. enable : in std_logic;
  22. req_read : in std_logic;
  23. req_write : in std_logic;
  24. slave_cs : out std_logic;
  25. slave_clk : out std_logic;
  26. slave_mosi : out std_logic;
  27. slave_miso : in std_logic
  28. );
  29. end spimaster;
  30. -- registers:
  31. -- base+0 -- chip select control; bit 0 is slave_cs
  32. -- base+1 -- status register; bit 0 indicates "transmitter busy"
  33. -- base+2 -- transmitter: write a byte here, starts SPI bus transaction
  34. -- base+3 -- receiver: last byte received (updated on each transation)
  35. -- base+4 -- clock divider: clk counts from 0 to whatever is in this register before proceeding
  36. --
  37. -- Note that if an SPI transfer is underway already the CPU will be
  38. -- forced to wait until it completes before any register can be
  39. -- read or written. This is very convenient as it means you can
  40. -- just read or write bytes without checking the status register.
  41. architecture Behavioral of spimaster is
  42. -- start up in idle state
  43. signal slave_cs_register : std_logic := '1';
  44. signal slave_clk_register : std_logic := '1';
  45. signal slave_mosi_register: std_logic := '0';
  46. signal data_out_sr : std_logic_vector(7 downto 0) := (others => '0'); -- shifted left ie MSB <- LSB
  47. signal data_in_sr : std_logic_vector(7 downto 0) := (others => '0'); -- shifted left ie MSB <- LSB
  48. signal busy_sr : std_logic_vector(7 downto 0) := (others => '0'); -- shifted left ie MSB <- LSB
  49. signal clk_divide_target : unsigned(7 downto 0) := (others => '0');
  50. signal clk_divide_value : unsigned(7 downto 0) := (others => '0');
  51. signal cpu_was_idle : std_logic := '1';
  52. -- cpu visible registers
  53. signal chip_select_out : std_logic_vector(7 downto 0);
  54. signal status_data_out : std_logic_vector(7 downto 0);
  55. begin
  56. chip_select_out <= "0000000" & slave_cs_register;
  57. status_data_out <= "0000000" & busy_sr(7);
  58. cpu_wait <= busy_sr(7);
  59. with cpu_address select
  60. data_out <=
  61. chip_select_out when "000",
  62. status_data_out when "001",
  63. data_out_sr when "010",
  64. data_in_sr when "011",
  65. std_logic_vector(clk_divide_target) when "100",
  66. status_data_out when others;
  67. slave_cs <= slave_cs_register;
  68. slave_clk <= slave_clk_register;
  69. slave_mosi <= slave_mosi_register;
  70. spimaster_proc: process(clk)
  71. begin
  72. if rising_edge(clk) then
  73. if reset = '1' then
  74. slave_cs_register <= '1';
  75. slave_clk_register <= '1';
  76. slave_mosi_register <= '0';
  77. data_out_sr <= (others => '0');
  78. data_in_sr <= (others => '0');
  79. busy_sr <= (others => '0');
  80. clk_divide_target <= (others => '0');
  81. clk_divide_value <= (others => '0');
  82. cpu_was_idle <= '1';
  83. else
  84. -- divide down input clk to get 2 * spi clk
  85. clk_divide_value <= clk_divide_value + 1;
  86. if clk_divide_value = clk_divide_target then
  87. clk_divide_value <= to_unsigned(0, 8);
  88. end if;
  89. if busy_sr(7) = '1' then
  90. if clk_divide_value = clk_divide_target then
  91. -- we're in the midst of a transaction! whoo!
  92. if slave_clk_register = '1' then
  93. -- clk is high; next cycle will be falling edge of clk
  94. slave_clk_register <= '0';
  95. slave_mosi_register <= data_out_sr(7);
  96. -- shift data out
  97. data_out_sr <= data_out_sr(6 downto 0) & '0';
  98. else
  99. -- clk is low; next cycle will be rising edge of clk
  100. slave_clk_register <= '1';
  101. -- shift busy
  102. busy_sr <= busy_sr(6 downto 0) & '0';
  103. -- latch data in
  104. data_in_sr <= data_in_sr(6 downto 0) & slave_miso;
  105. end if;
  106. end if;
  107. end if;
  108. if enable = '1' and req_write = '1' then
  109. if busy_sr(7) = '0' and cpu_was_idle = '1' then
  110. cpu_was_idle <= '0';
  111. case cpu_address is
  112. when "000" =>
  113. slave_cs_register <= data_in(0);
  114. when "010" =>
  115. -- only allow writes when transmitter is idle
  116. data_out_sr <= data_in;
  117. busy_sr <= (others => '1');
  118. when "100" =>
  119. clk_divide_target <= unsigned(data_in);
  120. when others => -- no change
  121. end case;
  122. else
  123. cpu_was_idle <= cpu_was_idle;
  124. end if;
  125. else
  126. cpu_was_idle <= '1';
  127. end if;
  128. end if;
  129. end if;
  130. end process;
  131. end Behavioral;