SURF  1.0
SpiMaster.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : SpiMaster.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-05-24
5 -- Last update: 2016-12-06
6 -------------------------------------------------------------------------------
7 -- Description: Generic SPI Master Module
8 -------------------------------------------------------------------------------
9 -- This file is part of 'SLAC Firmware Standard Library'.
10 -- It is subject to the license terms in the LICENSE.txt file found in the
11 -- top-level directory of this distribution and at:
12 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
13 -- No part of 'SLAC Firmware Standard Library', including this file,
14 -- may be copied, modified, propagated, or distributed except according to
15 -- the terms contained in the LICENSE.txt file.
16 -------------------------------------------------------------------------------
17 
18 library ieee;
19 use ieee.std_logic_1164.all;
20 use ieee.std_logic_unsigned.all;
21 use ieee.std_logic_arith.all;
22 use ieee.math_real.all;
23 use work.StdRtlPkg.all;
24 
25 --! @see entity
26  --! @ingroup protocols_spi
27 entity SpiMaster is
28  generic (
29  TPD_G : time := 1 ns;
30  NUM_CHIPS_G : positive range 1 to 8 := 4;
31  DATA_SIZE_G : natural := 16;
32  CPHA_G : sl := '0';
33  CPOL_G : sl := '0';
34  CLK_PERIOD_G : real := 8.0E-9;
35  SPI_SCLK_PERIOD_G : real := 1.0E-6); -- 1 MHz
36  port (
37  --Global Signals
38  clk : in sl;
39  sRst : in sl;
40  -- Parallel interface
41  chipSel : in slv(log2(NUM_CHIPS_G)-1 downto 0);
42  wrEn : in sl;
43  wrData : in slv(DATA_SIZE_G-1 downto 0);
44  dataSize : in slv(log2(DATA_SIZE_G)-1 downto 0) := toSlv(DATA_SIZE_G-1, log2(DATA_SIZE_G));
45  rdEn : out sl;
46  rdData : out slv(DATA_SIZE_G-1 downto 0);
47  shiftCount : out slv(bitSize(DATA_SIZE_G)-1 downto 0);
48  --SPI interface
49  spiCsL : out slv(NUM_CHIPS_G-1 downto 0);
50  spiSclk : out sl;
51  spiSdi : out sl;
52  spiSdo : in sl);
53 end SpiMaster;
54 
55 architecture rtl of SpiMaster is
56 
57  constant SPI_CLK_PERIOD_DIV2_CYCLES_C : integer := integer(SPI_SCLK_PERIOD_G / (2.0*CLK_PERIOD_G));
58  constant SCLK_COUNTER_SIZE_C : integer := bitSize(SPI_CLK_PERIOD_DIV2_CYCLES_C);
59 
60 
61  -- Types
62  type StateType is (
63  IDLE_S,
64  SHIFT_S,
65  SAMPLE_S,
66  DONE_S);
67 
68  type RegType is record
69  state : StateType;
70  rdEn : sl;
71  rdData : slv(DATA_SIZE_G-1 downto 0);
72  wrData : slv(DATA_SIZE_G-1 downto 0);
73  dataCounter : slv(bitSize(DATA_SIZE_G)-1 downto 0);
74  sclkCounter : slv(SCLK_COUNTER_SIZE_C-1 downto 0);
75 
76  spiCsL : slv(NUM_CHIPS_G-1 downto 0);
77  spiSclk : sl;
78  spiSdi : sl;
79  end record RegType;
80 
81  constant REG_INIT_C : RegType := (
82  state => IDLE_S,
83  rdEn => '0',
84  rdData => (others => '0'),
85  wrData => (others => '0'),
86  dataCounter => (others => '0'),
87  sclkCounter => (others => '0'),
88  spiCsL => (others => '1'),
89  spiSclk => '0',
90  spiSdi => '0');
91 
92  signal r : RegType := REG_INIT_C;
93  signal rin : RegType;
94 
95  signal spiSdoRes : sl;
96 
97 begin
98 
99  spiSdoRes <= to_x01z(spiSdo);
100 
101  comb : process (chipSel, dataSize, r, sRst, spiSdoRes, wrData, wrEn) is
102  variable v : RegType;
103  begin
104  v := r;
105 
106  case (r.state) is
107  when IDLE_S =>
108 
109  v.spiSclk := CPOL_G;
110  v.spiSdi := '0';
111  v.dataCounter := (others => '0');
112  v.sclkCounter := (others => '0');
113  v.rdEn := '1'; -- rdEn always valid between txns, indicates ready for next txn
114 
115  if (wrEn = '1') then
116  v.rdEn := '0';
117  v.wrData := wrData;
118  v.rdData := (others => '0');
119  v.spiCsL := not (decode(chipSel)(NUM_CHIPS_G-1 downto 0));
120 
121  if (CPHA_G = '0') then
122  -- Sample on first sclk edge so shift here before that happens
123  v.spiSdi := wrData(DATA_SIZE_G-1);
124  v.wrData := wrData(DATA_SIZE_G-2 downto 0) & '0';
125  v.state := SAMPLE_S;
126  else
127  v.state := SHIFT_S;
128  end if;
129  end if;
130 
131  when SHIFT_S =>
132  -- Wait half a clock period then shift out the next data bit
133  v.sclkCounter := r.sclkCounter + 1;
134  if (r.sclkCounter = SPI_CLK_PERIOD_DIV2_CYCLES_C) then
135  v.sclkCounter := (others => '0');
136  v.spiSclk := not r.spiSclk;
137  v.spiSdi := r.wrData(DATA_SIZE_G-1);
138  v.wrData := r.wrData(DATA_SIZE_G-2 downto 0) & '0';
139  v.state := SAMPLE_S;
140 
141  if (CPHA_G = '0') then
142  v.dataCounter := r.dataCounter + 1;
143  if (r.dataCounter = dataSize) then
144  v.state := DONE_S;
145  end if;
146  end if;
147  end if;
148 
149  when SAMPLE_S =>
150  -- Wait half a clock period then sample the next data bit
151  v.sclkCounter := r.sclkCounter + 1;
152  if (r.sclkCounter = SPI_CLK_PERIOD_DIV2_CYCLES_C) then
153  v.sclkCounter := (others => '0');
154  v.spiSclk := not r.spiSclk;
155  v.rdData := r.rdData(DATA_SIZE_G-2 downto 0) & spiSdoRes;
156  v.state := SHIFT_S;
157 
158  if (CPHA_G = '1') then
159  v.dataCounter := r.dataCounter + 1;
160  if (r.dataCounter = dataSize) then
161  v.state := DONE_S;
162  end if;
163  end if;
164  end if;
165 
166  when DONE_S =>
167  -- Assert rdEn after half a SPI clk period
168  -- Go back to idle after one SPI clk period
169  -- Otherwise back to back operations happen too fast.
170  v.sclkCounter := r.sclkCounter + 1;
171  if (r.sclkCounter = SPI_CLK_PERIOD_DIV2_CYCLES_C) then
172  v.sclkCounter := (others => '0');
173  v.spiCsL := (others => '1');
174 
175  if (r.spiCsL = slvOne(NUM_CHIPS_G)) then
176  v.state := IDLE_S;
177  end if;
178  end if;
179  when others => null;
180  end case;
181 
182  if (sRst = '1') then
183  v := REG_INIT_C;
184  end if;
185 
186  rin <= v;
187 
188  spiSclk <= r.spiSclk;
189  spiSdi <= r.spiSdi;
190  spiCsL <= r.spiCsL;
191 
192  rdEn <= r.rdEn;
193  rdData <= r.rdData;
194  shiftCount <= r.dataCounter;
195 
196  end process comb;
197 
198  seq : process (clk) is
199  begin
200  if (rising_edge(clk)) then
201  r <= rin after TPD_G;
202  end if;
203  end process seq;
204 
205 end rtl;
out spiCsLslv( NUM_CHIPS_G- 1 downto 0)
Definition: SpiMaster.vhd:49
in wrDataslv( DATA_SIZE_G- 1 downto 0)
Definition: SpiMaster.vhd:43
std_logic sl
Definition: StdRtlPkg.vhd:28
out rdDataslv( DATA_SIZE_G- 1 downto 0)
Definition: SpiMaster.vhd:46
in wrEnsl
Definition: SpiMaster.vhd:42
SPI_SCLK_PERIOD_Greal := 1.0E-6
Definition: SpiMaster.vhd:35
out rdEnsl
Definition: SpiMaster.vhd:45
in chipSelslv( log2(NUM_CHIPS_G )- 1 downto 0)
Definition: SpiMaster.vhd:41
CPHA_Gsl := '0'
Definition: SpiMaster.vhd:32
in spiSdosl
Definition: SpiMaster.vhd:52
CPOL_Gsl := '0'
Definition: SpiMaster.vhd:33
in dataSizeslv( log2(DATA_SIZE_G )- 1 downto 0) := toSlv( DATA_SIZE_G- 1, log2(DATA_SIZE_G ))
Definition: SpiMaster.vhd:44
TPD_Gtime := 1 ns
Definition: SpiMaster.vhd:29
NUM_CHIPS_Gpositive range 1 to 8:= 4
Definition: SpiMaster.vhd:30
out shiftCountslv( bitSize(DATA_SIZE_G )- 1 downto 0)
Definition: SpiMaster.vhd:47
_library_ ieeeieee
out spiSclksl
Definition: SpiMaster.vhd:50
DATA_SIZE_Gnatural := 16
Definition: SpiMaster.vhd:31
out spiSdisl
Definition: SpiMaster.vhd:51
in clksl
Definition: SpiMaster.vhd:38
in sRstsl
Definition: SpiMaster.vhd:39
CLK_PERIOD_Greal := 8.0E-9
Definition: SpiMaster.vhd:34
std_logic_vector slv
Definition: StdRtlPkg.vhd:29