?? spi_ctrl.vhd
字號(hào):
---- Copyright (C) 2006 Johannes Hausensteiner (johannes.hausensteiner@pcl.at)-- -- This program is free software; you can redistribute it and/or-- modify it under the terms of the GNU General Public License-- as published by the Free Software Foundation; either version 2-- of the License, or (at your option) any later version.-- -- This program is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU General Public License for more details.-- -- You should have received a copy of the GNU General Public License-- along with this program; if not, write to the Free Software-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.---- -- Filename: spi_ctrl.vhd---- Function: SPI Flash controller for DIY Calculator-- ---- Changelog---- 0.1 25.Sep.2006 JH new-- 0.2 15.Nov.2006 JH remove old code-- 1.0 5.Feb.2007 JH new clocking scheme-- 1.1 4.Apr.2007 JH implement high address byte-- 1.2 16.Apr.2007 JH clock enable-- 1.3 23.Apr.2007 JH remove all asynchronous elements-- 1.4 4.May 2007 JH resolve read timing-- 1.5 10.May 2007 JH remove read signal--library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity spi_ctrl is port ( clk_in : in std_logic; rst : in std_logic; spi_clk : out std_logic; spi_cs : out std_logic; spi_din : in std_logic; spi_dout : out std_logic; sel : in std_logic; wr : in std_logic; addr : in std_logic_vector (2 downto 0); d_in : in std_logic_vector (7 downto 0); d_out : out std_logic_vector (7 downto 0) );end spi_ctrl;architecture rtl of spi_ctrl is -- clock generator constant SYS_FREQ : integer := 25000000; -- 25MHz constant SPI_FREQ : integer := 6250000; -- 6.25MHz signal clk_en : std_logic; signal clk_cnt : integer range 0 to (SYS_FREQ/SPI_FREQ)-1; type state_t is ( IDLE, TxCMD, TxADD_H, TxADD_M, TxADD_L, TxDUMMY, TxDATA, RxDATA, WAIT1, WAIT2, WAIT3, WAIT4, WAIT6, WAIT5, WAIT7, WAIT8, CLR_CMD); signal state, next_state : state_t; -- transmitter signal tx_reg, tx_sreg : std_logic_vector (7 downto 0); signal tx_empty, tx_empty_set : std_logic; signal tx_bit_cnt : std_logic_vector (3 downto 0); -- receiver signal rx_sreg : std_logic_vector (7 downto 0); signal rx_ready, rx_ready_set, rx_bit_cnt_clr : std_logic; signal rx_bit_cnt : std_logic_vector (3 downto 0); signal wr_cmd, wr_data, wr_add_h, wr_add_m, wr_add_l : std_logic; signal rd_stat, rd_add_h, rd_add_m, rd_add_l : std_logic; signal rd_data, rd_data1, rd_data2 : std_logic; signal spi_cs_int, spi_clk_int : std_logic; -- auxiliary signals signal rx_enable, rx_empty, rx_empty_clr : std_logic; signal tx_enable, tx_enable_d : std_logic; signal tx_new_data, tx_new_data_clr, is_tx_data, is_wait6 : std_logic; signal cmd_clr, busy : std_logic; -- registers signal cmd, tx_data, rx_data : std_logic_vector (7 downto 0); signal add_h, add_m, add_l : std_logic_vector (7 downto 0); -- FLASH commands constant NOP : std_logic_vector (7 downto 0) := x"FF"; -- no cmd to execute constant WREN : std_logic_vector (7 downto 0) := x"06"; -- write enable constant WRDI : std_logic_vector (7 downto 0) := x"04"; -- write disable constant RDSR : std_logic_vector (7 downto 0) := x"05"; -- read status reg constant WRSR : std_logic_vector (7 downto 0) := x"01"; -- write stat. reg constant RDCMD: std_logic_vector (7 downto 0) := x"03"; -- read data constant F_RD : std_logic_vector (7 downto 0) := x"0B"; -- fast read data constant PP : std_logic_vector (7 downto 0) := x"02"; -- page program constant SE : std_logic_vector (7 downto 0) := x"D8"; -- sector erase constant BE : std_logic_vector (7 downto 0) := x"C7"; -- bulk erase constant DP : std_logic_vector (7 downto 0) := x"B9"; -- deep power down constant RES : std_logic_vector (7 downto 0) := x"AB"; -- read signaturebegin -- assign signals spi_cs <= spi_cs_int; spi_clk <= spi_clk_int; spi_dout <= tx_sreg(7); -- clock generator spi_divider : process (rst, clk_in) begin if rst = '1' then clk_cnt <= 0; clk_en <= '0'; spi_clk_int <= '1'; elsif falling_edge (clk_in) then if clk_cnt = ((SYS_FREQ / SPI_FREQ) - 2) or clk_cnt = ((SYS_FREQ / SPI_FREQ) - 3) then clk_cnt <= clk_cnt + 1; clk_en <= '0'; if tx_enable = '1' or rx_enable = '1' then spi_clk_int <= '0'; else spi_clk_int <= '1'; end if; elsif clk_cnt = ((SYS_FREQ / SPI_FREQ) - 1) then clk_cnt <= 0; clk_en <= '1'; spi_clk_int <= '1'; else clk_cnt <= clk_cnt + 1; clk_en <= '0'; spi_clk_int <= '1'; end if; end if; end process; -- address decoder process (sel, addr, wr) variable input : std_logic_vector (4 downto 0); begin input := sel & addr & wr; -- defaults wr_data <= '0'; wr_cmd <= '0'; wr_add_h <= '0'; wr_add_m <= '0'; wr_add_l <= '0'; rd_data <= '0'; rd_stat <= '0'; rd_add_h <= '0'; rd_add_m <= '0'; rd_add_l <= '0'; case input is when "10000" => rd_data <= '1'; when "10001" => wr_data <= '1'; when "10010" => rd_stat <= '1'; when "10011" => wr_cmd <= '1'; when "10100" => rd_add_l <= '1'; when "10101" => wr_add_l <= '1'; when "10110" => rd_add_m <= '1'; when "10111" => wr_add_m <= '1'; when "11000" => rd_add_h <= '1'; when "11001" => wr_add_h <= '1'; when others => null; end case; end process; -- read back registers d_out(0) <= (rx_data(0) and rd_data) or (busy and rd_stat) or (add_h(0) and rd_add_h) or (add_m(0) and rd_add_m) or (add_l(0) and rd_add_l); d_out(1) <= (rx_data(1) and rd_data) or (tx_empty and rd_stat) or (add_h(1) and rd_add_h) or (add_m(1) and rd_add_m) or (add_l(1) and rd_add_l); d_out(2) <= (rx_data(2) and rd_data) or (rx_ready and rd_stat) or (add_h(2) and rd_add_h) or (add_m(2) and rd_add_m) or (add_l(2) and rd_add_l); d_out(3) <= (rx_data(3) and rd_data) or (is_wait6 and rd_stat) or (add_h(3) and rd_add_h) or (add_m(3) and rd_add_m) or (add_l(3) and rd_add_l); d_out(4) <= (rx_data(4) and rd_data) or ('0' and rd_stat) or (add_h(4) and rd_add_h) or (add_m(4) and rd_add_m) or (add_l(4) and rd_add_l); d_out(5) <= (rx_data(5) and rd_data) or ('0' and rd_stat) or (add_h(5) and rd_add_h) or (add_m(5) and rd_add_m) or (add_l(5) and rd_add_l); d_out(6) <= (rx_data(6) and rd_data) or ('0' and rd_stat) or (add_h(6) and rd_add_h) or (add_m(6) and rd_add_m) or (add_l(6) and rd_add_l); d_out(7) <= (rx_data(7) and rd_data) or ('0' and rd_stat) or (add_h(7) and rd_add_h) or (add_m(7) and rd_add_m) or (add_l(7) and rd_add_l); -- write command register process (rst, cmd_clr, clk_in) begin if rst = '1' or cmd_clr = '1' then cmd <= NOP; elsif rising_edge (clk_in) then if wr_cmd = '1' then cmd <= d_in; end if; end if; end process; -- write address high register process (rst, clk_in) begin if rst = '1' then add_h <= x"00"; elsif rising_edge (clk_in) then if wr_add_h = '1' then add_h <= d_in; end if; end if; end process; -- write address mid register process (rst, clk_in) begin if rst = '1' then add_m <= x"00"; elsif rising_edge (clk_in) then if wr_add_m ='1' then add_m <= d_in; end if; end if; end process; -- write address low register process (rst, clk_in) begin if rst = '1' then add_l <= x"00"; elsif rising_edge (clk_in) then if wr_add_l ='1' then add_l <= d_in; end if; end if; end process; -- write tx data register process (rst, clk_in) begin if rst = '1' then tx_data <= x"00"; elsif rising_edge (clk_in) then if wr_data = '1' then tx_data <= d_in; end if; end if; end process; -- new tx data flag tx_new_data_clr <= tx_empty_set and is_tx_data; process (rst, tx_new_data_clr, clk_in) begin if rst = '1' or tx_new_data_clr = '1' then tx_new_data <= '0'; elsif rising_edge (clk_in) then if wr_data ='1' then tx_new_data <= '1'; end if; end if; end process; -- advance the state machine process (rst, clk_in) begin if rst = '1' then state <= IDLE; elsif rising_edge (clk_in) then if clk_en = '1' then state <= next_state; end if; end if; end process; -- state machine transition table process (state, cmd, tx_bit_cnt, tx_new_data, rx_bit_cnt, rx_empty) begin case state is when IDLE => case cmd is when NOP => next_state <= IDLE; when others => next_state <= TxCMD; end case;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -