sensor_i2c_scl_sda.v 8.17 KB
Newer Older
Andrey Filippov's avatar
Andrey Filippov committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*******************************************************************************
 * Module: sensor_i2c_scl_sda
 * Date:2015-10-06  
 * Author: andrey     
 * Description: Generation of i2c signals
 *
 * Copyright (c) 2015 Elphel, Inc .
 * sensor_i2c_scl_sda.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  sensor_i2c_scl_sda.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  sensor_i2c_scl_sda(
Andrey Filippov's avatar
Andrey Filippov committed
24 25
    input         mrst,           // @ posedge mclk
    input         mclk,           // global clock
Andrey Filippov's avatar
Andrey Filippov committed
26
    input         i2c_rst,
Andrey Filippov's avatar
Andrey Filippov committed
27 28 29
    input  [ 7:0] i2c_dly,        // bit duration-1 (>=2?), 1 unit - 4 mclk periods
    input         active_sda,     // active pull SDA 
    input         early_release_0,// release SDA immediately after end of SCL if next bit is 1 (for ACKN). Data hold time by slow 0->1 
Andrey Filippov's avatar
Andrey Filippov committed
30 31 32
    input         snd_start,
    input         snd_stop,
    input         snd9,
33
    input         rcv,         // receive mode (valid with snd9) - master receives, slave - sends
Andrey Filippov's avatar
Andrey Filippov committed
34
    input  [ 8:0] din,
35
    output reg [ 8:0] dout,        //
Andrey Filippov's avatar
Andrey Filippov committed
36 37 38
    output reg    dout_stb,    // dout contains valid data
    output reg    scl,         // i2c SCL signal
    input         sda_in,      // i2c SDA signal form I/O pad           
Andrey Filippov's avatar
Andrey Filippov committed
39 40
    output reg    sda,         // i2c SDA signal
    output reg    sda_en,      // drive SDA when SDA=0 and during second half of SCL = 0 interval (also during stop) 
Andrey Filippov's avatar
Andrey Filippov committed
41 42 43 44 45 46 47 48 49
    output        ready,       // ready to accept commands
    output reg    bus_busy,    // i2c bus busy (1 cycle behind !ready)
    output        is_open      // i2c channel is open (started, no stop yet)
);
    wire         rst = mrst || i2c_rst;
    reg          is_open_r;
    reg    [8:0] sr;
    reg    [7:0] dly_cntr;
    reg          busy_r;
50 51 52 53
    wire         snd_start_w =  snd_start && ready; //!busy_r;
    wire         snd_stop_w =   snd_stop && ready; // !busy_r;
    wire         snd9_w =       snd9 && ready; //!busy_r;
    wire         start_w =      (snd_start || snd_stop || snd9_w) && ready; //!busy_r;
Andrey Filippov's avatar
Andrey Filippov committed
54 55
    reg          pre_dly_over;
    reg          dly_over;
56
//    reg          dly_over_d;
Andrey Filippov's avatar
Andrey Filippov committed
57 58 59 60 61 62 63
    reg    [3:0] seq_start_restart;
    reg    [2:0] seq_stop;
    reg    [3:0] seq_bit;
    reg    [3:0] bits_left;
    reg          done_r;
    reg          sda_r;
    reg          first_cyc; // first clock cycle for the delay interval - update SCL/SDA outputs
64 65
    reg          active_sda_r; // registered @ snd9, disable in rcv mode
    reg          active_sda_was_0; // only use active SDA if previous bit was 0 or it is receive mode
66
    reg          early_release_r;  // to enable it only for LSB before ACKN during send
67
    reg          rcv_r;
68 69
    wire         busy_w = busy_r && ! done_r;
//    wire         pre_dout_stb = dly_over && seq_bit[0] && (bits_left == 0); 
70 71 72
//    assign ready = !busy_r;
    assign ready = !busy_w;
    
Andrey Filippov's avatar
Andrey Filippov committed
73
    assign is_open =  is_open_r;
74
//    assign dout =     sr;
Andrey Filippov's avatar
Andrey Filippov committed
75
    always @ (posedge mclk) begin
76 77
        active_sda_was_0 <= !sda || rcv_r;
        if (snd9_w) rcv_r <= rcv;
78 79
        
        early_release_r <= early_release_0 && !rcv_r && (bits_left == 1); // only before ACN during master send
80 81 82 83 84 85

        // disable active_sda in send messages for the last (ACKN) bit, for the receive - all but ACKN
        if      (snd9_w)                    active_sda_r <= active_sda && !rcv;
        else if (snd_start_w || snd_stop_w) active_sda_r <= active_sda;
        else if (dly_over && seq_bit[0])    active_sda_r <= active_sda && ((bits_left != 1) ^ rcv_r);
//active_sda_r && !sda    
Andrey Filippov's avatar
Andrey Filippov committed
86
        if      (rst)         seq_start_restart <= 0;
87
        else if (snd_start_w) seq_start_restart <= (is_open_r && !seq_stop[0]) ? 4'h8 : 4'h4;
