OpenCores
URL https://opencores.org/ocsvn/ov7670-sccb/ov7670-sccb/trunk

Subversion Repositories ov7670-sccb

[/] [ov7670-sccb/] [trunk/] [hdl/] [english/] [hdl/] [SCCBMaster.vhd] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 ibrahimvar
---------------------------------------------------------------------------------------------------------------------------------------------
2
--  OV7670 uses SCCB interface for configuring it's registers. That interface is compatible with I2C. 
3
--  But unlike I2C, SCCB has logical-1 state on it's data line.
4
--  High - Low - High Impedance
5
--
6
--  The most important point of this interface is; ACK and NACK bits are useless in write mode. SCCB 
7
--  uses a "Don't Care" bit. That bit is logical-0. You can see the data frame of a write process:
8
--
9
--      |A6|A5|A4|A3|A2|A1|A0|R/W|DC|-|R7|R6|R5|R4|R3|R2|R1|R0|DC|-|D7|D6|D5|D4|D3|D2|D1|D0|DC|
10
--             7-bit Address               8-Bit Register/Data             8-bit Data
11
--         R => logical-1
12
--         W => logical-0
13
--
14
--  Warning: This module made for only writing data to registers. Read process will be added. :)
15
--
16
--  
17
--  Used Sources         : OV7670 Datasheet
18
--                       : OmniVision SCCB Specification
19
--                       : http://www.dejazzer.com/hardware.html (Face detection on FPGA: OV7670 CMOS camera + DE2-115 FPGA board)
20
--                       : http://www.dejazzer.com/eigenpi/digital_camera/digital_camera.html
21
--
22
--
23
---------------------------------------------------------------------------------------------------------------------------------------------
24
 
25
 
26
library IEEE;
27
use IEEE.STD_LOGIC_1164.all;
28
use IEEE.STD_LOGIC_UNSIGNED.all;
29
use IEEE.NUMERIC_STD.all;
30
 
31
entity SCCBMaster is
32
    generic(
33
        GInputClock :   integer := 50_000_000;                  --  FPGA main clock speed
34
        GBusClock   :   integer := 400_000                      --  Speed of SCCB clock to be used
35
    );
36
        port(
37
                PIClock     :   in      std_logic;                      --  System clock input
38
        PIReset     :   in      std_logic;                      --  Reset(active low) input
39
        PIEnable    :   in      std_logic;                      --  Enable input that enables the SCCB interface
40
        PIAddress   :   in      std_logic_vector(6 downto 0);   --  SCCB slave device's address input
41
        PIRegister  :   in      std_logic_vector(7 downto 0);   --  SCCB slave device's register input
42
        PIWriteData :   in      std_logic_vector(7 downto 0);   --  Data input
43
        PIStart     :   in      std_logic;                      --  Module's backend start input
44
        PODone      :   out     std_logic;                      --  Gives an logical-1 output when the process is complete
45
        POReady     :   out     std_logic;                      --  Output for determine SCCB line is ready for another operation
46
        PIOSIOD     :   inout   std_logic;                      --  SCCB serial data I/O
47
        POSIOC      :   out     std_logic                       --  SCCB clock output
48
        );
49
end SCCBMaster;
50
 
51
architecture Behavioral of SCCBMaster is
52
 
53
------------------------------------------------------------------------------------------------------------------
54
--  In this step; signals and state machine states created for I/O ports and references.
55
------------------------------------------------------------------------------------------------------------------
56
 
57
    type        TStatesWrite        is  (idle, start_condition, send_addr, addr_dc, send_reg, reg_dc, send_data, data_dc, stop);
58
    signal      SStateWriteBase     :   TStatesWrite                        :=  idle;
59
 
60
    constant    CClockCountMax      :   integer                             :=  (GInputClock / GBusClock);
61
 
62
    signal      SStart              :   std_logic                           :=  '0';
63
    signal      SStartReg           :   std_logic                           :=  '0';
64
    signal      SStartedWrite       :   std_logic                           :=  '0';
