• SPI bus master for System09 (2)


      1 --===========================================================================--
      2 --                                                                           --
      3 --             Synthesizable Serial Peripheral Interface Master              --
      4 --                                                                           --
      5 --===========================================================================--
      6 --
      7 --  File name      : spi-master.vhd
      8 --
      9 --  Entity name    : spi-master
     10 --
     11 --  Purpose        : Implements a SPI Master Controller
     12 --                  
     13 --  Dependencies   : ieee.std_logic_1164
     14 --                   ieee.std_logic_unsigned
     15 --
     16 --  Author         : Hans Huebner
     17 --
     18 --  Email          : hans@huebner.org  
     19 --
     20 --  Web            : http://opencores.org/project,system09
     21 --
     22 --  Description    : This core implements a SPI master interface.  
     23 --                   Transfer size is 4, 8, 12 or 16 bits.  
     24 --                   The SPI clock is 0 when idle, sampled on 
     25 --                   the rising edge of the SPI clock.  
     26 --                   The SPI clock is derived from the bus clock input 
     27 --                   divided by 2, 4, 8 or 16.
     28 --
     29 --                   clk, reset, cs, rw, addr, data_in, data_out and irq 
     30 --                   represent the System09 bus interface. 
     31 --                   spi_clk, spi_mosi, spi_miso and spi_cs_n are the 
     32 --                   standard SPI signals meant to be routed off-chip.
     33 --
     34 --                   The SPI core provides for four register addresses 
     35 --                   that the CPU can read or writen to:
     36 --
     37 --                   Base + $00 -> DL: Data Low LSB
     38 --                   Base + $01 -> DH: Data High MSB
     39 --                   Base + $02 -> CS: Command/Status
     40 --                   Base + $03 -> CO: Config
     41 --
     42 --                   CS: Write bits:
     43 --
     44 --                   CS[0]   START : Start transfer
     45 --                   CS[1]   END   : Deselect device after transfer 
     46 --                                   (or immediately if START = '0')
     47 --                   CS[2]   IRQEN : Generate IRQ at end of transfer
     48 --                   CS[6:4] SPIAD : SPI device address
     49 -- 
     50 --                   CS: Read bits
     51 --
     52 --                   CS[0]   BUSY  : Currently transmitting data
     53 --
     54 --                   CO: Write bits
     55 --
     56 --                   CO[1:0] DIVIDE: SPI clock divisor, 
     57 --                                   00=clk/2, 
     58 --                                   01=clk/4,
     59 --                                   10=clk/8,
     60 --                                   11=clk/16
     61 --                   CO[3:2] LENGTH: Transfer length, 
     62 --                                   00= 4 bits, 
     63 --                                   01= 8 bits,
     64 --                                   10=12 bits,
     65 --                                   11=16 bits
     66 --
     67 --  Copyright (C) 2009 - 2010 Hans Huebner
     68 --
     69 --  This program is free software: you can redistribute it and/or modify
     70 --  it under the terms of the GNU General Public License as published by
     71 --  the Free Software Foundation, either version 3 of the License, or
     72 --  (at your option) any later version.
     73 --
     74 --  This program is distributed in the hope that it will be useful,
     75 --  but WITHOUT ANY WARRANTY; without even the implied warranty of
     76 --  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     77 --  GNU General Public License for more details.
     78 --
     79 --  You should have received a copy of the GNU General Public License
     80 --  along with this program.  If not, see <http://www.gnu.org/licenses/>.
     81 --
     82 --
     83 --===========================================================================--
     84 --                                                                           --
     85 --                              Revision  History                            --
     86 --                                                                           --
     87 --===========================================================================--
     88 --
     89 -- Version  Author        Date               Description
     90 --
     91 -- 0.1      Hans Huebner  23 February 2009   SPI bus master for System09 
     92 -- 0.2      John Kent     16 June 2010       Added GPL notice
     93 --
     94 --
     95 
     96 library ieee;
     97 use ieee.std_logic_1164.all;
     98 use ieee.std_logic_unsigned.all;
     99 
    100 entity spi_master is
    101   port (
    102     --
    103     -- CPU Interface Signals
    104     --
    105     clk      : in  std_logic;
    106     reset    : in  std_logic;
    107     cs       : in  std_logic;
    108     rw       : in  std_logic;
    109     addr     : in  std_logic_vector(1 downto 0);
    110     data_in  : in  std_logic_vector(7 downto 0);
    111     data_out : out std_logic_vector(7 downto 0);
    112     irq      : out std_logic;
    113     --
    114     -- SPI Interface Signals
    115     --
    116     spi_miso : in  std_logic;
    117     spi_mosi : out std_logic;
    118     spi_clk  : out std_logic;
    119     spi_cs_n : out std_logic_vector(7 downto 0)
    120   );
    121 end;
    122 
    123 architecture rtl of spi_master is
    124 
    125   -- State type of the SPI transfer state machine
    126   type   state_type is (s_idle, s_running);
    127   signal state : state_type;
    128   -- Shift register
    129   signal shift_reg : std_logic_vector(15 downto 0);
    130   -- Buffer to hold data to be sent
    131   signal spi_data_buf : std_logic_vector(15 downto 0);
    132   -- Start transmission flag
    133   signal start : std_logic;
    134   -- Number of bits transfered
    135   signal count : std_logic_vector(3 downto 0);
    136   -- Buffered SPI clock
    137   signal spi_clk_buf : std_logic;
    138   -- Buffered SPI clock output
    139   signal spi_clk_out : std_logic;
    140   -- Previous SPI clock state
    141   signal prev_spi_clk : std_logic;
    142   -- Number of clk cycles-1 in this SPI clock period
    143   signal spi_clk_count : std_logic_vector(2 downto 0);
    144   -- SPI clock divisor
    145   signal spi_clk_divide : std_logic_vector(1 downto 0);
    146   -- SPI transfer length
    147   signal transfer_length : std_logic_vector(1 downto 0);
    148   -- Flag to indicate that the SPI slave should be deselected after the current
    149   -- transfer
    150   signal deselect : std_logic;
    151   -- Flag to indicate that an IRQ should be generated at the end of a transfer
    152   signal irq_enable : std_logic;
    153   -- Internal chip select signal, will be demultiplexed through the cs_mux
    154   signal spi_cs : std_logic;
    155   -- Current SPI device address
    156   signal spi_addr : std_logic_vector(2 downto 0);
    157 begin
    158 
    159   -- Read CPU bus into internal registers
    160   cpu_write : process(clk, reset)
    161   begin
    162     if reset = '1' then
    163       deselect        <= '0';
    164       irq_enable      <= '0';
    165       start           <= '0';
    166       spi_clk_divide  <= "11";
    167       transfer_length <= "11";
    168       spi_data_buf    <= (others => '0');
    169     elsif falling_edge(clk) then
    170       start <= '0';
    171       if cs = '1' and rw = '0' then
    172         case addr is
    173           when "00" =>
    174             spi_data_buf(7 downto 0) <= data_in;
    175           when "01" =>
    176             spi_data_buf(15 downto 8) <= data_in;
    177           when "10" =>
    178             start      <= data_in(0);
    179             deselect   <= data_in(1);
    180             irq_enable <= data_in(2);
    181             spi_addr   <= data_in(6 downto 4);
    182           when "11" =>
    183             spi_clk_divide  <= data_in(1 downto 0);
    184             transfer_length <= data_in(3 downto 2);
    185           when others =>
    186             null;
    187         end case;
    188       end if;
    189     end if;
    190   end process;
    191 
    192   -- Provide data for the CPU to read
    193   cpu_read : process(shift_reg, addr, state, deselect, start)
    194   begin
    195     data_out <= (others => '0');
    196     case addr is
    197       when "00" =>
    198         data_out <= shift_reg(7 downto 0);
    199       when "01" =>
    200         data_out <= shift_reg(15 downto 8);
    201       when "10" =>
    202         if state = s_idle then
    203           data_out(0) <= '0';
    204         else
    205           data_out(0) <= '1';
    206         end if;
    207         data_out(1) <= deselect;
    208       when others =>
    209         null;
    210     end case;
    211   end process;
    212 
    213   spi_cs_n <= "11111110" when spi_addr = "000" and spi_cs = '1' else
    214               "11111101" when spi_addr = "001" and spi_cs = '1' else
    215               "11111011" when spi_addr = "010" and spi_cs = '1' else
    216               "11110111" when spi_addr = "011" and spi_cs = '1' else
    217               "11101111" when spi_addr = "100" and spi_cs = '1' else
    218               "11011111" when spi_addr = "101" and spi_cs = '1' else
    219               "10111111" when spi_addr = "110" and spi_cs = '1' else
    220               "01111111" when spi_addr = "111" and spi_cs = '1' else
    221               "11111111";
    222 
    223   -- SPI transfer state machine
    224   spi_proc : process(clk, reset)
    225   begin
    226     if reset = '1' then
    227       count        <= (others => '0');
    228       shift_reg    <= (others => '0');
    229       prev_spi_clk <= '0';
    230       spi_clk_out  <= '0';
    231       spi_cs       <= '0';
    232       state        <= s_idle;
    233       irq          <= 'Z';
    234     elsif falling_edge(clk) then
    235       prev_spi_clk <= spi_clk_buf;
    236       irq          <= 'Z';
    237       case state is
    238         when s_idle =>
    239           if start = '1' then
    240             count     <= (others => '0');
    241             shift_reg <= spi_data_buf;
    242             spi_cs    <= '1';
    243             state     <= s_running;
    244           elsif deselect = '1' then
    245             spi_cs <= '0';
    246           end if;
    247         when s_running =>
    248           if prev_spi_clk = '1' and spi_clk_buf = '0' then
    249             spi_clk_out <= '0';
    250             count       <= count + "0001";
    251             shift_reg   <= shift_reg(14 downto 0) & spi_miso;
    252             if ((count = "0011" and transfer_length = "00")
    253               or (count = "0111" and transfer_length = "01")
    254                 or (count = "1011" and transfer_length = "10")
    255                 or (count = "1111" and transfer_length = "11")) then
    256               if deselect = '1' then
    257                 spi_cs <= '0';
    258               end if;
    259               if irq_enable = '1' then
    260                 irq <= '1';
    261               end if;
    262               state <= s_idle;
    263             end if;
    264           elsif prev_spi_clk = '0' and spi_clk_buf = '1' then
    265             spi_clk_out <= '1';
    266           end if;
    267         when others =>
    268           null;
    269       end case;
    270     end if;
    271   end process;
    272 
    273   -- Generate SPI clock
    274   spi_clock_gen : process(clk, reset)
    275   begin
    276     if reset = '1' then
    277       spi_clk_count <= (others => '0');
    278       spi_clk_buf   <= '0';
    279     elsif falling_edge(clk) then
    280       if state = s_running then
    281         if ((spi_clk_divide = "00")
    282           or (spi_clk_divide = "01" and spi_clk_count = "001")
    283             or (spi_clk_divide = "10" and spi_clk_count = "011")
    284             or (spi_clk_divide = "11" and spi_clk_count = "111")) then
    285           spi_clk_buf   <= not spi_clk_buf;
    286           spi_clk_count <= (others => '0');
    287         else
    288           spi_clk_count <= spi_clk_count + "001";
    289         end if;
    290       else
    291         spi_clk_buf <= '0';
    292       end if;
    293     end if;
    294   end process;
    295 
    296   spi_mosi_mux : process(shift_reg, transfer_length)
    297   begin
    298     case transfer_length is
    299       when "00" =>
    300         spi_mosi <= shift_reg(3);
    301       when "01" =>
    302         spi_mosi <= shift_reg(7);
    303       when "10" =>
    304         spi_mosi <= shift_reg(11);
    305       when "11" =>
    306         spi_mosi <= shift_reg(15);
    307       when others =>
    308         null;
    309     end case;
    310   end process;
    311 
    312   spi_clk <= spi_clk_out;
    313 
    314 end rtl;

  • 相关阅读:
    Linux之ARP——种种
    Linux之内核参数——backlog/somaxconn
    CLOSE_WAIT、CLOSE_WAIT原因,危害,如何避免
    OVS——大杂烩
    Linux 网络栈——
    OpenShift——大杂烩
    协议之ICMP——种种
    Neutron 理解 (8): Neutron 是如何实现虚机防火墙的 [How Neutron Implements Security Group]
    Neutron 理解 (6): Neutron 是怎么实现虚拟三层网络的 [How Neutron implements virtual L3 network]
    CIDR地址块及其子网划分(内含原始IP地址分类及其子网划分的介绍)
  • 原文地址:https://www.cnblogs.com/shangdawei/p/2503736.html
Copyright © 2020-2023  润新知