@@ -30,8 +30,6 @@ architecture model of i2c_peripheral is
30
30
31
31
type state_t is (
32
32
IDLE,
33
- GET_START_BYTE,
34
- GET_REG_BYTE,
35
33
SEND_ACK,
36
34
SEND_NACK,
37
35
SEND_BYTE,
@@ -43,55 +41,153 @@ architecture model of i2c_peripheral is
43
41
signal state : state_t := IDLE;
44
42
45
43
signal start_condition : std_logic := '0' ;
44
+ signal stop_condition : std_logic := '0' ;
45
+ signal sda_last : std_logic := 'H' ;
46
46
signal rx_data : std_logic_vector (7 downto 0 ) := (others => '0' );
47
47
signal rx_bit_count : unsigned (3 downto 0 ) := (others => '0' );
48
48
signal rx_done : std_logic := '0' ;
49
+ signal rx_ackd : boolean := FALSE ;
50
+ signal tx_data : std_logic_vector (7 downto 0 ) := (others => '0' );
51
+ signal tx_bit_count : unsigned (3 downto 0 ) := (others => '0' );
52
+ signal tx_done : std_logic := '0' ;
53
+
54
+ signal in_receiving_state : boolean := FALSE ;
55
+ signal in_transmitting_state : boolean := FALSE ;
49
56
begin
50
57
51
- start_condition <= '1' when sda = '0' and state = IDLE else '0' ;
58
+ start_condition <= '1' when sda_last = 'H' and sda = '0' and scl = 'H' else '0' ;
59
+ stop_condition <= '1' when sda_last = '0' and sda = 'H' and scl = 'H' else '0' ;
60
+
61
+ -- message_handler: process
62
+ -- variable msg_type : msg_type_t;
63
+ -- variable request_msg, reply_msg : msg_t;
64
+ -- begin
65
+ -- receive(net, i2c_peripheral_vc.p_actor, request_msg);
66
+ -- msg_type := message_type(request_msg);
67
+ -- end process;
52
68
53
- message_handler : process
54
- variable msg_type : msg_type_t;
55
- variable request_msg, reply_msg : msg_t;
69
+ -- sample SDA regularly to catch transitions
70
+ sda_monitor : process
56
71
begin
57
- receive(net, i2c_peripheral_vc.p_actor, request_msg) ;
58
- msg_type := message_type(request_msg) ;
72
+ wait for 20 ns ;
73
+ sda_last <= sda ;
59
74
end process ;
60
75
61
76
transaction_sm : process
62
- variable event_msg : msg_t;
77
+ variable event_msg : msg_t;
78
+ variable is_read : boolean := FALSE ;
63
79
begin
80
+ -- IDLE: wait for a START
64
81
wait on start_condition;
65
82
event_msg := new_msg(got_start);
66
83
send(net, i2c_peripheral_vc.p_actor, event_msg);
84
+ state <= GET_BYTE;
67
85
68
- state <= GET_START_BYTE;
86
+ -- GET_BYTE: check address and acknowledge appropriately
69
87
wait on rx_done;
88
+ wait until falling_edge (scl);
70
89
if rx_data(7 downto 1 ) = i2c_peripheral_vc.address then
71
90
state <= SEND_ACK;
91
+ is_read := rx_data(0 ) = '1' ;
72
92
event_msg := new_msg(address_matched);
73
93
send(net, i2c_peripheral_vc.p_actor, event_msg);
74
94
else
75
95
state <= SEND_NACK;
76
96
event_msg := new_msg(address_different);
77
97
send(net, i2c_peripheral_vc.p_actor, event_msg);
78
98
end if ;
99
+
100
+ -- SEND_ACK/NACK: acknowledge the START byte
101
+ wait until falling_edge (scl);
102
+ if state = SEND_ACK then
103
+ if is_read then
104
+ state <= SEND_BYTE;
105
+ else
106
+ state <= GET_BYTE;
107
+ end if ;
108
+ else
109
+ -- NACK'd
110
+ state <= GET_STOP;
111
+ end if ;
112
+ wait until rising_edge (scl);
113
+
114
+ if is_read then
115
+ -- loop to respond to a controller read request
116
+ while state /= GET_STOP loop
117
+ -- SEND_BYTE: send the byte and then wait for an acknowledge
118
+ wait on tx_done;
119
+ wait until rising_edge (scl);
120
+ state <= GET_ACK;
121
+
122
+ -- GET_ACK: see if the controller wants to continue reading or is finished
123
+ wait on rx_done;
124
+ state <= SEND_BYTE when rx_ackd else GET_STOP;
125
+ end loop ;
126
+ end if ;
127
+
128
+ -- GET_STOP: wait for a STOP
129
+ wait on stop_condition;
130
+ event_msg := new_msg(got_stop);
131
+ send(net, i2c_peripheral_vc.p_actor, event_msg);
132
+ state <= IDLE;
79
133
end process ;
80
134
81
- rx_done <= '1' when rx_bit_count = 8 else '0' ;
135
+ in_receiving_state <= state = GET_BYTE or state = GET_ACK;
136
+ rx_done <= '1' when (state = GET_BYTE and rx_bit_count = 8 ) or
137
+ (state = GET_ACK and rx_bit_count = 1 )
138
+ else '0' ;
82
139
83
140
receive_sm : process
84
141
variable data_next : std_logic_vector (7 downto 0 ) := (others => '0' );
142
+ variable sda_v : std_logic ;
85
143
begin
86
144
wait until rising_edge (scl);
87
- if state = GET_START_BYTE then
88
- data_next := sda & rx_data(7 downto 1 );
89
- rx_bit_count <= rx_bit_count + 1 ;
90
- else
145
+
146
+ if rx_done then
91
147
rx_bit_count <= (others => '0' );
148
+ elsif state = GET_ACK then
149
+ -- '0' = ACK, 'H' = NACK
150
+ rx_ackd <= TRUE when sda = '0' else FALSE ;
151
+ rx_bit_count <= to_unsigned (1 , rx_bit_count'length );
152
+ elsif state = GET_BYTE then
153
+ sda_v := '1' when sda = 'H' else '0' ;
154
+ data_next := sda_v & rx_data(7 downto 1 );
155
+ rx_bit_count <= rx_bit_count + 1 ;
92
156
end if ;
93
157
94
158
rx_data <= data_next;
95
159
end process ;
96
160
161
+
162
+ in_transmitting_state <= state = SEND_ACK or state = SEND_NACK or state = SEND_BYTE;
163
+ tx_done <= '1' when ((state = SEND_ACK or state = SEND_ACK) and tx_bit_count = 1 ) or
164
+ (state = SEND_BYTE and tx_bit_count = 8 )
165
+ else '0' ;
166
+
167
+ transmit_sm : process
168
+ variable data_next : std_logic_vector (7 downto 0 ) := X"CC" ;
169
+ begin
170
+ if tx_done then
171
+ tx_bit_count <= (others => '0' );
172
+ end if ;
173
+
174
+ wait until falling_edge (scl);
175
+ -- delay the SDA transition to a bit after SCL falls to allow the controller to release SDA
176
+ wait for 25 ns ;
177
+
178
+ if tx_done then
179
+ -- release bus
180
+ sda <= 'H' ;
181
+ elsif state = SEND_ACK or state = SEND_NACK then
182
+ sda <= '0' when state = SEND_ACK else 'H' ;
183
+ tx_bit_count <= to_unsigned (1 , tx_bit_count'length );
184
+ elsif state = SEND_BYTE then
185
+ sda <= 'H' when data_next(to_integer (tx_bit_count)) = '1' else '0' ;
186
+ tx_bit_count <= tx_bit_count + 1 ;
187
+ end if ;
188
+
189
+ wait until rising_edge (scl);
190
+
191
+ end process ;
192
+
97
193
end architecture ;
0 commit comments