65
 
66
    signal      SEnable             :   std_logic                           :=  '0';
67
    signal      SAddress            :   std_logic_vector(6 downto 0)        :=  (others => '0');
68
    signal      SRegister           :   std_logic_vector(7 downto 0)        :=  (others => '0');
69
    signal      SWriteData          :   std_logic_vector(7 downto 0)        :=  (others => '0');
70
    signal      SBusy               :   std_logic                           :=  '0';
71
    signal      SBusy2              :   std_logic                           :=  '0';
72
    signal      SDone               :   std_logic                           :=  '0';
73
    signal      SReady              :   std_logic                           :=  '0';
74
 
75
    signal      SDataClockRef       :   std_logic                           :=  '0';
76
    signal      SDataClockRefPrev   :   std_logic                           :=  '0';
77
 
78
    -- signal      SSIODClock          :   std_logic                        :=    '0';   --  DEBUG ONLY!
79
    -- signal      SSIODClockPrev      :   std_logic;                                    --  DEBUG ONLY!
80
    signal      SSIOCClock          :   std_logic                           :=  '1';
81
    signal      SSIOCClockPrev      :   std_logic;
82
 
83
    signal      SSIODWrite          :   std_logic                           :=  '0';
84
    signal      SSIODRead           :   std_logic                           :=  '0';
85
    signal      SSIOCWrite          :   std_logic                           :=  '0';
86
    signal      SSIOCRead           :   std_logic                           :=  '0';
87
 
88
    signal      SAddr               :   std_logic_vector(6 downto 0)        :=  (others => '0');
89
    signal      SReg                :   std_logic_vector(7 downto 0)        :=  (others => '0');
90
    signal      SData               :   std_logic_vector(7 downto 0)        :=  (others => '0');
91
 
92
    signal      SAddrReg            :   std_logic_vector(6 downto 0)        :=  (others => '0');
93
    signal      SRegReg             :   std_logic_vector(7 downto 0)        :=  (others => '0');
94
    signal      SDataReg            :   std_logic_vector(7 downto 0)        :=  (others => '0');
95
    signal      SCounter            :   integer range 0 to 8                :=  0;
96
 
97
    signal      SCounterSCCB        :   integer range 0 to CClockCountMax   :=  0;
98
    signal          SCounter2           :       integer range 0 to 3                :=  0;
99
 
100
 
101
begin
102
 
103
------------------------------------------------------------------------
104
--  In this part; the I/O ports are directed to according signals
105
------------------------------------------------------------------------
106
    SStart      <=  PIStart;
107
    SEnable     <=  PIEnable;
108
    SAddress    <=  PIAddress;
109
    SRegister   <=  PIRegister;
110
    SWriteData  <=  PIWriteData;
111
    PODone      <=  SDone;
112
    POReady     <=  SReady;
113
 
114
    POSIOC      <=  SSIOCWrite when (SStateWriteBase = idle or SStateWriteBase = start_condition or SStateWriteBase = stop ) else
115
                    SSIOCClock;
116
 
117
    PIOSIOD     <=  SSIODWrite when SEnable = '1' else 'Z';
118
 
119
    SStartReg   <=  '1' when SStart = '1' and SEnable = '1' else
120
                    '0' when (SSIOCClock = '0' and SSIOCClockPrev = '1') or PIReset = '0' or SEnable = '0' else
121
                    SStartReg;
122
 
123
-------------------------------------------------------------------------------------------------------------------------------
124
--  READY process; if write operation is over (SDone == '1') and write state machine is at start(SStateWriteBase == idle)
125
--  then it changes SReady to logic-1. And when the system at reset state(PIReset == '0') it changes SReady to logic-0.
126
-------------------------------------------------------------------------------------------------------------------------------
127
    READY : process(PIClock, PIReset)
128
    begin
129
        if PIReset = '0' then
130
            SReady      <= '0';
131
        elsif rising_edge(PIClock) then
132
            if SStateWriteBase = idle then
133
                SReady  <= '1';
