sens_sync.v 9.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*!
 * <b>Module:</b>sens_sync
 * @file sens_sync.v
 * @date 2015-07-13  
 * @author Andrey Filippov     
 *
 * @brief Handle linescan mode, sensor trigger and late frame sync
 *
 * @copyright Copyright (c) 2015 Elphel, Inc .
 *
 * <b>License:</b>
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * sens_sync.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.
 *
 *  sens_sync.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/> .
25 26 27 28 29 30
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
31
 * files and/or simulating the code, the copyright holders of this Program give
32 33
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
Andrey Filippov's avatar
Andrey Filippov committed
34
 * charge, and there is no dependence on any encrypted modules for simulating of
35 36 37
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
38
 */
39 40 41 42 43 44 45 46 47 48
`timescale 1ns/1ps

module  sens_sync#(
    parameter SENS_SYNC_ADDR  =     'h404,
    parameter SENS_SYNC_MASK  =     'h7fc,
    // 2 locations reserved for control/status (if they will be needed)
    parameter SENS_SYNC_MULT  =     'h2,   // relative register address to write number of frames to combine in one (minus 1, '0' - each farme)
    parameter SENS_SYNC_LATE  =     'h3,    // number of lines to delay late frame sync
    parameter SENS_SYNC_FBITS =     16,    // number of bits in a frame counter for linescan mode
    parameter SENS_SYNC_LBITS =     16,    // number of bits in a line counter for sof_late output (limited by eof) 
49
    parameter SENS_SYNC_LATE_DFLT =  4, // 15,    // number of lines to delay late frame sync
50 51 52 53
    parameter SENS_SYNC_MINBITS =    8,    // number of bits to enforce minimal frame period 
    parameter SENS_SYNC_MINPER =   130    // minimal frame period (in pclk/mclk?) 
    
)(
Andrey Filippov's avatar
Andrey Filippov committed
54
//    input         rst,         // global reset
55 56
    input         pclk,        // global clock input, pixel rate (96MHz for MT9P006)
    input         mclk,        // global system clock, synchronizes commands
Andrey Filippov's avatar
Andrey Filippov committed
57 58
    input         mrst,        // @mclk sync reset
    input         prst,        // @mclk sync reset
Andrey Filippov's avatar
Andrey Filippov committed
59
    input         en,          // @pclk enable channel (0 resets counters)
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    input         sof_in,      // @pclk start of frame input, single-cycle
    input         eof_in,      // @pclk end of frame input, single-cycle (to limit sof_late
    input         hact,        // @pclk (use to count lines for delayed pulse)
    input         trigger_mode,// @mclk - 1 - triggered mode, 0 - free running mode
    input         trig_in,     // @mclk - single-cycle trigger input
    output        trig,        // @pclk trigger signal to the sensor - from trig_in until SOF 
    output reg    sof_out_pclk,// @pclk - use in the same sensor_channel module
    output        sof_out,     // @mclk - single-cycle frame sync (no delay)
    output        sof_late,    // @mclk - single-cycle frame sync (delayed)
    
    input   [7:0] cmd_ad,      // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
    input         cmd_stb      // strobe (with first byte) for the command a/d
    
);
    localparam DATA_WIDTH = (SENS_SYNC_FBITS > SENS_SYNC_LBITS) ? SENS_SYNC_FBITS : SENS_SYNC_LBITS;
    reg [SENS_SYNC_FBITS-1:0] sub_frames_pclk = 0;                  // sub-frame number ("linescan" mode)
    reg [SENS_SYNC_LBITS-1:0] line_dly_pclk = SENS_SYNC_LATE_DFLT;  // sub-frame number ("linescan" mode)
    reg [SENS_SYNC_FBITS-1:0] sub_frames_left;  // sub-frame number ("linescan" mode)
    reg [SENS_SYNC_FBITS-1:0] lines_left;  //Number of lines left to generate sof_late
    reg      [DATA_WIDTH-1:0] cmd_data_r;
    wire               [31:0] cmd_data;
    wire                [1:0] cmd_a;
    wire                      cmd_we;
    reg                 [1:0] cmd_a_r;
    wire                      set_data_mclk;
    wire                      set_data_pclk;
    wire                      zero_frames_left;
    wire                      trig_in_pclk;
    wire                      pre_sof_out;
    reg                       hact_r; 
    wire                      hact_single;
    reg                       sof_dly; // from sof_in to sof_out;
    wire                      last_line;
    wire                      pre_sof_late;
    reg                       trigger_mode_pclk;
    reg                       en_vacts_free=1'b1; // register to allow only one vacts after trigger in triggered mode. Allows first vacts after mode is set
    reg                       overdue; // generated at camsync to bypass filtering out second vact after trigger. Needed to prevent lock-up
                             // when exposure > triger period (and trigger is operated as divide-by-2)
    reg                       trig_r;
    reg [SENS_SYNC_MINBITS-1:0] period_cntr;
    reg                       period_dly; // runnning counter to enforce > min period

    assign set_data_mclk = cmd_we && ((cmd_a == SENS_SYNC_MULT) || (cmd_a == SENS_SYNC_LATE));
    assign zero_frames_left = !(|sub_frames_left);
    assign hact_single = hact && !hact_r;
    assign last_line = !(|lines_left);
    assign pre_sof_late = sof_dly && (eof_in || (hact_single && last_line));
    assign trig = trig_r;
    assign pre_sof_out = sof_in && zero_frames_left && !period_dly && (en_vacts_free || trig_r || overdue);

    always @ (posedge mclk) begin
        if (set_data_mclk)  cmd_data_r <= cmd_data[DATA_WIDTH-1:0];
        if (set_data_mclk)  cmd_a_r <= cmd_a;
    end
    
    always @ (posedge pclk) begin
        if (set_data_pclk && (cmd_a_r == SENS_SYNC_MULT))
            sub_frames_pclk <= cmd_data_r[SENS_SYNC_FBITS-1:0];
            
        if (set_data_pclk && (cmd_a_r == SENS_SYNC_LATE))
            line_dly_pclk <=   cmd_data_r[SENS_SYNC_LBITS-1:0];
            
        if (!en || (sof_in && zero_frames_left)) sub_frames_left <= sub_frames_pclk ;
        else if (sof_in)                         sub_frames_left <=  sub_frames_left - 1;
        
125 126
//        if (!en) hact_r <= hact; 
        hact_r <= hact || !en; 
127 128 129 130 131 132 133 134
        
        if (!en)               sof_dly <= 0;
        else if (pre_sof_out)  sof_dly <= 1;
        else if (pre_sof_late) sof_dly <= 0;

        else if (!sof_dly)    lines_left <= line_dly_pclk;
        else if (hact_single) lines_left <= lines_left - 1;
        
Andrey Filippov's avatar
Andrey Filippov committed
135
        trigger_mode_pclk <= trigger_mode; 
136 137 138 139 140 141 142
        
        if (!trigger_mode_pclk || !en) en_vacts_free<= 1'b1;
        else if (sof_in)               en_vacts_free<= 1'b0;
        
        if (pre_sof_out || !trigger_mode_pclk) overdue <= 1'b0;
        else if (trig_in_pclk)                 overdue <= trig_r;
        
Andrey Filippov's avatar
Andrey Filippov committed
143 144
        if (!en || !trigger_mode_pclk  || sof_in) trig_r <=0;
        else if (trig_in_pclk)                    trig_r <= ~trig_r;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

        // enforce minimal frame period (applies to both normal and delayed pulse (Make it only in free-running mode?)
        if (!en || !(&period_cntr)) period_dly <= 0;
        else if (pre_sof_out)       period_dly <= 1;
        
        if (!period_dly) period_cntr <= SENS_SYNC_MINPER;
        else             period_cntr <= period_cntr - 1;
        
        sof_out_pclk <= pre_sof_out;
        
    end
    
    cmd_deser #(
        .ADDR        (SENS_SYNC_ADDR),
        .ADDR_MASK   (SENS_SYNC_MASK),
        .NUM_CYCLES  (6),
        .ADDR_WIDTH  (2),
        .DATA_WIDTH  (32),
        .ADDR1       (0),
        .ADDR_MASK1  (0),
        .ADDR2       (0),
        .ADDR_MASK2  (0)
    ) cmd_deser_sens_sync_i (
Andrey Filippov's avatar
Andrey Filippov committed
168
        .rst         (1'b0),          // input
169
        .clk         (mclk),          // input
Andrey Filippov's avatar
Andrey Filippov committed
170
        .srst        (mrst),          // input
171 172 173 174 175 176 177 178 179
        .ad          (cmd_ad),        // input[7:0] 
        .stb         (cmd_stb),       // input
        .addr        (cmd_a),         // output[15:0] 
        .data        (cmd_data),      // output[31:0] 
        .we          (cmd_we)         // output
    );

    // mclk -> pclk    
    pulse_cross_clock pulse_cross_clock_set_data_pclk_i (
Andrey Filippov's avatar
Andrey Filippov committed
180
        .rst         (mrst),           // input
181 182 183 184 185 186 187 188
        .src_clk     (mclk),          // input
        .dst_clk     (pclk),          // input
        .in_pulse    (set_data_mclk), // input
        .out_pulse   (set_data_pclk), // output
        .busy() // output
    );
    
    pulse_cross_clock pulse_cross_clock_trig_in_pclk_i (
Andrey Filippov's avatar
Andrey Filippov committed
189
        .rst         (mrst),           // input
190 191 192 193 194 195 196 197 198
        .src_clk     (mclk),          // input
        .dst_clk     (pclk),          // input
        .in_pulse    (trig_in),       // input
        .out_pulse   (trig_in_pclk),  // output
        .busy() // output
    );
    
    // pclk -> mclk    
    pulse_cross_clock pulse_cross_clock_sof_out_i (
Andrey Filippov's avatar
Andrey Filippov committed
199
        .rst         (prst),           // input
200 201 202 203 204 205 206
        .src_clk     (pclk),          // input
        .dst_clk     (mclk),          // input
        .in_pulse    (pre_sof_out),   // input
        .out_pulse   (sof_out),       // output
        .busy() // output
    );
    pulse_cross_clock pulse_cross_clock_sof_late_i (
Andrey Filippov's avatar
Andrey Filippov committed
207
        .rst         (prst),           // input
208 209 210 211 212 213 214 215 216
        .src_clk     (pclk),          // input
        .dst_clk     (mclk),          // input
        .in_pulse    (pre_sof_late),  // input
        .out_pulse   (sof_late),      // output
        .busy() // output
    );

endmodule