OpenCores
URL https://opencores.org/ocsvn/a-z80/a-z80/trunk

Subversion Repositories a-z80

[/] [a-z80/] [trunk/] [host/] [zxspectrum_de1/] [ula/] [i2c_loader.vhd] - Blame information for rev 8

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 8 gdevic
-- ZX Spectrum for Altera DE1
2
--
3
-- Copyright (c) 2009-2010 Mike Stirling
4
--
5
-- All rights reserved
6
--
7
-- Redistribution and use in source and synthezised forms, with or without
8
-- modification, are permitted provided that the following conditions are met:
9
--
10
-- * Redistributions of source code must retain the above copyright notice,
11
--   this list of conditions and the following disclaimer.
12
--
13
-- * Redistributions in synthesized form must reproduce the above copyright
14
--   notice, this list of conditions and the following disclaimer in the
15
--   documentation and/or other materials provided with the distribution.
16
--
17
-- * Neither the name of the author nor the names of other contributors may
18
--   be used to endorse or promote products derived from this software without
19
--   specific prior written permission.
20
--
21
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
25
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
-- POSSIBILITY OF SUCH DAMAGE.
32
--
33
 
34
library IEEE;
35
use IEEE.STD_LOGIC_1164.ALL;
36
use IEEE.STD_LOGIC_ARITH.ALL;
37
use IEEE.STD_LOGIC_UNSIGNED.ALL;
38
use IEEE.STD_LOGIC_MISC.ALL; -- for AND_REDUCE
39
use IEEE.NUMERIC_STD.ALL;
40
 
41
entity i2c_loader is
42
generic (
43
    -- Address of slave to be loaded
44
    device_address : integer := 16#1a#;
45
    -- Number of retries to allow before stopping
46
    num_retries : integer := 0;
47
    -- Length of clock divider in bits.  Resulting bus frequency is
48
    -- CLK/2^(log2_divider + 2)
49
    log2_divider : integer := 6
50
);
51
 
52
port (
53
    CLK         :   in  std_logic;
54
    nRESET      :   in  std_logic;
55
 
56
    I2C_SCL     :   inout   std_logic;
57
    I2C_SDA     :   inout   std_logic;
58
 
59
    IS_DONE     :   out std_logic;
60
    IS_ERROR    :   out std_logic
61
    );
62
end i2c_loader;
63
 
64
architecture i2c_loader_arch of i2c_loader is
65
type regs is array(0 to 19) of std_logic_vector(7 downto 0);
66
constant init_regs : regs := (
67
    -- Left line in, 0dB, unmute
68
    X"00", X"17",
69
    -- Right line in, 0dB, unmute
70
    X"02", X"17",
71
    -- Left headphone out, 0dB
72
    X"04", X"79",
73
    -- Right headphone out, 0dB
74
    X"06", X"79",
75
    -- Audio path, DAC enabled, Line in, Bypass off, mic unmuted
76
    X"08", X"10",
77
    -- Digital path, Unmute, HP filter enabled
78
    X"0A", X"00",
79
    -- Power down mic, clkout and xtal osc
80
    X"0C", X"62",
81
    -- Format 16-bit I2S, no bit inversion or phase changes
82
    X"0E", X"02",
83
    -- Sampling control, 8 kHz USB mode (MCLK = 250fs * 6)
84
    X"10", X"0D",
85
    -- Activate
86
    X"12", X"01"
87
    );
