~ruther/vhdl-spi

ref: e8d0cfa4c8f015cb4375bf6a9081ab2b2663ed36 vhdl-spi/src/spi_transmit.vhd -rw-r--r-- 5.4 KiB
e8d0cfa4 — František Boháček feat: add spi_slave connecting spi_recv and spi_transmit 1 year, 10 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
library ieee;
use ieee.std_logic_1164.all;

entity spi_transmit is

  generic (
    WIDTH : integer := 8;
    ALIGN_START : std_logic := '1');

  port (
    clk_i           : in  std_logic;    -- Clock
    rst_in          : in  std_logic;    -- Asynchronous reset, active low
    transmit_data_i : in  std_logic_vector(WIDTH - 1 downto 0);  -- The data to
                                                                 -- transmit.
                                                                 -- Change only
                                                                 -- if ready_o
                                                                 -- is '1'.
    valid_i      : in  std_logic;    -- Pulse to signal new data are present
                                        -- in transmit_data. Data has to change
                                        -- only if ready_o is '1'
    ready_o         : out std_logic;    -- Signals that the transmitter is
                                        -- ready for new data on `transmit_data_i``.
    transmitting_o  : out std_logic;    -- Signals that the transmitter is
                                        -- currently transmitting data
    transmit_bit_o  : out std_logic);   -- The bit to transmit (on master MOSI)

end entity spi_transmit;

architecture a1 of spi_transmit is
  signal store_data_in_sr : std_logic;  -- should data be stored in the
                                            -- shift register next clock cycle?

  signal transmit_bit_falling : std_logic;
  signal sr_q_o : std_logic;

  signal data_bit_index_reg : integer range 0 to WIDTH;
  signal data_bit_index_next : integer range 0 to WIDTH;

  type state is (IDLE, WAITING, SINGLE_TRANSMISSION, CONTINUOUS_TRANSMISSION);
  -- IDLE - not sending anything
  -- WAITING - waiting for the right moment to send - data_bit_index = 0
  -- SINGLE_TRANSMISSION - just one data currently loaded into the shift register
  -- CONTINUOUS_TRANSMISSION - one data currently being sent, and another data
  -- loaded into the shift register, and another ready to be sent

  signal state_reg : state;
  signal state_next : state;

  signal can_begin_transmission_next : std_logic;
begin  -- architecture a1
  transmit_bit_o <= sr_q_o when state_reg = SINGLE_TRANSMISSION and data_bit_index_reg = 1 else
                    transmit_bit_falling when state_reg /= IDLE else
                    sr_q_o;

  can_begin_transmission_next <= '1' when data_bit_index_reg = 0 else '0';

  -- in IDLE, go to
  --   -- SINGLE_TRANSMISSION if data valid, and can start transmission
  --   -- WAITING if data valid, and cannot start transmission
  --   -- IDLE
  -- in WAITING, go to
  --   -- SINGLE_TRANSMISSION if can start transmission
  --   -- WAITING
  -- in SINGLE_TRANSMISSION, go to
  --   -- CONTINUOUS_TRANSMISSION if data valid and cannot begin new transmission
  --   -- SINGLE_TRANSMISSION if data valid and can begin new transmission
  --   -- IDLE if transmission done
  --   -- SINGLE_TRANSMISSION if transmission ongoing
  -- in CONTINUOUS_TRANSMISSION, go to
  --   -- CONTINUOUS_TRANSMISSION if cannot begin new transmission
  --   -- SINGLE_TRANSMISSION if can begin new transmission

  state_next <= SINGLE_TRANSMISSION when state_reg = IDLE and valid_i = '1' and can_begin_transmission_next = '1' else
                WAITING when state_reg = IDLE and valid_i = '1' else
                SINGLE_TRANSMISSION when state_reg = WAITING and can_begin_transmission_next = '1'  else
                WAITING when state_reg = WAITING else
                SINGLE_TRANSMISSION when state_reg = SINGLE_TRANSMISSION and valid_i = '1' and can_begin_transmission_next = '1' else
                CONTINUOUS_TRANSMISSION when state_reg = SINGLE_TRANSMISSION and valid_i = '1' else
                SINGLE_TRANSMISSION when state_reg = SINGLE_TRANSMISSION and data_bit_index_reg /= 0 else
                CONTINUOUS_TRANSMISSION when state_reg = CONTINUOUS_TRANSMISSION and can_begin_transmission_next = '0' else
                SINGLE_TRANSMISSION when state_reg = CONTINUOUS_TRANSMISSION and can_begin_transmission_next = '1' else
                IDLE;

  store_data_in_sr <= '1' when data_bit_index_reg = 0 and state_next /= IDLE else '0';
  ready_o <= '1' when state_reg /= CONTINUOUS_TRANSMISSION else '0';
  transmitting_o <= '1' when state_next = SINGLE_TRANSMISSION or state_next = CONTINUOUS_TRANSMISSION else '0';

  data_bit: if ALIGN_START = '1' generate
    data_bit_index_next <= (data_bit_index_reg + 1) mod WIDTH;
  else generate
    data_bit_index_next <= (data_bit_index_reg + 1) mod WIDTH when state_reg /= IDLE else
                           0;
  end generate data_bit;

  store_next: process (clk_i) is
  begin  -- process store_next
    if rst_in = '0' then              -- synchronous reset (active low)
      data_bit_index_reg <= 0;
      state_reg <= IDLE;
    elsif rising_edge(clk_i) then          -- rising clock edge
      data_bit_index_reg <= data_bit_index_next;
      state_reg <= state_next;
    end if;
  end process store_next;

  store_falling: process (clk_i) is
  begin  -- process store_falling
    if falling_edge(clk_i) then
      transmit_bit_falling <= sr_q_o;
    end if;
  end process store_falling;

  sr: entity work.piso_shift_register
    generic map (
      WIDTH => WIDTH)
    port map (
      clk_i => clk_i,
      data_i => transmit_data_i,
      store_i => store_data_in_sr,
      q_o => sr_q_o
    );

end architecture a1;
Do not follow this link