• SPI Flash controller for DIY Calculator


      1 --
      2 -- Copyright (C) 2006 Johannes Hausensteiner (johannes.hausensteiner@pcl.at)
      3 -- 
      4 -- This program is free software; you can redistribute it and/or
      5 -- modify it under the terms of the GNU General Public License
      6 -- as published by the Free Software Foundation; either version 2
      7 -- of the License, or (at your option) any later version.
      8 -- 
      9 -- This program is distributed in the hope that it will be useful,
     10 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12 -- GNU General Public License for more details.
     13 -- 
     14 -- You should have received a copy of the GNU General Public License
     15 -- along with this program; if not, write to the Free Software
     16 -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     17 --
     18 -- 
     19 -- Filename: spi_ctrl.vhd
     20 --
     21 -- Function: SPI Flash controller for DIY Calculator
     22 -- 
     23 --
     24 -- Changelog
     25 --
     26 -- 0.1 25.Sep.2006 JH new
     27 -- 0.2 15.Nov.2006 JH remove old code
     28 -- 1.0 5.Feb.2007 JH new clocking scheme
     29 -- 1.1 4.Apr.2007 JH implement high address byte
     30 -- 1.2 16.Apr.2007 JH clock enable
     31 -- 1.3 23.Apr.2007 JH remove all asynchronous elements
     32 -- 1.4 4.May 2007 JH resolve read timing
     33 -- 1.5 10.May 2007 JH remove read signal
     34 --
     35 
     36 
     37 library ieee;
     38 use ieee.std_logic_1164.all;
     39 use ieee.std_logic_unsigned.all;
     40 
     41 entity spi_ctrl is
     42   port (
     43     clk_in   : in std_logic;
     44     rst      : in std_logic;
     45     spi_clk  : out std_logic;
     46     spi_cs   : out std_logic;
     47     spi_din  : in std_logic;
     48     spi_dout : out std_logic;
     49     sel      : in std_logic;
     50     wr       : in std_logic;
     51     addr     : in std_logic_vector (2 downto 0);
     52     d_in     : in std_logic_vector (7 downto 0);
     53     d_out    : out std_logic_vector (7 downto 0)
     54   );
     55 end spi_ctrl;
     56 
     57 architecture rtl of spi_ctrl is
     58  -- clock generator
     59   constant SYS_FREQ : integer := 25000000; -- 25MHz
     60   constant SPI_FREQ : integer := 6250000; -- 6.25MHz
     61   signal clk_en     : std_logic;
     62   signal clk_cnt    : integer range 0 to (SYS_FREQ/SPI_FREQ)-1;
     63 
     64   type state_t is (
     65     IDLE,
     66     TxCMD,
     67     TxADD_H,
     68     TxADD_M,
     69     TxADD_L,
     70     TxDUMMY,
     71     TxDATA,
     72     RxDATA,
     73     WAIT1,
     74     WAIT2,
     75     WAIT3,
     76     WAIT4,
     77     WAIT6,
     78     WAIT5,
     79     WAIT7,
     80     WAIT8,
     81     CLR_CMD);
     82 
     83   signal state, next_state : state_t;
     84 
     85  -- transmitter
     86   signal tx_reg       : std_logic_vector (7 downto 0);
     87   signal tx_sreg      : std_logic_vector (7 downto 0);
     88   signal tx_empty_set : std_logic;
     89   signal tx_empty     : std_logic;
     90   signal tx_bit_cnt   : std_logic_vector (3 downto 0);
     91 
     92  -- receiver
     93   signal rx_sreg        : std_logic_vector (7 downto 0);
     94   signal rx_ready       : std_logic;
     95   signal rx_ready_set   : std_logic;
     96   signal rx_bit_cnt_clr : std_logic;
     97   signal rx_bit_cnt     : std_logic_vector (3 downto 0);
     98 
     99   signal wr_cmd, wr_data              : std_logic;
    100   signal wr_add_h, wr_add_m, wr_add_l : std_logic;
    101   signal rd_stat                      : std_logic;
    102   signal rd_add_h, rd_add_m, rd_add_l : std_logic;
    103   signal rd_data, rd_data1, rd_data2  : std_logic;
    104   signal spi_cs_int, spi_clk_int      : std_logic;
    105 
    106  -- auxiliary signals
    107   signal rx_enable                    : std_logic;
    108   signal rx_empty, rx_empty_clr       : std_logic;
    109   signal tx_enable, tx_enable_d       : std_logic;
    110   signal tx_new_data, tx_new_data_clr : std_logic;
    111   signal is_tx_data, is_wait6         : std_logic;
    112   signal cmd_clr, busy                : std_logic;
    113 
    114  -- registers
    115   signal cmd, tx_data, rx_data : std_logic_vector (7 downto 0);
    116   signal add_h, add_m, add_l   : std_logic_vector (7 downto 0);
    117 
    118  -- FLASH commands
    119   constant NOP   : std_logic_vector (7 downto 0) := x"FF"; -- no cmd to execute
    120   constant WREN  : std_logic_vector (7 downto 0) := x"06"; -- write enable
    121   constant WRDI  : std_logic_vector (7 downto 0) := x"04"; -- write disable
    122   constant RDSR  : std_logic_vector (7 downto 0) := x"05"; -- read status reg
    123   constant WRSR  : std_logic_vector (7 downto 0) := x"01"; -- write stat. reg
    124   constant RDCMD : std_logic_vector (7 downto 0) := x"03"; -- read data
    125   constant F_RD  : std_logic_vector (7 downto 0) := x"0B"; -- fast read data
    126   constant PP    : std_logic_vector (7 downto 0) := x"02"; -- page program
    127   constant SE    : std_logic_vector (7 downto 0) := x"D8"; -- sector erase
    128   constant BE    : std_logic_vector (7 downto 0) := x"C7"; -- bulk erase
    129   constant DP    : std_logic_vector (7 downto 0) := x"B9"; -- deep power down
    130   constant RES   : std_logic_vector (7 downto 0) := x"AB"; -- read signature
    131 begin
    132  -- assign signals
    133   spi_cs   <= spi_cs_int;
    134   spi_clk  <= spi_clk_int;
    135   spi_dout <= tx_sreg(7);
    136 
    137  -- clock generator
    138   spi_divider : process (rst, clk_in)
    139   begin
    140     if rst = '1' then
    141       clk_cnt     <= 0;
    142       clk_en      <= '0';
    143       spi_clk_int <= '1';
    144     elsif falling_edge (clk_in) then
    145       if clk_cnt = ((SYS_FREQ / SPI_FREQ) - 2) or
    146  clk_cnt = ((SYS_FREQ / SPI_FREQ) - 3) then
    147         clk_cnt <= clk_cnt + 1;
    148         clk_en  <= '0';
    149         if tx_enable = '1' or rx_enable = '1' then
    150           spi_clk_int <= '0';
    151         else
    152           spi_clk_int <= '1';
    153         end if;
    154       elsif clk_cnt = ((SYS_FREQ / SPI_FREQ) - 1) then
    155         clk_cnt     <= 0;
    156         clk_en      <= '1';
    157         spi_clk_int <= '1';
    158       else
    159         clk_cnt     <= clk_cnt + 1;
    160         clk_en      <= '0';
    161         spi_clk_int <= '1';
    162       end if;
    163     end if;
    164   end process;
    165 
    166  -- address decoder
    167   process (sel, addr, wr)
    168     variable input : std_logic_vector (4 downto 0);
    169   begin
    170     input := sel & addr & wr;
    171  -- defaults
    172     wr_data  <= '0';
    173     wr_cmd   <= '0';
    174     wr_add_h <= '0';
    175     wr_add_m <= '0';
    176     wr_add_l <= '0';
    177     rd_data  <= '0';
    178     rd_stat  <= '0';
    179     rd_add_h <= '0';
    180     rd_add_m <= '0';
    181     rd_add_l <= '0';
    182     case input is
    183       when "10000" => rd_data <= '1';
    184       when "10001" => wr_data <= '1';
    185       when "10010" => rd_stat <= '1';
    186       when "10011" => wr_cmd <= '1';
    187       when "10100" => rd_add_l <= '1';
    188       when "10101" => wr_add_l <= '1';
    189       when "10110" => rd_add_m <= '1';
    190       when "10111" => wr_add_m <= '1';
    191       when "11000" => rd_add_h <= '1';
    192       when "11001" => wr_add_h <= '1';
    193       when others  => null;
    194     end case;
    195   end process;
    196 
    197  -- read back registers
    198   d_out(0) <= (rx_data(0) and rd_data)
    199  or (busy and rd_stat)
    200  or (add_h(0) and rd_add_h)
    201  or (add_m(0) and rd_add_m)
    202  or (add_l(0) and rd_add_l);
    203 
    204   d_out(1) <= (rx_data(1) and rd_data)
    205  or (tx_empty and rd_stat)
    206  or (add_h(1) and rd_add_h)
    207  or (add_m(1) and rd_add_m)
    208  or (add_l(1) and rd_add_l);
    209 
    210   d_out(2) <= (rx_data(2) and rd_data)
    211  or (rx_ready and rd_stat)
    212  or (add_h(2) and rd_add_h)
    213  or (add_m(2) and rd_add_m)
    214  or (add_l(2) and rd_add_l);
    215 
    216   d_out(3) <= (rx_data(3) and rd_data)
    217  or (is_wait6 and rd_stat)
    218  or (add_h(3) and rd_add_h)
    219  or (add_m(3) and rd_add_m)
    220  or (add_l(3) and rd_add_l);
    221 
    222   d_out(4) <= (rx_data(4) and rd_data)
    223  or ('0' and rd_stat)
    224  or (add_h(4) and rd_add_h)
    225  or (add_m(4) and rd_add_m)
    226  or (add_l(4) and rd_add_l);
    227 
    228   d_out(5) <= (rx_data(5) and rd_data)
    229  or ('0' and rd_stat)
    230  or (add_h(5) and rd_add_h)
    231  or (add_m(5) and rd_add_m)
    232  or (add_l(5) and rd_add_l);
    233 
    234   d_out(6) <= (rx_data(6) and rd_data)
    235  or ('0' and rd_stat)
    236  or (add_h(6) and rd_add_h)
    237  or (add_m(6) and rd_add_m)
    238  or (add_l(6) and rd_add_l);
    239 
    240   d_out(7) <= (rx_data(7) and rd_data)
    241  or ('0' and rd_stat)
    242  or (add_h(7) and rd_add_h)
    243  or (add_m(7) and rd_add_m)
    244  or (add_l(7) and rd_add_l);
    245 
    246  -- write command register
    247   process (rst, cmd_clr, clk_in)
    248   begin
    249     if rst = '1' or cmd_clr = '1' then
    250       cmd <= NOP;
    251     elsif rising_edge (clk_in) then
    252       if wr_cmd = '1' then
    253         cmd <= d_in;
    254       end if;
    255     end if;
    256   end process;
    257 
    258  -- write address high register
    259   process (rst, clk_in)
    260   begin
    261     if rst = '1' then
    262       add_h <= x"00";
    263     elsif rising_edge (clk_in) then
    264       if wr_add_h = '1' then
    265         add_h <= d_in;
    266       end if;
    267     end if;
    268   end process;
    269 
    270  -- write address mid register
    271   process (rst, clk_in)
    272   begin
    273     if rst = '1' then
    274       add_m <= x"00";
    275     elsif rising_edge (clk_in) then
    276       if wr_add_m = '1' then
    277         add_m <= d_in;
    278       end if;
    279     end if;
    280   end process;
    281 
    282  -- write address low register
    283   process (rst, clk_in)
    284   begin
    285     if rst = '1' then
    286       add_l <= x"00";
    287     elsif rising_edge (clk_in) then
    288       if wr_add_l = '1' then
    289         add_l <= d_in;
    290       end if;
    291     end if;
    292   end process;
    293 
    294  -- write tx data register
    295   process (rst, clk_in)
    296   begin
    297     if rst = '1' then
    298       tx_data <= x"00";
    299     elsif rising_edge (clk_in) then
    300       if wr_data = '1' then
    301         tx_data <= d_in;
    302       end if;
    303     end if;
    304   end process;
    305 
    306  -- new tx data flag
    307   tx_new_data_clr <= tx_empty_set and is_tx_data;
    308   process (rst, tx_new_data_clr, clk_in)
    309   begin
    310     if rst = '1' or tx_new_data_clr = '1' then
    311       tx_new_data <= '0';
    312     elsif rising_edge (clk_in) then
    313       if wr_data = '1' then
    314         tx_new_data <= '1';
    315       end if;
    316     end if;
    317   end process;
    318 
    319  -- advance the state machine
    320   process (rst, clk_in)
    321   begin
    322     if rst = '1' then
    323       state <= IDLE;
    324     elsif rising_edge (clk_in) then
    325       if clk_en = '1' then
    326         state <= next_state;
    327       end if;
    328     end if;
    329   end process;
    330 
    331  -- state machine transition table
    332   process (state, cmd, tx_bit_cnt, tx_new_data, rx_bit_cnt, rx_empty)
    333   begin
    334     case state is
    335       when IDLE =>
    336         case cmd is
    337           when NOP    => next_state <= IDLE;
    338           when others => next_state <= TxCMD;
    339         end case;
    340 
    341       when TxCMD =>
    342         if tx_bit_cnt < x"7" then
    343           next_state <= TxCMD;
    344         else
    345           case cmd is
    346             when WREN | WRDI    => next_state <= CLR_CMD;
    347             when BE | DP        => next_state <= CLR_CMD;
    348             when SE | PP        => next_state <= WAIT1;
    349             when RES | RDCMD    => next_state <= WAIT1;
    350             when F_RD|WRSR|RDSR => next_state <= WAIT1;
    351             when others         => next_state <= CLR_CMD;
    352           end case;
    353         end if;
    354 
    355       when WAIT1 =>
    356         case cmd is
    357           when WREN | WRDI   => next_state <= CLR_CMD;
    358           when BE | DP       => next_state <= CLR_CMD;
    359           when SE | PP | RES => next_state <= TxADD_H;
    360           when RDCMD | F_RD  => next_state <= TxADD_H;
    361           when WRSR          => next_state <= TxDATA;
    362           when RDSR          => next_state <= RxDATA;
    363           when others        => next_state <= CLR_CMD;
    364         end case;
    365 
    366       when TxADD_H =>
    367         if tx_bit_cnt < x"7" then
    368           next_state <= TxADD_H;
    369         else
    370           next_state <= WAIT2;
    371         end if;
    372 
    373       when WAIT2 => next_state <= TxADD_M;
    374 
    375       when TxADD_M =>
    376         if tx_bit_cnt < x"7" then
    377           next_state <= TxADD_M;
    378         else
    379           next_state <= WAIT3;
    380         end if;
    381 
    382       when WAIT3 => next_state <= TxADD_L;
    383 
    384       when TxADD_L =>
    385         if tx_bit_cnt < x"7" then
    386           next_state <= TxADD_L;
    387         else
    388           case cmd is
    389             when PP           => next_state <= WAIT6;
    390             when SE | RES     => next_state <= WAIT4;
    391             when RDCMD | F_RD => next_state <= WAIT4;
    392             when others       => next_state <= CLR_CMD;
    393           end case;
    394         end if;
    395 
    396       when WAIT4 =>
    397         case cmd is
    398           when F_RD        => next_state <= TxDUMMY;
    399           when RES | RDCMD => next_state <= RxDATA;
    400           when others      => next_state <= CLR_CMD;
    401         end case;
    402 
    403       when TxDUMMY =>
    404         if tx_bit_cnt < x"7" then
    405           next_state <= TxDUMMY;
    406         else
    407           next_state <= WAIT8;
    408         end if;
    409 
    410       when WAIT7 => next_state <= WAIT8;
    411 
    412       when WAIT8 =>
    413         case cmd is
    414           when RDCMD | F_RD =>
    415             if rx_empty = '1' then
    416               next_state <= RxDATA;
    417             else
    418               next_state <= WAIT8;
    419             end if;
    420           when others => next_state <= CLR_CMD;
    421         end case;
    422 
    423       when RxDATA =>
    424         if rx_bit_cnt < x"7" then
    425           next_state <= RxDATA;
    426         else
    427           case cmd is
    428             when RDCMD | F_RD => next_state <= WAIT7;
    429             when RDSR | RES   => next_state <= WAIT5;
    430             when others       => next_state <= CLR_CMD;
    431           end case;
    432         end if;
    433 
    434       when TxDATA =>
    435         if tx_bit_cnt < x"7" then
    436           next_state <= TxDATA;
    437         else
    438           case cmd is
    439             when PP     => next_state <= WAIT6;
    440             when others => next_state <= CLR_CMD;
    441           end case;
    442         end if;
    443 
    444       when WAIT6 =>
    445         case cmd is
    446           when PP =>
    447             if tx_new_data = '1' then
    448               next_state <= TxDATA;
    449             else
    450               next_state <= WAIT6;
    451             end if;
    452           when others => next_state <= CLR_CMD;
    453         end case;
    454 
    455       when WAIT5 => next_state <= CLR_CMD;
    456 
    457       when CLR_CMD => next_state <= IDLE;
    458     end case;
    459   end process;
    460 
    461  -- state machine output table
    462   process (state, cmd, tx_data, add_m, add_l, add_h)
    463   begin
    464  -- default values
    465     tx_enable      <= '0';
    466     rx_enable      <= '0';
    467     rx_bit_cnt_clr <= '1';
    468     tx_reg         <= x"FF";
    469     spi_cs_int     <= '0';
    470     busy           <= '1';
    471     cmd_clr        <= '0';
    472     is_tx_data     <= '0';
    473     is_wait6       <= '0';
    474 
    475     case state is
    476       when IDLE =>
    477         busy <= '0';
    478       when TxCMD =>
    479         tx_reg     <= cmd;
    480         tx_enable  <= '1';
    481         spi_cs_int <= '1';
    482       when TxDATA =>
    483         tx_reg     <= tx_data;
    484         tx_enable  <= '1';
    485         spi_cs_int <= '1';
    486         is_tx_data <= '1';
    487       when TxADD_H =>
    488         tx_reg     <= add_h;
    489         tx_enable  <= '1';
    490         spi_cs_int <= '1';
    491       when TxADD_M =>
    492         tx_reg     <= add_m;
    493         tx_enable  <= '1';
    494         spi_cs_int <= '1';
    495       when TxADD_L =>
    496         tx_reg     <= add_l;
    497         tx_enable  <= '1';
    498         spi_cs_int <= '1';
    499       when TxDUMMY =>
    500         tx_reg     <= x"00";
    501         tx_enable  <= '1';
    502         spi_cs_int <= '1';
    503       when RxDATA =>
    504         rx_bit_cnt_clr <= '0';
    505         rx_enable      <= '1';
    506         spi_cs_int     <= '1';
    507       when WAIT1 | WAIT2 | WAIT3 | WAIT4 | WAIT8 =>
    508         spi_cs_int <= '1';
    509       when WAIT6 =>
    510         is_wait6   <= '1';
    511         spi_cs_int <= '1';
    512       when WAIT5 | WAIT7 =>
    513         rx_bit_cnt_clr <= '0';
    514         spi_cs_int     <= '1';
    515       when CLR_CMD =>
    516         cmd_clr <= '1';
    517       when others => null;
    518     end case;
    519   end process;
    520 
    521  -- the tx_empty flip flop
    522   process (rst, wr_data, clk_in)
    523   begin
    524     if rst = '1' then
    525       tx_empty <= '1';
    526     elsif wr_data = '1' then
    527       tx_empty <= '0';
    528     elsif rising_edge (clk_in) then
    529       if tx_empty_set = '1' then
    530         tx_empty <= '1';
    531       end if;
    532     end if;
    533   end process;
    534 
    535  -- delay the tx_enable signal
    536   process (rst, clk_in)
    537   begin
    538     if rst = '1' then
    539       tx_enable_d <= '0';
    540     elsif rising_edge (clk_in) then
    541       tx_enable_d <= tx_enable;
    542     end if;
    543   end process;
    544 
    545  -- transmitter shift register and bit counter
    546   process (rst, tx_reg, tx_enable_d, clk_in)
    547   begin
    548     if rst = '1' then
    549       tx_sreg      <= x"FF";
    550       tx_bit_cnt   <= x"0";
    551       tx_empty_set <= '0';
    552     elsif tx_enable_d = '0' then
    553       tx_sreg      <= tx_reg;
    554       tx_bit_cnt   <= x"0";
    555       tx_empty_set <= '0';
    556     elsif rising_edge (clk_in) then
    557       if clk_en = '1' then
    558         tx_bit_cnt <= tx_bit_cnt + 1;
    559         tx_sreg    <= tx_sreg (6 downto 0) & '1';
    560         if tx_bit_cnt = x"6" and is_tx_data = '1' then
    561           tx_empty_set <= '1';
    562         else
    563           tx_empty_set <= '0';
    564         end if;
    565       end if;
    566     end if;
    567   end process;
    568 
    569  -- synchronize rd_data
    570   process (rst, clk_in)
    571   begin
    572     if rst = '1' then
    573       rd_data1 <= '0';
    574     elsif falling_edge (clk_in) then
    575       rd_data1 <= rd_data;
    576     end if;
    577   end process;
    578 
    579   process (rst, clk_in)
    580   begin
    581     if rst = '1' then
    582       rd_data2 <= '0';
    583     elsif falling_edge (clk_in) then
    584       if rd_data = '0' then
    585         rd_data2 <= rd_data1;
    586       end if;
    587     end if;
    588   end process;
    589 
    590  -- the rx_empty flip flop
    591   process (rst, clk_in)
    592   begin
    593     if rst = '1' then
    594       rx_empty <= '1';
    595     elsif rising_edge (clk_in) then
    596       if rx_empty_clr = '1' then
    597         rx_empty <= '0';
    598       elsif rd_data2 = '1' then
    599         rx_empty <= '1';
    600       end if;
    601     end if;
    602   end process;
    603 
    604  -- the rx_ready flip flop
    605   process (rst, clk_in)
    606   begin
    607     if rst = '1' then
    608       rx_ready <= '0';
    609     elsif rising_edge (clk_in) then
    610       if rd_data = '1' then
    611         rx_ready <= '0';
    612       elsif rx_ready_set = '1' then
    613         rx_ready <= '1';
    614       end if;
    615     end if;
    616   end process;
    617 
    618  -- the rx_data register
    619   process (rst, clk_in)
    620   begin
    621     if rst = '1' then
    622       rx_data <= x"FF";
    623     elsif rising_edge (clk_in) then
    624       if rx_ready_set = '1' then
    625         rx_data <= rx_sreg;
    626       end if;
    627     end if;
    628   end process;
    629 
    630  -- receiver shift register and bit counter
    631   process (rst, rx_bit_cnt_clr, clk_in)
    632   begin
    633     if rst = '1' or rx_bit_cnt_clr = '1' then
    634       rx_bit_cnt   <= x"0";
    635       rx_ready_set <= '0';
    636       rx_empty_clr <= '0';
    637       rx_sreg      <= x"FF";
    638     elsif rising_edge (clk_in) then
    639       if clk_en = '1' then
    640         rx_sreg <= rx_sreg (6 downto 0) & spi_din;
    641         case rx_bit_cnt is
    642           when x"0" =>
    643             rx_bit_cnt   <= rx_bit_cnt + 1;
    644             rx_ready_set <= '0';
    645             rx_empty_clr <= '1';
    646           when x"1" | x"2" | x"3" | x"4" | x"5" | x"6" =>
    647             rx_bit_cnt   <= rx_bit_cnt + 1;
    648             rx_ready_set <= '0';
    649             rx_empty_clr <= '0';
    650           when x"7" =>
    651             rx_bit_cnt   <= rx_bit_cnt + 1;
    652             rx_ready_set <= '1';
    653             rx_empty_clr <= '0';
    654           when others =>
    655             null;
    656         end case;
    657       end if;
    658     end if;
    659   end process;
    660 end rtl;

    http://www.diycalculator.com/

    http://opencores.org/project,spiflashcontroller

     1 Command classification:
     2 -----------------------
     3 
     4   Write Enable (WREN)              transmit 1 byte ... cmd (0x06)
     5   Write Disable (WRDI)                                     (0x04)
     6   Bulk Erase (BE)                                          (0xC7)
     7   Deep Power Down (DP)                                     (0xB9)
     8   
     9   Write Status reg (WRSR)          transmit 1 byte ... cmd (0x01)
    10                                             1 byte ... SR contents
    11 
    12   Sector Erase (SE)                transmit 1 byte ... cmd (0xD8)
    13                                             3 bytes .. address
    14 
    15   Page Program (PP)                transmit 1 byte ... cmd (0x02)
    16                                             3 bytes .. address
    17                                             1-256 bytes .. data
    18 
    19   Read Status reg (RDSR)           transmit 1 byte ... cmd (0x05)
    20                                    receive  1 byte ... SR contents
    21 
    22   Read Signature (RES)             transmit 1 byte ... cmd (0xAB)
    23                                             3 bytes .. dummy
    24                                    receive  1 byte ... the signature (0x13)
    25 
    26   Read Data (RD)                   transmit 1 byte ... cmd (0x03)
    27                                             3 bytes .. address
    28                                    receive  n bytes .. data
    29 
    30   Fast Read Data (F_RD)            transmit 1 byte ... cmd (0x0B)
    31                                             3 bytes .. address
    32                                             1 byte ... dummy
    33                                    receive  n bytes .. data
      1 library ieee;
      2 use ieee.std_logic_1164.all;
      3 use ieee.numeric_std.all;
      4 
      5 entity test_spi_ctrl is
      6 end test_spi_ctrl;
      7 
      8 architecture test of test_spi_ctrl is
      9   signal rst, clk, sel, rd, wr              : std_logic;
     10   signal addr                               : std_logic_vector (2 downto 0);
     11   signal spi_clk, spi_cs, spi_din, spi_dout : std_logic;
     12   signal d_in, d_out, stat, data            : std_logic_vector (7 downto 0);
     13   -- FLASH commands
     14   constant NOP   : std_logic_vector (7 downto 0) := x"FF"; -- no cmd to execute
     15   constant WREN  : std_logic_vector (7 downto 0) := x"06"; -- write enable
     16   constant WRDI  : std_logic_vector (7 downto 0) := x"04"; -- write disable
     17   constant RDSR  : std_logic_vector (7 downto 0) := x"05"; -- read status reg
     18   constant WRSR  : std_logic_vector (7 downto 0) := x"01"; -- write stat. reg
     19   constant RDCMD : std_logic_vector (7 downto 0) := x"03"; -- read data
     20   constant F_RD  : std_logic_vector (7 downto 0) := x"0B"; -- fast read data
     21   constant PP    : std_logic_vector (7 downto 0) := x"02"; -- page program
     22   constant SE    : std_logic_vector (7 downto 0) := x"D8"; -- sector erase
     23   constant BE    : std_logic_vector (7 downto 0) := x"C7"; -- bulk erase
     24   constant DP    : std_logic_vector (7 downto 0) := x"B9"; -- deep power down
     25   constant RES   : std_logic_vector (7 downto 0) := x"AB"; -- read signature
     26 
     27   -- status register bit masks
     28   constant STAT_BUSY : std_logic_vector (7 downto 0) := x"01";
     29   constant STAT_TXE  : std_logic_vector (7 downto 0) := x"02";
     30   constant STAT_RXR  : std_logic_vector (7 downto 0) := x"04";
     31   constant STAT_WDAT : std_logic_vector (7 downto 0) := x"08";
     32 begin
     33   dut : entity work.spi_ctrl
     34   port map (
     35     clk_in   => clk,
     36     rst      => rst,
     37     spi_clk  => spi_clk,
     38     spi_cs   => spi_cs,
     39     spi_din  => spi_din,
     40     spi_dout => spi_dout,
     41     sel      => sel,
     42     wr       => wr,
     43     addr     => addr,
     44     d_in     => d_in,
     45     d_out    => d_out
     46   );
     47 
     48   process is
     49   begin
     50     clk <= '0';
     51     wait for 20 ns;
     52     clk <= '1';
     53     wait for 20 ns;
     54   end process;
     55 
     56   process is
     57   begin
     58     rst <= '0';
     59     wait for 50 ns;
     60     rst <= '1';
     61     wait for 120 ns;
     62     rst <= '0';
     63     wait;
     64   end process;
     65 
     66   process
     67   begin
     68     -- initial condition
     69     sel  <= '0';
     70     addr <= "000";
     71     rd   <= '0';
     72     wr   <= '0';
     73     d_in <= x"FF";
     74 
     75     wait for 1420 ns;
     76 
     77     -- write command WREN
     78     sel  <= '1';
     79     addr <= "001";
     80     d_in <= WREN;
     81     wait for 5 ns;
     82     wr <= '1';
     83     wait for 100 ns;
     84     wr <= '0';
     85     wait for 5 ns;
     86     sel  <= '0';
     87     d_in <= x"FF";
     88     wait for 2 us;
     89 
     90     -- write command WRDI
     91     sel  <= '1';
     92     addr <= "001";
     93     d_in <= WRDI;
     94     wait for 5 ns;
     95     wr <= '1';
     96     wait for 100 ns;
     97     wr <= '0';
     98     wait for 5 ns;
     99     sel  <= '0';
    100     d_in <= x"FF";
    101     wait for 2 us;
    102 
    103     -- write command WRSR: data
    104     sel  <= '1';
    105     addr <= "000";
    106     d_in <= x"55";
    107     wait for 5 ns;
    108     wr <= '1';
    109     wait for 100 ns;
    110     wr <= '0';
    111     wait for 5 ns;
    112     sel  <= '0';
    113     d_in <= x"FF";
    114     wait for 10 ns;
    115     -- the command
    116     sel  <= '1';
    117     addr <= "001";
    118     d_in <= WRSR;
    119     wait for 5 ns;
    120     wr <= '1';
    121     wait for 100 ns;
    122     wr <= '0';
    123     wait for 5 ns;
    124     sel  <= '0';
    125     d_in <= x"FF";
    126     wait for 4 us;
    127 
    128     -- write command SE:
    129     -- address low
    130     sel  <= '1';
    131     addr <= "010";
    132     d_in <= x"AB";
    133     wait for 5 ns;
    134     wr <= '1';
    135     wait for 100 ns;
    136     wr <= '0';
    137     wait for 5 ns;
    138     sel  <= '0';
    139     d_in <= x"FF";
    140     wait for 10 ns;
    141     --address mid
    142     sel  <= '1';
    143     addr <= "011";
    144     d_in <= x"CD";
    145     wait for 5 ns;
    146     wr <= '1';
    147     wait for 100 ns;
    148     wr <= '0';
    149     wait for 5 ns;
    150     sel  <= '0';
    151     d_in <= x"FF";
    152     wait for 10 ns;
    153     -- address high
    154     sel  <= '1';
    155     addr <= "100";
    156     d_in <= x"EF";
    157     wait for 5 ns;
    158     wr <= '1';
    159     wait for 100 ns;
    160     wr <= '0';
    161     wait for 5 ns;
    162     sel  <= '0';
    163     d_in <= x"FF";
    164     wait for 10 ns;
    165     -- the command
    166     sel  <= '1';
    167     addr <= "001";
    168     d_in <= SE;
    169     wait for 5 ns;
    170     wr <= '1';
    171     wait for 100 ns;
    172     wr <= '0';
    173     wait for 5 ns;
    174     sel  <= '0';
    175     d_in <= x"FF";
    176     wait for 6.5 us;
    177 
    178     -- write command PP:
    179     -- address low
    180     sel  <= '1';
    181     addr <= "010";
    182     d_in <= x"45";
    183     wait for 5 ns;
    184     wr <= '1';
    185     wait for 100 ns;
    186     wr <= '0';
    187     wait for 5 ns;
    188     sel  <= '0';
    189     d_in <= x"FF";
    190     wait for 10 ns;
    191     -- address mid
    192     sel  <= '1';
    193     addr <= "011";
    194     d_in <= x"67";
    195     wait for 5 ns;
    196     wr <= '1';
    197     wait for 100 ns;
    198     wr <= '0';
    199     wait for 5 ns;
    200     sel  <= '0';
    201     d_in <= x"FF";
    202     wait for 10 ns;
    203     -- address high
    204     sel  <= '1';
    205     addr <= "100";
    206     d_in <= x"89";
    207     wait for 5 ns;
    208     wr <= '1';
    209     wait for 100 ns;
    210     wr <= '0';
    211     wait for 5 ns;
    212     sel  <= '0';
    213     d_in <= x"FF";
    214     wait for 10 ns;
    215     -- the command
    216     sel  <= '1';
    217     addr <= "001";
    218     d_in <= PP;
    219     wait for 5 ns;
    220     wr <= '1';
    221     wait for 100 ns;
    222     wr <= '0';
    223     wait for 5 ns;
    224     sel  <= '0';
    225     d_in <= x"FF";
    226     wait for 100 ns;
    227     -- some data
    228     for i in 0 to 20 loop
    229       -- 
    230       wait for tx_empty
    231       stat <= x"00";
    232       wait for 10 ns;
    233       while (stat and STAT_WDAT) /= STAT_WDAT loop
    234         sel  <= '1';
    235         addr <= "001";
    236         wait for 5 ns;
    237         rd <= '1';
    238         wait for 100 ns;
    239         stat <= d_out;
    240         rd   <= '0';
    241         wait for 5 ns;
    242         sel <= '0';
    243         wait for 1 us;
    244       end loop;
    245       -- write new data
    246       sel  <= '1';
    247       addr <= "000";
    248       d_in <= std_logic_vector(TO_UNSIGNED(i, d_in'Length));
    249       wait for 5 ns;
    250       wr <= '1';
    251       wait for 100 ns;
    252       wr <= '0';
    253       wait for 5 ns;
    254       sel  <= '0';
    255       d_in <= x"FF";
    256       wait for 1 us;
    257     end loop;
    258     -- send one more byte
    259 
    260     wait for 10 us;
    261     sel  <= '1';
    262     addr <= "000";
    263 
    264     d_in <= x"AA";
    265     wait for 5 ns;
    266     wr <= '1';
    267     wait for 100 ns;
    268     wr <= '0';
    269     wait for 5 ns;
    270     sel  <= '0';
    271     d_in <= x"FF";
    272     wait for 1 us;
    273     -- write the NOP command to terminate
    274     sel  <= '1';
    275     addr <= "001";
    276 
    277     d_in <= NOP;
    278     wait for 5 ns;
    279     wr <= '1';
    280     wait for 100 ns;
    281     wr <= '0';
    282     wait for 5 ns;
    283     sel  <= '0';
    284     d_in <= x"FF";
    285     wait for 100 ns;
    286 
    287 
    288     wait for 40 us;
    289 
    290     -- now receive something, cmd RDSR
    291     sel  <= '1';
    292     addr <= "001";
    293     d_in <= RDSR;
    294     wait for 5 ns;
    295     wr <= '1';
    296     wait for 100 ns;
    297     wr <= '0';
    298     wait for 5 ns;
    299     sel  <= '0';
    300     d_in <= x"FF";
    301     -- poll for rx_ready
    302     stat <= x"00";
    303     wait for 10 ns;
    304     while (stat and STAT_RXR) /= STAT_RXR loop
    305 
    306       wait for 200 ns;
    307       sel  <= '1';
    308       addr <= "001";
    309       wait for 5 ns;
    310       rd <= '1';
    311       wait for 100 ns;
    312       stat <= d_out;
    313       rd   <= '0';
    314       wait for 5 ns;
    315       sel <= '0';
    316     end loop;
    317 
    318     wait for 100 ns;
    319     -- read the data            
    320     sel  <= '1';
    321     addr <= "000";
    322     wait for 5 ns;
    323     rd <= '1';
    324     wait for 100 ns;
    325     data <= d_out;
    326     rd   <= '0';
    327     wait for 5 ns;
    328     sel <= '0';
    329     wait for 1.5 us;
    330 
    331     -- RES command
    332     sel  <= '1';
    333     addr <= "001";
    334     d_in <= RES;
    335     wait for 5 ns;
    336     wr <= '1';
    337     wait for 100 ns;
    338     wr <= '0';
    339     wait for 5 ns;
    340     sel  <= '0';
    341     d_in <= x"FF";
    342     -- poll for rx_ready
    343     stat <= x"00";
    344     wait for 10 ns;
    345     while (stat and STAT_RXR) /= STAT_RXR loop
    346 
    347       wait for 200 ns;
    348       sel  <= '1';
    349       addr <= "001";
    350       wait for 5 ns;
    351       rd <= '1';
    352       wait for 100 ns;
    353       stat <= d_out;
    354       rd   <= '0';
    355       wait for 5 ns;
    356       sel <= '0';
    357     end loop;
    358 
    359     wait for 100 ns;
    360     -- read the data
    361     sel  <= '1';
    362     addr <= "000";
    363     wait for 5 ns;
    364     rd <= '1';
    365     wait for 100 ns;
    366     data <= d_out;
    367     rd   <= '0';
    368     wait for 5 ns;
    369     sel <= '0';
    370     wait for 1.5 us;
    371 
    372     -- READ command
    373     -- address low
    374     sel  <= '1';
    375     addr <= "010";
    376     d_in <= x"12";
    377     wait for 5 ns;
    378     wr <= '1';
    379     wait for 100 ns;
    380     wr <= '0';
    381     wait for 5 ns;
    382     sel  <= '0';
    383     d_in <= x"FF";
    384     wait for 10 ns;
    385     -- address mid
    386     sel  <= '1';
    387     addr <= "011";
    388     d_in <= x"34";
    389     wait for 5 ns;
    390     wr <= '1';
    391     wait for 100 ns;
    392     wr <= '0';
    393     wait for 5 ns;
    394     sel  <= '0';
    395     d_in <= x"FF";
    396     wait for 10 ns;
    397     -- address high
    398     sel  <= '1';
    399     addr <= "100";
    400     d_in <= x"56";
    401     wait for 5 ns;
    402     wr <= '1';
    403     wait for 100 ns;
    404     wr <= '0';
    405     wait for 5 ns;
    406     sel  <= '0';
    407     d_in <= x"FF";
    408     wait for 10 ns;
    409     -- the command
    410     sel  <= '1';
    411     addr <= "001";
    412     d_in <= RDCMD;
    413     wait for 5 ns;
    414     wr <= '1';
    415     wait for 100 ns;
    416     wr <= '0';
    417     wait for 5 ns;
    418     sel  <= '0';
    419     d_in <= x"FF";
    420     -- read data
    421     for i in 1 to 10 loop
    422       -- poll for rx_ready
    423       stat <= x"00";
    424       wait for 10 ns;
    425       while (stat and STAT_RXR) /= STAT_RXR loop
    426 
    427         wait for 200 ns;
    428         sel  <= '1';
    429         addr <= "001";
    430         wait for 5 ns;
    431         rd <= '1';
    432         wait for 100 ns;
    433         stat <= d_out;
    434         rd   <= '0';
    435         wait for 5 ns;
    436         sel <= '0';
    437       end loop;
    438 
    439       wait for 100 ns;
    440       -- read the data
    441       sel  <= '1';
    442       addr <= "000";
    443       wait for 5 ns;
    444       rd <= '1';
    445       wait for 100 ns;
    446       data <= d_out;
    447       rd   <= '0';
    448       wait for 5 ns;
    449       sel <= '0';
    450     end loop;
    451 
    452     wait for 1 us;
    453     -- write the NOP command to terminate
    454     sel  <= '1';
    455     addr <= "001";
    456     d_in <= NOP;
    457     wait for 5 ns;
    458     wr <= '1';
    459     wait for 100 ns;
    460     wr <= '0';
    461     wait for 5 ns;
    462     sel  <= '0';
    463     d_in <= x"FF";
    464 
    465     wait;
    466   end process;
    467 
    468   process
    469   begin
    470     spi_din <= '1';
    471     wait for 144.880 us;
    472 
    473     -- input data for RDSR cmd 0x54
    474     spi_din <= '0';
    475     wait for 160 ns;
    476     spi_din <= '1';
    477     wait for 160 ns;
    478     spi_din <= '0';
    479     wait for 160 ns;
    480     spi_din <= '1';
    481     wait for 160 ns;
    482     spi_din <= '0';
    483     wait for 160 ns;
    484     spi_din <= '1';
    485     wait for 160 ns;
    486     spi_din <= '0';
    487     wait for 160 ns;
    488     spi_din <= '0';
    489     wait for 160 ns;
    490 
    491     spi_din <= '1';
    492     wait for 7.68 us;
    493 
    494     -------------------------------
    495 
    496     -- input data for RES cmd 0xAB
    497     spi_din <= '1';
    498     wait for 160 ns;
    499     spi_din <= '0';
    500     wait for 160 ns;
    501     spi_din <= '1';
    502     wait for 160 ns;
    503     spi_din <= '0';
    504     wait for 160 ns;
    505     spi_din <= '1';
    506     wait for 160 ns;
    507     spi_din <= '0';
    508     wait for 160 ns;
    509     spi_din <= '1';
    510     wait for 160 ns;
    511     spi_din <= '1';
    512     wait for 160 ns;
    513 
    514     spi_din <= '1';
    515     wait for 8.0 us;
    516 
    517     -------------------------------
    518 
    519     -- input data for RD cmd 0x01
    520     spi_din <= '0';
    521     wait for 160 ns;
    522     spi_din <= '0';
    523     wait for 160 ns;
    524     spi_din <= '0';
    525     wait for 160 ns;
    526     spi_din <= '0';
    527     wait for 160 ns;
    528     spi_din <= '0';
    529     wait for 160 ns;
    530     spi_din <= '0';
    531     wait for 160 ns;
    532     spi_din <= '0';
    533     wait for 160 ns;
    534     spi_din <= '1';
    535     wait for 160 ns;
    536 
    537     spi_din <= '1';
    538     wait for 480 ns;
    539 
    540     -- input data for RD cmd 0x02
    541     spi_din <= '0';
    542     wait for 160 ns;
    543     spi_din <= '0';
    544     wait for 160 ns;
    545     spi_din <= '0';
    546     wait for 160 ns;
    547     spi_din <= '0';
    548     wait for 160 ns;
    549     spi_din <= '0';
    550     wait for 160 ns;
    551     spi_din <= '0';
    552     wait for 160 ns;
    553     spi_din <= '1';
    554     wait for 160 ns;
    555     spi_din <= '0';
    556     wait for 160 ns;
    557 
    558     spi_din <= '1';
    559     wait for 480 ns;
    560 
    561     -- input data for RD cmd 0x03
    562     spi_din <= '0';
    563     wait for 160 ns;
    564     spi_din <= '0';
    565     wait for 160 ns;
    566     spi_din <= '0';
    567     wait for 160 ns;
    568     spi_din <= '0';
    569     wait for 160 ns;
    570     spi_din <= '0';
    571     wait for 160 ns;
    572     spi_din <= '0';
    573     wait for 160 ns;
    574     spi_din <= '1';
    575     wait for 160 ns;
    576     spi_din <= '1';
    577     wait for 160 ns;
    578 
    579     spi_din <= '1';
    580     wait for 480 ns;
    581 
    582     -- input data for RD cmd 0x04
    583     spi_din <= '0';
    584     wait for 160 ns;
    585     spi_din <= '0';
    586     wait for 160 ns;
    587     spi_din <= '0';
    588     wait for 160 ns;
    589     spi_din <= '0';
    590     wait for 160 ns;
    591     spi_din <= '0';
    592     wait for 160 ns;
    593     spi_din <= '1';
    594     wait for 160 ns;
    595     spi_din <= '0';
    596     wait for 160 ns;
    597     spi_din <= '0';
    598     wait for 160 ns;
    599 
    600     spi_din <= '1';
    601     wait for 480 ns;
    602 
    603     -- input data for RD cmd 0x05
    604     spi_din <= '0';
    605     wait for 160 ns;
    606     spi_din <= '0';
    607     wait for 160 ns;
    608     spi_din <= '0';
    609     wait for 160 ns;
    610     spi_din <= '0';
    611     wait for 160 ns;
    612     spi_din <= '0';
    613     wait for 160 ns;
    614     spi_din <= '1';
    615     wait for 160 ns;
    616     spi_din <= '0';
    617     wait for 160 ns;
    618     spi_din <= '1';
    619     wait for 160 ns;
    620 
    621     spi_din <= '1';
    622     wait for 480 ns;
    623 
    624     -- input data for RD cmd 0x06
    625     spi_din <= '0';
    626     wait for 160 ns;
    627     spi_din <= '0';
    628     wait for 160 ns;
    629     spi_din <= '0';
    630     wait for 160 ns;
    631     spi_din <= '0';
    632     wait for 160 ns;
    633     spi_din <= '0';
    634     wait for 160 ns;
    635     spi_din <= '1';
    636     wait for 160 ns;
    637     spi_din <= '1';
    638     wait for 160 ns;
    639     spi_din <= '0';
    640     wait for 160 ns;
    641 
    642     spi_din <= '1';
    643     wait for 640 ns;
    644 
    645     -- input data for RD cmd 0x07
    646     spi_din <= '0';
    647     wait for 160 ns;
    648     spi_din <= '0';
    649     wait for 160 ns;
    650     spi_din <= '0';
    651     wait for 160 ns;
    652     spi_din <= '0';
    653     wait for 160 ns;
    654     spi_din <= '0';
    655     wait for 160 ns;
    656     spi_din <= '1';
    657     wait for 160 ns;
    658     spi_din <= '1';
    659     wait for 160 ns;
    660     spi_din <= '1';
    661     wait for 160 ns;
    662 
    663     spi_din <= '1';
    664     wait for 480 ns;
    665 
    666     -- input data for RD cmd 0x08
    667     spi_din <= '0';
    668     wait for 160 ns;
    669     spi_din <= '0';
    670     wait for 160 ns;
    671     spi_din <= '0';
    672     wait for 160 ns;
    673     spi_din <= '0';
    674     wait for 160 ns;
    675     spi_din <= '1';
    676     wait for 160 ns;
    677     spi_din <= '0';
    678     wait for 160 ns;
    679     spi_din <= '0';
    680     wait for 160 ns;
    681     spi_din <= '0';
    682     wait for 160 ns;
    683 
    684     spi_din <= '1';
    685     wait for 480 ns;
    686 
    687     -- input data for RD cmd 0x09
    688     spi_din <= '0';
    689     wait for 160 ns;
    690     spi_din <= '0';
    691     wait for 160 ns;
    692     spi_din <= '0';
    693     wait for 160 ns;
    694     spi_din <= '0';
    695     wait for 160 ns;
    696     spi_din <= '1';
    697     wait for 160 ns;
    698     spi_din <= '0';
    699     wait for 160 ns;
    700     spi_din <= '0';
    701     wait for 160 ns;
    702     spi_din <= '1';
    703     wait for 160 ns;
    704 
    705     spi_din <= '1';
    706     wait for 480 ns;
    707 
    708     -- input data for RD cmd 0x0A
    709     spi_din <= '0';
    710     wait for 160 ns;
    711     spi_din <= '0';
    712     wait for 160 ns;
    713     spi_din <= '0';
    714     wait for 160 ns;
    715     spi_din <= '0';
    716     wait for 160 ns;
    717     spi_din <= '1';
    718     wait for 160 ns;
    719     spi_din <= '0';
    720     wait for 160 ns;
    721     spi_din <= '1';
    722     wait for 160 ns;
    723     spi_din <= '0';
    724     wait for 160 ns;
    725 
    726     spi_din <= '1';
    727 
    728     wait;
    729   end process;
    730 end test;


  • 相关阅读:
    hosts 本机DNS域名解析
    五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程
    OracleBulkCopy
    第三方登录(QQ登录)开发流程详解
    Asp.net MVC中Html.Partial, RenderPartial, Action,RenderAction 区别和用法
    MVC Return View() 和 Return PartialView()的区别
    如何选择Html.RenderPartial和Html.RenderAction
    C# Dictionary和Dynamic类型
    css01入门小例子
    html03表单
  • 原文地址:https://www.cnblogs.com/shangdawei/p/2503753.html
Copyright © 2020-2023  润新知