88
-- Number of bursts (i.e. total number of registers)
89
constant burst_length : positive := 2;
90
-- Number of bytes to transfer per burst
91
constant num_bursts : positive := (init_regs'length / burst_length);
92
 
93
type state_t is (Idle, Start, Data, Ack, Stop, Pause, Done);
94
signal state : state_t;
95
signal phase : std_logic_vector(1 downto 0);
96
subtype nbit_t is integer range 0 to 7;
97
signal nbit : nbit_t;
98
subtype nbyte_t is integer range 0 to burst_length; -- +1 for address byte
99
signal nbyte : nbyte_t;
100
subtype thisbyte_t is integer range 0 to init_regs'length; -- +1 for "done"
101
signal thisbyte : thisbyte_t;
102
subtype retries_t is integer range 0 to num_retries;
103
signal retries : retries_t;
104
 
105
signal clken : std_logic;
106
signal divider : std_logic_vector(log2_divider-1 downto 0);
107
signal shiftreg : std_logic_vector(7 downto 0);
108
signal scl_out : std_logic;
109
signal sda_out : std_logic;
110
signal nak : std_logic;
111
begin
112
    -- Create open-drain outputs for I2C bus
113
    I2C_SCL <= '0' when scl_out = '0' else 'Z';
114
    I2C_SDA <= '0' when sda_out = '0' else 'Z';
115
    -- Status outputs are driven both ways
116
    IS_DONE <= '1' when state = Done else '0';
117
    IS_ERROR <= nak;
118
 
119
    -- Generate clock enable for desired bus speed
120
    clken <= AND_REDUCE(divider);
121
    process(nRESET,CLK)
122
    begin
123
        if nRESET = '0' then
124
            divider <= (others => '0');
125
        elsif falling_edge(CLK) then
126
            divider <= divider + '1';
127
        end if;
128
    end process;
129
 
130
    -- The I2C loader process
131
    process(nRESET,CLK,clken)
132
    begin
133
        if nRESET = '0' then
134
            scl_out <= '1';
135
            sda_out <= '1';
136
            state <= Idle;
137
            phase <= "00";
138
            nbit <= 0;
139
            nbyte <= 0;
140
            thisbyte <= 0;
141
            shiftreg <= (others => '0');
142
            nak <= '0'; -- No error
143
            retries <= num_retries;
144
        elsif rising_edge(CLK) and clken = '1' then
145
            -- Next phase by default
146
            phase <= phase + 1;
147
 
148
            -- STATE: IDLE
149
            if state = Idle then
150
                -- Start loading the device registers straight away
151
                -- A 'GO' bit could be polled here if required
152
                state <= Start;
153
                phase <= "00";
154
                scl_out <= '1';
155
                sda_out <= '1';
156
 
157
            -- STATE: START
158
            elsif state = Start then
159
                -- Generate START condition
160
                case phase is
161
                when "00" =>
162
                    -- Drop SDA first
163
                    sda_out <= '0';
164
                when "10" =>
165
                    -- Then drop SCL
166
                    scl_out <= '0';
167
                when "11" =>
168
                    -- Advance to next state
169
                    -- Shift register loaded with device slave address
170
                    state <= Data;
171
                    nbit <= 7;
172
                    shiftreg <= std_logic_vector(to_unsigned(device_address,7)) & '0'; -- writing
173
                    nbyte <= burst_length;
174
                when others =>
175
                    null;
176
                end case;
177
 
178
            -- STATE: DATA
179
            elsif state = Data then
180
                -- Generate data
181
                case phase is
182
                when "00" =>
183
                    -- Drop SCL
184
                    scl_out <= '0';
185
                when "01" =>
186
                    -- Output data and shift (MSb first)
187
                    sda_out <= shiftreg(7);
188
                    shiftreg <= shiftreg(6 downto 0) & '0';
189
                when "10" =>
190
                    -- Raise SCL
191
                    scl_out <= '1';
192
                when "11" =>
193
                    -- Next bit or advance to next state when done
194
                    if nbit = 0 then
195
                        state <= Ack;
196
                    else
197
                        nbit <= nbit - 1;
198
                    end if;
199
                when others =>
200
                  null;
201
                end case;
202
 
203
            -- STATE: ACK
204
            elsif state = Ack then
205
                -- Generate ACK clock and check for error condition
206
                case phase is
207
                when "00" =>
208
                    -- Drop SCL
209
                    scl_out <= '0';
210
                when "01" =>
211
                    -- Float data
212
                    sda_out <= '1';
213
                when "10" =>
214
                    -- Sample ack bit
215
                    nak <= I2C_SDA;
216
                    if I2C_SDA = '1' then
217
                        -- Error
218
                        nbyte <= 0; -- Close this burst and skip remaining registers
219
                        thisbyte <= init_regs'length;
220
                    else
221
                        -- Hold ACK to avoid spurious stops - this seems to fix a
222
                        -- problem with the Wolfson codec which releases the ACK
223
                        -- right on the falling edge of the clock pulse.  It looks like
224
                        -- the device interprets this is a STOP condition and then fails
225
                        -- to acknowledge the next byte.  We can avoid this by holding the
226
                        -- ACK condition for a little longer.
227
                        sda_out <= '0';
228
                    end if;
229
                    -- Raise SCL
230
                    scl_out <= '1';
231
                when "11" =>
232
                    -- Advance to next state
233
                    if nbyte = 0 then
234
                        -- No more bytes in this burst - generate a STOP
235
                        state <= Stop;
236
                    else
237
                        -- Generate next byte
238
                        state <= Data;
239
                        nbit <= 7;
240
                        shiftreg <= init_regs(thisbyte);
241
                        nbyte <= nbyte - 1;
242
                        thisbyte <= thisbyte + 1;
243
                    end if;
244
                when others =>
245
                    null;
246
                end case;
247
 
248
            -- STATE: STOP
249
            elsif state = Stop then
250
                -- Generate STOP condition
251
                case phase is
252
                when "00" =>
253
                    -- Drop SCL first
254
                    scl_out <= '0';
255
                when "01" =>
256
                    -- Drop SDA
257
                    sda_out <= '0';
258
                when "10" =>
259
                    -- Raise SCL
260
                    scl_out <= '1';
261
                when "11" =>
262
                    if thisbyte = init_regs'length then
263
                        -- All registers done, advance to finished state.  This will
264
                        -- bring SDA high while SCL is still high, completing the STOP
265
                        -- condition
266
                        state <= Done;
267
                    else
268
                        -- Load the next register after a short delay
269
                        state <= Pause;
270
                    end if;
271
                when others =>
272
                    null;
273
                end case;
274
 
275
            -- STATE: PAUSE
276
            elsif state = Pause then
277
                -- Delay for one cycle of 'phase' then start the next burst
278
                scl_out <= '1';
279
                sda_out <= '1';
280
                if phase = "11" then
281
                    state <= Start;
282
                end if;
283
 
284
            -- STATE: DONE
285
            else
286
                -- Finished
287
                scl_out <= '1';
288
                sda_out <= '1';
289
 
290
                if nak = '1' and retries > 0 then
291
                    -- We can retry in the event of a NAK in case the
292
                    -- slave got out of sync for some reason
293
                    retries <= retries - 1;
294
                    state <= Idle;
295
                end if;
296
            end if;
297
        end if;
298
    end process;
299
end i2c_loader_arch;
300
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.