summaryrefslogtreecommitdiff
path: root/FPGA/vhdl/i2c_master.vhd
blob: 99b179b7e078050224b0ba6a6635d334284999ab (plain)
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity i2C_master is  
  generic (
    system_frequency   : real := 50.0E6;   -- 50 MHz
	  i2c_rate           : real := 20.0E3    -- 20 kHz	
  );
  port (
    clk     : in    std_logic;
	  resetn  : in    std_logic;
  	 go      : in    std_logic;
   	ready   : out   std_logic;
	  data_in : in    std_logic_vector(23 downto 0); -- adress & command & data
	  ack     : out   std_logic;
	  -- i2c 
	  i2c_scl : out   std_logic;              -- A6
	  i2c_sda : inout std_logic               -- B6
  );
end entity;

architecture rtl of i2c_master is
  constant mod_ctr_tempo : positive := integer(system_frequency/(2.0*i2c_rate));
  constant mod_ctr_bit   : positive := 35;
  type state is (wait_for_go, wait_for_i2clk, tx);
  signal current_state : state; 
  signal next_state    : state;  
  signal sdo           : std_logic;  
  signal ctr_tempo     : natural range 0 to mod_ctr_tempo-1;
  signal end_tempo     : std_logic;
  signal ctr_bit       : natural range 0 to mod_ctr_bit-1;
  signal ack1          : std_logic;
  signal ack2          : std_logic;
  signal ack3          : std_logic;
  signal reg_data      : std_logic_vector(data_in'range);
  signal cmd_data      : std_logic_vector(1 downto 0);
  signal cmd_bit       : std_logic_vector(1 downto 0);
  signal cmd_ack1      : std_logic_vector(1 downto 0);
  signal cmd_ack2      : std_logic_vector(1 downto 0);
  signal cmd_ack3      : std_logic_vector(1 downto 0);
  signal sclk          : std_logic;  
  signal i2c_clk       : std_logic;
  signal ready_i       : std_logic;
  
begin
 i2c_sda   <= 'Z'     when sdo = '1' 
              else '0';
 i2c_scl   <= '1' when sclk='1' 
              else  not i2c_clk when (ctr_bit>=4 and ctr_bit <= 30)
              else '0';
 ack       <= ack1 or ack2 or ack3;	
 end_tempo <= '0' when ctr_tempo< mod_ctr_tempo-1 else '1';
 
 process(resetn, clk) is
 begin
   if resetn = '0'        then 
	  i2c_clk   <= '0';
	  ctr_tempo <= 0;
	  ctr_bit   <= 0;
	  reg_data  <= (others => '0');
	  --sclk      <= '1';
	  ACK1      <= '0';
	  ACK2      <= '0';
	  ACK3      <= '0'; 
	  ready     <= '1';
	  current_state <= wait_for_go;
  elsif rising_edge(clk) then
    current_state <= next_state;
    ready         <= ready_i;
    
    -- temporisation et i2_clk
    if current_state = wait_for_go then
       ctr_tempo <= 0;
       i2c_clk   <= '0';
    elsif end_tempo='0' then 
  	    ctr_tempo <= ctr_tempo +1;
  	 else    
  	    ctr_tempo <= 0;
  		   i2c_clk   <= not i2c_clk;
  	 end if;	 
  	 -- reg_data
  	 case cmd_data is
	    when "10"   => reg_data <= data_in;	                  
	    when "11"   => reg_data <= reg_data(22 downto 0)&'0';
	    when others => null;  
	  end case;
    --  ctr_bit
    case cmd_bit is
      when "10"   => ctr_bit <= 0;	                  
	    when "11"   =>  if ctr_bit<mod_ctr_bit-1 then ctr_bit       <= ctr_bit+1;
                      else                          ctr_bit       <= 0;
                      end if;
	    when others => null;  
    end case;
   -- ack1
    case cmd_ack1 is
	    when "10"   => ack1 <= '0';	                  
	    when "11"   => ack1 <= '1';
	    when others => null;  
	  end case;
	 -- ack2
    case cmd_ack2 is
	    when "10"   => ack2 <= '0';	                  
	    when "11"   => ack2 <= '1';
	    when others => null;  
	  end case;
	  -- ack1
    case cmd_ack3 is
	    when "10"   => ack3 <= '0';	                  
	    when "11"   => ack3 <= '1';
	    when others => null;  
	  end case;
  end if;
end process;	   
--------------------------------
-- FSM
-------------------------------
process(current_state, end_tempo, i2c_clk, go,reg_data(23), i2c_sda,ctr_bit) is
begin
  next_state <= current_state;
  ready_i    <= '0';
  cmd_ack1   <= "00";
  cmd_ack2   <= "00";
  cmd_ack3   <= "00";
  cmd_bit    <= "00";
  cmd_data   <= "00";
  sdo        <= '1';
  sclk       <= '0';
  case current_state is
    when wait_for_go    => if go = '1' then next_state <=wait_for_i2clk; 
                           end if;
                           ready_i <= '1';                           
                           cmd_bit    <= "10";
                           cmd_data   <= "10";
                           sclk       <= '1';
    when wait_for_i2clk => if i2c_clk='0' and end_tempo='1' then  next_state <=tx;   
                           end if;
                           cmd_ack1   <= "10";
                           cmd_ack2   <= "10";
                           cmd_ack3   <= "10";
                           sclk       <= '1';
    when tx             => if ctr_bit< mod_ctr_bit-1 then
                               if i2c_clk='0' and end_tempo='1'then                              
                                cmd_bit    <= "11";  
                               end if;                                
                           elsif end_tempo='1'then                                 
                                next_state <= wait_for_go;                                
                          end if;      
                          case ctr_bit is 
                             when      0 => sdo  <= '1'; sclk <= '1';
                          			-- start
                          			when      1 => sdo  <= '0'; sclk <= '0';
                          			when      2 => sdo  <= '0'; sclk <= '0';
                          			-- slave address
                          			when      3 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when      4 => sdo  <= reg_data(23);
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when      5 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when      6 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when      7 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when      8 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when      9 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     10 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     11 => sdo  <= '1';         -- ack

                          			-- command
                          			when     12 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			               if i2c_sda='1' then cmd_ack1 <= "11" ;
                          			               else                cmd_ack1 <= "10" ;
                        			                 end if;
                          			when     13 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     14 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     15 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     16 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     17 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     18 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     19 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     20 => sdo  <= '1';         -- ack
                          			-- data
                          			when     21 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			               if i2c_sda='1' then cmd_ack2 <= "11" ;
                          			               else                cmd_ack2 <= "10" ;
                        			                 end if;                                			
                        			  when     22 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     23 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     24 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     25 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     26 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     27 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     28 => sdo  <= reg_data(23); 
                          			               if i2c_clk='0' and end_tempo='1'then cmd_data   <= "11";
                        			                 end if;
                          			when     29 => sdo  <= '1';         -- ack
                          			--stop
                          			when     30 => sdo  <= '0'; 
                          			               if i2c_sda='1' then cmd_ack3 <= "11" ;
                        			                 else                cmd_ack3 <= "10" ;
                        			                 end if; 
                        			                 sclk <= '0';
                          			when     31 => sdo  <= '0'; sclk <= '1';
                      			    when others => sdo  <= '1'; sclk <= '1';    				 
                          end case;                               
                              
                            
  end case;
    
end process;
     
end architecture;