Andrey Filippov's avatar
Andrey Filippov committed
88 89 90 91 92 93
        else if (dly_over)    seq_start_restart <= {1'b0,seq_start_restart[3:1]};
    
        if      (rst)         seq_stop <= 0;
        else if (snd_stop_w)  seq_stop <= 3'h4;
        else if (dly_over)    seq_stop <= {1'b0,seq_stop[2:1]};

94 95 96
        if      (rst)                                                    seq_bit <= 0;
        else if (snd9_w || (seq_bit[0] && (bits_left != 0) && dly_over)) seq_bit <= 4'h8;
        else if (dly_over)                                               seq_bit <= {1'b0,seq_bit[3:1]};
Andrey Filippov's avatar
Andrey Filippov committed
97
        
98
        if      (rst)                                             bits_left <= 4'h0;
Andrey Filippov's avatar
Andrey Filippov committed
99
        else if (snd9_w)                                          bits_left <= 4'h8;
100
        else if (dly_over && seq_bit[0] && (|bits_left))          bits_left <= bits_left - 1;
Andrey Filippov's avatar
Andrey Filippov committed
101 102 103 104 105 106


        if      (rst)     busy_r <= 0;
        else if (start_w) busy_r <= 1;
        else if (done_r)  busy_r <= 0;
        
107
//        pre_dly_over <=  (dly_cntr == 3);
Andrey Filippov's avatar
Andrey Filippov committed
108 109 110
        pre_dly_over <=  (dly_cntr == 2);
        
        dly_over <=      pre_dly_over;
111
//        dly_over_d <=    dly_over;
Andrey Filippov's avatar
Andrey Filippov committed
112 113 114 115 116
        if      (rst)     done_r <= 0;
        else              done_r <= pre_dly_over &&
                                   (bits_left == 0) &&
                                   (seq_start_restart[3:1] == 0) &&
                                   (seq_stop[2:1] == 0) &&
117
                                   (seq_bit[3:1] == 0);
Andrey Filippov's avatar
Andrey Filippov committed
118
                                   
119 120 121 122
//        if (!busy_r || dly_over_d) dly_cntr <= i2c_dly;
//        else                       dly_cntr <= dly_cntr - 1;
        
        if (!busy_w || dly_over) dly_cntr <= i2c_dly;
Andrey Filippov's avatar
Andrey Filippov committed
123 124 125 126
        else                     dly_cntr <= dly_cntr - 1;
        
        if (dly_over && seq_bit[1]) sda_r <= sda_in; // just before the end of SCL pulse - delay it by a few clocks to match external latencies?
        
127
        if      (snd9_w)                 sr <= din;
Andrey Filippov's avatar
Andrey Filippov committed
128 129
        else if (dly_over && seq_bit[0]) sr <= {sr[7:0], sda_r};
        
130 131 132 133
        dout_stb <= dly_over && seq_bit[0] && (bits_left == 0) && rcv_r;
//        dout_stb <= pre_dout_stb;
//        if (pre_dout_stb) dout <= {sr[7:0],sda_r};
        if (done_r) dout <= {sr[7:0],sda_r};
Andrey Filippov's avatar
Andrey Filippov committed
134 135 136 137 138 139 140 141
        
        if      (rst)                              is_open_r <= 0;
        else if (dly_over && seq_start_restart[0]) is_open_r <= 1;                       
        else if (dly_over && seq_stop[0])          is_open_r <= 0;
        
        first_cyc <= start_w || dly_over;

        if      (rst)        scl <= 1;
142 143
//        else if (first_cyc)  scl <= !busy_r || // Wrong whe "open"?
        else if (first_cyc)  scl <= (scl && !busy_w) || // Wrong whe "open"?
Andrey Filippov's avatar
Andrey Filippov committed
144 145 146 147 148
                                     seq_start_restart[2] ||  seq_start_restart[1] ||
                                     seq_stop[1] || seq_stop[0] ||
                                     seq_bit[2] || seq_bit[1];
                                                       
        if      (rst)        sda <= 1;
149 150
//        else if (first_cyc)  sda <= !busy_r ||
        else if (first_cyc)  sda <= (sda && !busy_w) ||
Andrey Filippov's avatar
Andrey Filippov committed
151 152 153
                                     seq_start_restart[3] ||  seq_start_restart[2] ||
                                     seq_stop[0] ||
                                     (sr[8] && (|seq_bit));
Andrey Filippov's avatar
Andrey Filippov committed
154 155

        if      (rst)        sda_en <= 1;
156 157 158 159
//        else if (first_cyc)  sda_en <= busy_r && (
// TODO: no active SDA if previous SDA was 1
        else if (first_cyc)  sda_en <= busy_w && (
                                     (active_sda_r && active_sda_was_0 && (seq_start_restart[3] || seq_stop[0] || (sr[8] && seq_bit[3]))) || // !sda uses output reg
Andrey Filippov's avatar
Andrey Filippov committed
160 161 162
                                     (|seq_start_restart[1:0]) ||
                                     (|seq_stop[2:1]) ||
                                     (!sr[8] && (|seq_bit[3:1])) ||
163 164
//                                     (!sr[8] && seq_bit[0] && (!early_release_0 || !sr[7])));
                                     (!sr[8] && seq_bit[0] && (!early_release_r || !sr[7])));
Andrey Filippov's avatar
Andrey Filippov committed
165 166 167 168 169
       bus_busy <= busy_r;
    end

endmodule