1 -- Module Name: i2c_core.vhd
2 -- File Description: Generic i2c module with write capability only.
3 -- Project: FPGA Image Registration
4 -- Target Device: XC5VSX50T (Xilinx Virtex5 SXT)
6 -- Synthesis Tool: Xilinx ISE 9.2
7 -- Copyright (C) 2008 Brandyn Allen White
8 -- Contact: bwhite(at)cs.ucf.edu
9 -- Project Website: http://code.google.com/p/fpga-image-registration/
11 -- This program is free software: you can redistribute it and/or modify
12 -- it under the terms of the GNU General Public License as published by
13 -- the Free Software Foundation, either version 3 of the License, or
14 -- (at your option) any later version.
16 -- This program is distributed in the hope that it will be useful,
17 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
18 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 -- GNU General Public License for more details.
21 -- You should have received a copy of the GNU General Public License
22 -- along with this program. If not, see <http://www.gnu.org/licenses/>.
24 -- NOTE The data is in little endian byte ordering, data is sent lowest byte
25 -- first, highest bit first (I2C convention).
28 USE IEEE.STD_LOGIC_1164.ALL;
29 USE IEEE.STD_LOGIC_ARITH.ALL;
30 USE IEEE.STD_LOGIC_UNSIGNED.ALL;
34 PORT (clk : IN std_logic;
35 data : IN std_logic_vector (23 DOWNTO 0);
36 new_data : IN std_logic;
38 i2c_sda : OUT std_logic;
39 i2c_scl : OUT std_logic;
40 received_data : OUT std_logic);
43 ARCHITECTURE Behavioral OF i2c_core IS
44 SIGNAL cur_data : std_logic_vector (23 DOWNTO 0); -- {device_id(7 downto 0), address(7 downto 0), data(7 downto 0)}
45 SIGNAL i2c_state : std_logic_vector (2 DOWNTO 0) := (OTHERS => '0'); -- {START, DATA, POST_DATA, STOP, STOP_WAIT, X, X, X}
46 SIGNAL byte_position : std_logic_vector(1 DOWNTO 0) := (OTHERS => '0'); -- {device_id, address, data, X}
47 SIGNAL bit_position : std_logic_vector(2 DOWNTO 0) := (OTHERS => '0');
48 SIGNAL received_data_reg : std_logic := '0';
49 SIGNAL i2c_sda_reg : std_logic := '1';
51 -- I2C Clock Variables
52 SIGNAL i2c_clock_counter : std_logic_vector (8 DOWNTO 0) := (OTHERS => '0'); -- [0,499]
53 SIGNAL i2c_edge_count : std_logic_vector (2 DOWNTO 0) := (OTHERS => '0'); -- [0,4]
54 SIGNAL i2c_clock : std_logic := '1';
55 SIGNAL i2c_clock_5x : std_logic := '1';
56 SIGNAL i2c_clock_5x_posedge : std_logic := '1';
59 i2c_scl <= '0' WHEN i2c_clock = '0' ELSE 'Z'; -- Output using {0,Z logic}
60 i2c_sda <= '0' WHEN i2c_sda_reg = '0' ELSE 'Z'; -- Output using {0,Z logic}
61 received_data <= received_data_reg;
65 IF (clk'event AND clk = '1') THEN
66 -- Set initial register values upon synchronous reset
68 i2c_state <= (OTHERS => '0');
69 byte_position <= (OTHERS => '0');
70 bit_position <= (OTHERS => '0');
71 received_data_reg <= '0';
74 -- I2C Clock Variables
75 i2c_clock_counter <= (OTHERS => '0');
76 i2c_edge_count <= (OTHERS => '0');
79 i2c_clock_5x_posedge <= '1';
81 -- If we are supposed to start; however, no data is ready, then reset the clock logic to hold it high
82 IF (i2c_state = "000" AND new_data = '0') THEN
84 received_data_reg <= '0';
86 -- I2C Clock Variables
87 i2c_clock_counter <= (OTHERS => '0');
88 i2c_edge_count <= (OTHERS => '0');
91 i2c_clock_5x_posedge <= '1';
93 -- I2C Clock generation - Reduces clock rate by 100 for internal use and 500 for external use.
94 IF (i2c_clock_counter = 99 OR i2c_clock_counter = 199 OR i2c_clock_counter = 299 OR i2c_clock_counter = 399 OR i2c_clock_counter = 499) THEN
95 i2c_clock_5x <= NOT i2c_clock_5x;
96 IF (i2c_clock_5x = '0') THEN
97 i2c_clock_5x_posedge <= '1';
98 IF (i2c_edge_count < 4) THEN
99 i2c_edge_count <= i2c_edge_count + 1;
101 i2c_edge_count <= (OTHERS => '0');
106 -- Toggle the external I2C clock every 500 ticks
107 IF (i2c_clock_counter = 499) THEN
108 i2c_clock_counter <= (OTHERS => '0');
109 i2c_clock <= NOT i2c_clock;
111 i2c_clock_counter <= i2c_clock_counter + 1;
116 IF (i2c_clock_5x_posedge = '1') THEN
117 i2c_clock_5x_posedge <= '0';
118 CASE i2c_edge_count IS -- Edge selection -> individual state selection
120 IF (i2c_state = "011") THEN -- STATE: stop
122 i2c_state <= "000"; -- 'start'
125 IF (i2c_state = "000") THEN -- STATE: start
126 IF (new_data = '1' AND received_data_reg = '0') THEN
129 received_data_reg <= '1';
130 i2c_state <= "001"; -- 'data'
136 WHEN "001" => -- STATE: data
137 CASE bit_position IS -- Select bit position and output it (NOTE: MSB is output first!), TODO investigate other bit selection methods
139 i2c_sda_reg <= cur_data(7);
141 i2c_sda_reg <= cur_data(6);
143 i2c_sda_reg <= cur_data(5);
145 i2c_sda_reg <= cur_data(4);
147 i2c_sda_reg <= cur_data(3);
149 i2c_sda_reg <= cur_data(2);
151 i2c_sda_reg <= cur_data(1);
153 i2c_sda_reg <= cur_data(0);
157 bit_position <= bit_position + 1;
158 IF (bit_position = "111") THEN
159 i2c_state <= "010"; -- 'post_data'
161 i2c_state <= "001"; -- 'data'
163 WHEN "010" => -- STATE: post_data
164 cur_data(15 DOWNTO 0) <= cur_data(23 DOWNTO 8); -- Shift right by 8, TODO investigate other shifting methods
166 IF (byte_position = 2) THEN
167 byte_position <= (OTHERS => '0');
170 byte_position <= byte_position + 1;
173 WHEN "100" => -- STATE: stop_wait
175 i2c_state <= "011"; -- 'stop'
184 -- Data synchronization acknowledgement
185 IF (new_data = '0' AND received_data_reg = '1') THEN
186 received_data_reg <= '0';