~ruther/vhdl-i2c

ref: 2759cb29fc6b42bad3bbb25c9bbf2273e19ce203 vhdl-i2c/src/i2c/slave_state.vhd -rw-r--r-- 3.9 KiB
2759cb29 — Rutherther feat(tx): remove unnecessary bit index 1 year, 3 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
library ieee;
use ieee.std_logic_1164.all;

entity i2c_slave_state is
  port (
    clk_i                    : in  std_logic;
    rst_in                   : in  std_logic;

    sda_i                    : in  std_logic;
    scl_i                    : in  std_logic;
    scl_pulse_i              : in  std_logic;

    start_condition_i        : in  std_logic;
    stop_condition_i         : in  std_logic;

    rw_i                     : in  std_logic;
    address_detect_success_i : in  std_logic;
    address_detect_fail_i    : in  std_logic;
    address_detect_start_o   : out std_logic;
    address_detect_active_o  : out std_logic;

    expects_ack_o            : out std_logic;
    generate_ack_o           : out std_logic;
    receive_o                : out std_logic;
    transmit_o               : out std_logic;
    start_receive_o          : out std_logic;
    start_transmit_o         : out std_logic
  );
end entity i2c_slave_state;

architecture a1 of i2c_slave_state is
  type slave_state is (
    BUS_FREE,           -- there is no communication on the bus
    BUS_ADDRESS,        -- communication on the bus just started, listening for
                        -- address
    RECEIVING,          -- we are receiving data
    TRANSMITTING,       -- we are transmitting data
    BUS_BUSY);          -- bus is taken, different slave communicating

  signal curr_state : slave_state;
  signal next_state : slave_state;

  constant TRANSMIT_LEN : integer := 9;
  signal curr_data_position : integer range 0 to TRANSMIT_LEN-1;
  signal next_data_position : integer range 0 to TRANSMIT_LEN-1;

  signal communicating_with_master : std_logic;
begin  -- architecture a1

  communicating_with_master <= '1' when curr_state = BUS_ADDRESS or curr_state = RECEIVING or curr_state = TRANSMITTING else '0';

  next_data_position <= 0 when start_condition_i = '1' else
                        0 when stop_condition_i = '1' or curr_state = BUS_FREE else
                        (curr_data_position + 1) mod TRANSMIT_LEN when scl_pulse_i = '1' and communicating_with_master = '1' else
                        curr_data_position;

  generate_ack_o <= '1' when next_data_position = TRANSMIT_LEN - 1 and
                             (curr_state = BUS_ADDRESS or curr_state = RECEIVING)
                    else '0';
  expects_ack_o <= '1' when next_data_position = TRANSMIT_LEN - 1 and
                            (curr_state = TRANSMITTING)
                   else '0';

  address_detect_start_o <= '1' when start_condition_i = '1' else '0';

  receive_o <= '1' when curr_state = RECEIVING else '0';
  transmit_o <= '1' when curr_state = TRANSMITTING else '0';

  start_receive_o <= '1' when curr_data_position /= 0 and next_data_position = 0 and curr_state = RECEIVING else '0';
  start_transmit_o <= '1' when curr_data_position /= 0 and next_data_position = 0 and curr_state = TRANSMITTING else '0';

  next_state <= BUS_ADDRESS when start_condition_i = '1' else
                -- BUS_BUSY when curr_state = BUS_FREE and (sda_i = '0' or scl_i = '0') else --
                  -- assume busy when there is something on the bus?
                BUS_FREE when stop_condition_i = '1' else
                RECEIVING when curr_state = BUS_ADDRESS and address_detect_success_i = '1' and rw_i = '0' else
                TRANSMITTING when curr_state = BUS_ADDRESS and address_detect_success_i = '1' and rw_i = '1' else
                BUS_BUSY when curr_state = BUS_ADDRESS and address_detect_fail_i = '1' else
                curr_state;

  set_regs: process (clk_i) is
  begin  -- process set_regs
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        curr_state <= BUS_FREE;
        curr_data_position <= 0;
      else
        curr_state <= next_state;
        curr_data_position <= next_data_position;
      end if;
    end if;
  end process set_regs;

end architecture a1;
Do not follow this link