134
            else
135
                SReady  <= '0';
136
            end if;
137
        end if;
138
    end process;
139
 
140
-------------------------------------------------------------------------------------------------------------------------------
141
--  According to SStart signal state, this process; it assigns address, register and data inputs into their "register" 
142
--  signals. When the system triggered by the reset input, all the register signals will be cleared.
143
-------------------------------------------------------------------------------------------------------------------------------
144
 
145
    DATA_CAPTURE : process(PIClock, PIReset)
146
    begin
147
        if PIReset = '0' then
148
            SAddrReg        <= (others => '0');
149
            SRegReg         <= (others => '0');
150
            SDataReg        <= (others => '0');
151
        elsif rising_edge(PIClock) then
152
            if SStart = '1' then
153
                SAddrReg    <= SAddress;
154
                SRegReg     <= SRegister;
155
                SDataReg    <= SWriteData;
156
            elsif SSIOCClock = '0' and SSIOCClockPrev = '1' then
157
                SAddrReg    <= SAddrReg;
158
                SRegReg     <= SRegReg;
159
                SDataReg    <= SDataReg;
160
            else
161
                SAddrReg    <= SAddrReg;
162
                SRegReg     <= SRegReg;
163
                SDataReg    <= SDataReg;
164
            end if;
165
        end if;
166
    end process;
167
 
168
-------------------------------------------------------------------------------------------------------------------------------
169
--  CLKGEN process; generates clock reference signals for SCCB interface. The important thing at this point is:
170
--  If we inspect the datasheet of the OV7670, we can see data changes at half of the period of SCCB's logic-0.  
171
--  For that reason we need to create a data reference signal that changes at half of the period of SIOC reference signal.
172
--  
173
--  |¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______    =====>>>    SIOC Reference Clock
174
--              |               |               |               |               |
175
--              |               |               |               |               |
176
--  |¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_    =====>>>    DATA Reference Clock
177
--  
178
-------------------------------------------------------------------------------------------------------------------------------
179
    CLKGEN : process(PIClock)
180
        variable    VCounter        : integer range 0 to CClockCountMax     := 0;
181
    begin
182
        if rising_edge(PIClock) then
183
            --SSIODClockPrev      <= SSIODClock;
184
            SSIOCClockPrev      <= SSIOCClock;
185
            SDataClockRefPrev   <=  SDataClockRef;
186
 
187
                                if SCounterSCCB = (CClockCountMax / 4) - 1 then
188
                                        SDataClockRef   <= not SDataClockRef;
189
                                        if SCounter2 = 1 then
190
                                                --SSIODClock  <= not SSIODClock;
191
                                                SSIOCClock   <= not SSIOCClock;
192
                                                SCounter2 <= 0;
193
                                        else
194
                                                SCounter2 <= SCounter2 + 1;
195
                                        end if;
196
                                        SCounterSCCB    <= 0;
197
                                else
198
                                        SCounterSCCB    <= SCounterSCCB +1;
199
                                end if;
200
 
201
        end if;
202
    end process;
203
 
