sens_sync.v 10 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: sens_sync
 * Date:2015-07-13  
4
 * Author: Andrey Filippov     
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * Description: Handle linescan mode, sensor trigger and late frame sync
 *
 * Copyright (c) 2015 Elphel, Inc .
 * 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/> .
20 21 22 23 24 25
 *
 * 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"
26
 * files and/or simulating the code, the copyright holders of this Program give
27 28
 * 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
29
 * charge, and there is no dependence on any encrypted modules for simulating of
30 31 32
 * 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.
33 34 35 36 37 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) 
    parameter SENS_SYNC_LATE_DFLT = 15,    // number of lines to delay late frame sync
    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
49
//    input         rst,         // global reset
50 51
    input         pclk,        // global clock input, pixel rate (96MHz for MT9P006)
    input         mclk,        // global system clock, synchronizes commands
Andrey Filippov's avatar
Andrey Filippov committed
52 53
    input         mrst,        // @mclk sync reset
    input         prst,        // @mclk sync reset
Andrey Filippov's avatar
Andrey Filippov committed
54
    input         en,          // @pclk enable channel (0 resets counters)
55 56 57 58 59 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 125 126 127 128
    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;
        
        if (!en) hact_r <= hact; 
        
        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
129
        trigger_mode_pclk <= trigger_mode; 
130 131 132 133 134 135 136
        
        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
137 138
        if (!en || !trigger_mode_pclk  || sof_in) trig_r <=0;
        else if (trig_in_pclk)                    trig_r <= ~trig_r;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

        // 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
162
        .rst         (1'b0),          // input
163
        .clk         (mclk),          // input
Andrey Filippov's avatar
Andrey Filippov committed
164
        .srst        (mrst),          // input
165 166 167 168 169 170 171 172 173
        .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
174
        .rst         (mrst),           // input
175 176 177 178 179 180 181 182
        .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
183
        .rst         (mrst),           // input
184 185 186 187 188 189 190 191 192
        .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
193
        .rst         (prst),           // input
194 195 196 197 198 199 200
        .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
201
        .rst         (prst),           // input
202 203 204 205 206 207 208 209 210
        .src_clk     (pclk),          // input
        .dst_clk     (mclk),          // input
        .in_pulse    (pre_sof_late),  // input
        .out_pulse   (sof_late),      // output
        .busy() // output
    );

endmodule