DVI support -- initial demo works
[fleet.git] / src / edu / berkeley / fleet / fpga / dvi / i2c_core.vhd
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)
5 -- Target Board:  ML506
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/
10
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.
15
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.
20
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/>.
23
24 -- NOTE The data is in little endian byte ordering, data is sent lowest byte
25 -- first, highest bit first (I2C convention).
26
27 LIBRARY IEEE;
28 USE IEEE.STD_LOGIC_1164.ALL;
29 USE IEEE.STD_LOGIC_ARITH.ALL;
30 USE IEEE.STD_LOGIC_UNSIGNED.ALL;
31
32
33 ENTITY i2c_core IS
34   PORT (clk           : IN  std_logic;
35         data          : IN  std_logic_vector (23 DOWNTO 0);
36         new_data      : IN  std_logic;
37         reset         : IN  std_logic;
38         i2c_sda       : OUT std_logic;
39         i2c_scl       : OUT std_logic;
40         received_data : OUT std_logic);
41 END i2c_core;
42
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';
50
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';
57
58 BEGIN
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;
62
63   PROCESS(clk)
64   BEGIN
65     IF (clk'event AND clk = '1') THEN
66       -- Set initial register values upon synchronous reset
67       IF (reset = '1') THEN
68         i2c_state         <= (OTHERS => '0');
69         byte_position     <= (OTHERS => '0');
70         bit_position      <= (OTHERS => '0');
71         received_data_reg <= '0';
72         i2c_sda_reg       <= '1';
73
74         -- I2C Clock Variables
75         i2c_clock_counter    <= (OTHERS => '0');
76         i2c_edge_count       <= (OTHERS => '0');
77         i2c_clock            <= '1';
78         i2c_clock_5x         <= '1';
79         i2c_clock_5x_posedge <= '1';
80       ELSE
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
83           i2c_sda_reg       <= '1';
84           received_data_reg <= '0';
85
86                                         -- I2C Clock Variables
87           i2c_clock_counter    <= (OTHERS => '0');
88           i2c_edge_count       <= (OTHERS => '0');
89           i2c_clock            <= '1';
90           i2c_clock_5x         <= '1';
91           i2c_clock_5x_posedge <= '1';
92         ELSE
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;
100               ELSE
101                 i2c_edge_count <= (OTHERS => '0');
102               END IF;
103             END IF;
104           END IF;
105
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;
110           ELSE
111             i2c_clock_counter <= i2c_clock_counter + 1;
112           END IF;
113         END IF;
114
115         -- Main I2C Logic
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
119             WHEN "001" =>
120               IF (i2c_state = "011") THEN      -- STATE: stop
121                 i2c_sda_reg <= '1';
122                 i2c_state   <= "000";   -- 'start'
123               END IF;
124             WHEN "010" =>
125               IF (i2c_state = "000") THEN      -- STATE: start
126                 IF (new_data = '1' AND received_data_reg = '0') THEN
127                   i2c_sda_reg       <= '0';
128                   cur_data          <= data;
129                   received_data_reg <= '1';
130                   i2c_state         <= "001";  -- 'data'
131                 END IF;
132               END IF;
133
134             WHEN "100" =>
135               CASE i2c_state IS
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
138                     WHEN "000" =>
139                       i2c_sda_reg <= cur_data(7);
140                     WHEN "001" =>
141                       i2c_sda_reg <= cur_data(6);
142                     WHEN "010" =>
143                       i2c_sda_reg <= cur_data(5);
144                     WHEN "011" =>
145                       i2c_sda_reg <= cur_data(4);
146                     WHEN "100" =>
147                       i2c_sda_reg <= cur_data(3);
148                     WHEN "101" =>
149                       i2c_sda_reg <= cur_data(2);
150                     WHEN "110" =>
151                       i2c_sda_reg <= cur_data(1);
152                     WHEN "111" =>
153                       i2c_sda_reg <= cur_data(0);
154                     WHEN OTHERS =>
155                       NULL;
156                   END CASE;
157                       bit_position <= bit_position + 1;
158                       IF (bit_position = "111") THEN
159                         i2c_state <= "010";  -- 'post_data'
160                       ELSE
161                         i2c_state <= "001";  -- 'data'
162                       END IF;
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
165                   i2c_sda_reg           <= '1';
166                   IF (byte_position = 2) THEN
167                     byte_position <= (OTHERS => '0');
168                     i2c_state     <= "100";
169                   ELSE
170                     byte_position <= byte_position + 1;
171                     i2c_state     <= "001";
172                   END IF;
173                 WHEN "100" =>           -- STATE: stop_wait
174                   i2c_sda_reg <= '0';
175                   i2c_state   <= "011";      -- 'stop'
176                 WHEN OTHERS =>
177                   NULL;
178               END CASE;
179             WHEN OTHERS =>
180               NULL;
181           END CASE;
182         END IF;
183
184         -- Data synchronization acknowledgement
185         IF (new_data = '0' AND received_data_reg = '1') THEN
186           received_data_reg <= '0';
187         END IF;
188       END IF;
189     END IF;
190   END PROCESS;
191 END Behavioral;
192