204
-------------------------------------------------------------------------------------------------------------------------------------------
205
--  DATA_WRITE process; It contains the state machine that will write in accordance with the SCCB interface. When PIReset input trig-
206
--  gered, all of the states, signals and registers will be cleared.
207
--
208
--                                                           !!!!IMPORTANT!!!!
209
--
210
--  When the SCCB interface at the idle state, it will hold the SIOD output at high impedance and SIOC output at logic-1 state. Start
211
--  condition changes the SIOD line to logic-1 and after half of the SIOC referance period, changes the SIOC line to logic-0 to start
212
--  communication. The finish state is; when there is no data to be written, firstly changes the SIOC line to logic-1 state and after
213
--  half of the SIOC referance period, the SIOD line will be changed to high impedance state. But if there is another data needs to
214
--  be written, then SIOD line will be changed to logic-1 state.
215
--
216
--
217
--  SIOD     -------¯¯¯¯¯¯¯|                               |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|               |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
218
--                         |_______________________________|               |_______________|                               |______
219
--                         |               |               |               |               |               |               |
220
--                         |               |               |               |               |               |               |
221
--                         |               |               |               |               |               |               |  
222
--  SIOC     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|               |¯¯¯¯¯¯¯|   |   |¯¯¯¯¯¯¯|   |   |¯¯¯¯¯¯¯|   |   |¯¯¯¯¯¯¯|   |   |¯¯¯¯¯¯¯|   |    
223
--                             |_______________|       |_______|       |_______|       |_______|       |_______|       |___|______
224
--                         |               |               |               |               |               |               |
225
--                         |               |               |               |               |               |               |
226
--  SIOC Ref   |¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______|¯¯¯¯¯¯¯|_______ 
227
--                         |               |               |               |               |               |               |
228
--                         |               |               |               |               |               |               |
229
--  SIOD Ref   |¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_|¯|_            
230
--
231
-------------------------------------------------------------------------------------------------------------------------------------------
232
 
233
    DATA_WRITE : process(PIClock, PIReset)
234
        variable VCounter : integer range 0 to 16 := 0;
235
    begin
236
        if PIReset = '0' then
237
            SStateWriteBase <= idle;
238
            SStartedWrite   <= '0';
239
            SAddr           <= (others => '0');
240
            SReg            <= (others => '0');
241
            SData           <= (others => '0');
242
            SSIODWrite      <= 'Z';
243
            SSIOCWrite      <= '1';
244
            SBusy           <= '0';
245
            SDone           <= '0';
246
            SBusy2          <= '0';
247
            VCounter        := 0;
248
            SCounter        <=  7;
249
        elsif rising_edge(PIClock) then
250
            case SStateWriteBase is
251
-------------------------------------------------------------------------------------------------------------------------------------------
252
--  "idle" state; when SStartReg is triggered; takes address, register and write data to cache and changes the it's state to 
253
--  "start_condition" at rising edge of SIOC reference clock.
254
--  If SStartReg signal is not triggered(SIOD = 'Z' - SIOC = '1'), then system will remain in the "idle" state.
255
-------------------------------------------------------------------------------------------------------------------------------------------
256
                when idle =>
257
                    if SSIOCClock = '0' and SSIOCClockPrev = '1' then
258
                        if SStartReg = '1' then
259
                            SSIODWrite   <= '1';
260
                            SSIOCWrite   <= '1';
261
                            SStartedWrite    <= '1';
262
                            SDone       <= '0';
263
                            SAddr       <= SAddrReg;
264
                            SReg        <= SRegReg;
265
                            SData       <= SDataReg;
266
                        else
267
                            SAddr       <= (others => '0');
268
                            SReg        <= (others => '0');
269
                            SData       <= (others => '0');
270
                            SStateWriteBase      <= idle;
271
                            SSIODWrite   <= 'Z';
272
                            SSIOCWrite   <= '1';
273
                            SStartedWrite    <= '0';
274
                            SDone       <= '1';
275
                        end if;
276
                    elsif SSIOCClock = '1' and SSIOCClockPrev = '0' and SStartedWrite = '1' then
277
                        SSIODWrite   <= '0';
278
 
279
                        SStartedWrite    <= '0';
280
                        SStateWriteBase <= start_condition;
281
                    end if;
282
-------------------------------------------------------------------------------------------------------------------------------------------
283
--  start_condition" state; after 2 SIOC reference clock pulse, it writes the cached address data's first bit to SIOD line while shifting
284
--  cached address data to left when rising edge of SIOD reference and SIOC reference is logic-0. After that the state will change to
285
--  "send_addr" state.
286
-------------------------------------------------------------------------------------------------------------------------------------------
287
                when start_condition =>
288
                    if SSIOCClock = '0' and SSIOCClockPrev = '1' then
289
                        SBusy <= '1';
290
                        if SBusy = '1' then
291
                            SBusy2 <= '1';
292
                        end if;
293
                        SSIOCWrite   <= '0';
294
                    elsif SDataClockRef = '1' and SDataClockRefPrev = '0' and SSIOCClock = '0' and SBusy2 = '1' then
295
                        if SAddr(6) = '1' then
296
                            SSIODWrite <= '1';
297
                            SAddr <= std_logic_vector(shift_left(unsigned(SAddr), 1));
298
                        elsif SAddr(6) = '0' then
299
                            SSIODWrite <= '0';
300
                            SAddr <= std_logic_vector(shift_left(unsigned(SAddr), 1));
301
                        end if;
302
                        SBusy   <= '0';
303
                        SBusy2   <= '0';
304
                        SStateWriteBase      <= send_addr;
305
 
306
 
307
                    else
308
                        SStateWriteBase      <= start_condition;
309
                    end if;
310
-------------------------------------------------------------------------------------------------------------------------------------------
311
--  "send_addr" state; writes the remaining address data to SIOD line and writes the "Don't Care" bit (logic-0) to SIOD line when rising 
312
--  edge of SIOD reference clock and at SIOC reference clock is 0.
313
-------------------------------------------------------------------------------------------------------------------------------------------                    
314
                when send_addr =>
315
                    if SDataClockRef = '1' and SDataClockRefPrev = '0' and SSIOCClock = '0' then
316
                        if VCounter <= 5 then
317
                            VCounter    := VCounter + 1;
318
                            if(SAddr(6) = '1') then
319
                                SSIODWrite   <= '1';
320
                                SAddr       <= std_logic_vector(shift_left(unsigned(SAddr), 1));
321
                            elsif (SAddr(6) = '0') then
322
                                SSIODWrite   <= '0';
323
                                SAddr       <= std_logic_vector(shift_left(unsigned(SAddr), 1));
324
                            end if;
325
                        else
326
                            VCounter    := 0;
327
                            SSIODWrite   <= '0'; ---->>>> Don't Care Bit!
328
                            SStateWriteBase      <= addr_dc;
329
                            SBusy       <= '0';
330
                        end if;
331
                    else
332
                        SStateWriteBase      <= send_addr;
333
                    end if;
334
 
335
                when addr_dc =>
336
                    if SDataClockRef = '1' and SDataClockRefPrev = '0' and SSIOCClock = '0' then
337
                        SAddr   <=  (others => '0');
338
                    elsif SDataClockRef = '0' and SDataClockRefPrev = '1' and SSIOCClock = '0' then
339
                        SStateWriteBase      <= send_reg;
340
                    end if;
341
-------------------------------------------------------------------------------------------------------------------------------------------
342
--  "send_reg" state; It writes the register data to the SIOD line as soon as the rising edge of the SIOD reference and the SIOC 
343
--  reference are logic-0. After finishing writing register data, it will write a "Don't Care" bit.
344
-------------------------------------------------------------------------------------------------------------------------------------------   
345
                when send_reg =>
346
                    if SDataClockRef = '1' and SDataClockRefPrev = '0' and SSIOCClock = '0' then
347
                        SBusy <= '1';
348
                        if SBusy = '1' then
349
                            if VCounter <= 7 then
350
                                VCounter    := VCounter + 1;
351
                                if(SReg(7) = '1') then
352
                                    SSIODWrite   <= '1';
353
                                    SReg        <= std_logic_vector(shift_left(unsigned(SReg), 1));
354
                                elsif (SReg(7) = '0') then
355
                                    SSIODWrite   <= '0';
356
                                    SReg        <= std_logic_vector(shift_left(unsigned(SReg), 1));
357
                                end if;
358
                            else
359
                                SBusy <= '0';
360
                                VCounter    := 0;
361
                                SSIODWrite   <= '0'; ---->>>> Don't Care Bit!
362
                                SStateWriteBase      <= reg_dc;
363
                            end if;
364
                        end if;
365
                    end if;
366
-------------------------------------------------------------------------------------------------------------------------------------------
367
--  "reg_dc" state; after "Don't Care" bit is written, like the other states, according SIOD and SIOC reference states it will write 
368
--  the cached data's first bit while shifting to the left to SIOD line and changes it's state to "send_data".
369
-------------------------------------------------------------------------------------------------------------------------------------------   
370
                when reg_dc =>
371
                    if SDataClockRef = '1' and SDataClockRefPrev = '0' and SSIOCClock = '0' then
372
                        SReg   <=  (others => '0');
373
                        SStateWriteBase      <= send_data;
374
                        if(SData(7) = '1') then
375
                            SSIODWrite   <= '1';
376
                            SData       <= std_logic_vector(shift_left(unsigned(SData), 1));
377
                            SBusy <= '0';
378
                        elsif (SData(7) = '0') then
379
                            SSIODWrite   <= '0';
380
                            SData       <= std_logic_vector(shift_left(unsigned(SData), 1));
381
                            SBusy <= '0';
382
                        end if;
383
                    end if;
384
-------------------------------------------------------------------------------------------------------------------------------------------
385
--  "send_data" state; when the first bit of the data is written, the remaining bits will be written to the SIOD line while shifting
386
--  to the left. When data write is done, it will write "Don't Care" bit to SIOD line and after 1 SIOD and SIOC reference clock it
387
--  will change it's state to "data_dc".
388
-------------------------------------------------------------------------------------------------------------------------------------------   
389
                when send_data =>
390
                    if SDataClockRef = '1' and SDataClockRefPrev = '0' and SSIOCClock = '0' then
391
                        if VCounter     <= 6 then
392
                            VCounter    := VCounter + 1;
393
                            if(SData(7) = '1') then
394
                                SSIODWrite   <= '1';
395
                                SData       <= std_logic_vector(shift_left(unsigned(SData), 1));
396
                            elsif (SData(7) = '0') then
397
                                SSIODWrite   <= '0';
398
                                SData       <= std_logic_vector(shift_left(unsigned(SData), 1));
399
                            end if;
400
                        else
401
 
402
                            SSIODWrite   <= '0'; ----
403
                            SBusy <= '1';
404
                            if SBusy = '1' then
405
                                VCounter    := 0;
406
                                SStateWriteBase      <= data_dc;
407
                                SBusy <= '0';
408
                            end if;
409
 
410
                        end if;
411
                    end if;
412
----------------------------------------------------------------------------------------------
413
--  "data_dc" state; waits only one SIOC reference clock and change it's state to "stop".
414
----------------------------------------------------------------------------------------------
415
                when data_dc =>
416
                    if SSIOCClock = '1' and SSIOCClockPrev = '0' then
417
                        SData      <= (others => '0');
418
                        SStateWriteBase <= stop;
419
                    end if;
420
-------------------------------------------------------------------------------------------------------------------------------------------
421
--  "stop" state; for stopping the SCCB communication, firstly changes SIOC line to logic-1 state and after 1 SIOC reference clock, it
422
--  changes the SIOD line to logic-1 state and goes to "idle" state.
423
-------------------------------------------------------------------------------------------------------------------------------------------   
424
                when stop =>
425
                    SSIOCWrite   <= '1';
426
                    if SSIOCClock = '1' and SSIOCClockPrev = '0' then
427
                          SSIODWrite   <= '1';
428
                        SBusy       <= '1';
429
                        SAddr       <= (others => '0');
430
                        SReg        <= (others => '0');
431
                        SData       <= (others => '0');
432
                        if SBusy = '1' then
433
                            --SReady      <= '1';
434
                            SStateWriteBase      <= idle;
435
                            SDone       <= '1';
436
 
437
                            SBusy       <= '0';
438
                        end if;
439
                    elsif SSIOCClock = '0' and SSIOCClockPrev = '1' then
440
                        SSIODWrite   <= '1';
441
                    end if;
442
 
443
                when others =>
444
            end case;
445
        end if;
446
    end process;
447
 
448
end Behavioral;

powered by: WebSVN 2.1.0

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