Commit d4f2714d authored by Andrey Filippov's avatar Andrey Filippov
Browse files

added sensor trigger/synchronization module (with linescan mode), completed top sensor subsystem

parent 3023d860
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -70,7 +70,7 @@ module event_logger#(
    output           [GPIO_N-1:0] ext_en,
    output           [GPIO_N-1:0] ext_en,
    
    


    // byte-parallel timestamps from 4 sesnors channels (in triggered mode all are the same, different only in free running mode)
    // byte-parallel timestamps from 4 sensors channels (in triggered mode all are the same, different only in free running mode)
    // each may generate logger event, channel number encoded in bits 25:24 of the external microseconds
    // each may generate logger event, channel number encoded in bits 25:24 of the external microseconds


    input                         ts_stb_chn0,  // @mclk 1 clock before ts_rcv_data is valid
    input                         ts_stb_chn0,  // @mclk 1 clock before ts_rcv_data is valid
+2 −2
Original line number Original line Diff line number Diff line
@@ -21,7 +21,7 @@
`timescale 1ns/1ps
`timescale 1ns/1ps
/*
/*
Logs frame synchronization data from other camera (same as frame sync)
Logs frame synchronization data from other camera (same as frame sync)
When sesnors are running in free running mode, each sensor may provide individual timestamp (sampled at vsync)
When sensors are running in free running mode, each sensor may provide individual timestamp (sampled at vsync)
*/
*/


module  imu_exttime393(
module  imu_exttime393(
@@ -29,7 +29,7 @@ module imu_exttime393(
    input                         mclk,         // system clock, negedge TODO:COnvert to posedge!
    input                         mclk,         // system clock, negedge TODO:COnvert to posedge!
    input                         xclk,         // half frequency (80 MHz nominal)
    input                         xclk,         // half frequency (80 MHz nominal)
    input                   [3:0] en_chn_mclk,  // enable per-channel module operation, if all 0 - reset
    input                   [3:0] en_chn_mclk,  // enable per-channel module operation, if all 0 - reset
    // byte-parallel timestamps from 4 sesnors channels (in triggered mode all are the same, different only in free running mode)
    // byte-parallel timestamps from 4 sensors channels (in triggered mode all are the same, different only in free running mode)
    // each may generate logger event, channel number encoded in bits 25:24 of the external microseconds
    // each may generate logger event, channel number encoded in bits 25:24 of the external microseconds


    input                         ts_stb_chn0,  // @mclk 1 clock before ts_rcv_data is valid
    input                         ts_stb_chn0,  // @mclk 1 clock before ts_rcv_data is valid
+1 −1
Original line number Original line Diff line number Diff line
@@ -260,7 +260,7 @@ module sens_histogram #(
        .ADDR_MASK1  (0),
        .ADDR_MASK1  (0),
        .ADDR2       (0),
        .ADDR2       (0),
        .ADDR_MASK2  (0)
        .ADDR_MASK2  (0)
    ) cmd_deser_sens_i2c_i (
    ) cmd_deser_sens_histogram_i (
        .rst         (rst), // input
        .rst         (rst), // input
        .clk         (mclk), // input
        .clk         (mclk), // input
        .ad          (cmd_ad), // input[7:0] 
        .ad          (cmd_ad), // input[7:0] 
+19 −15
Original line number Original line Diff line number Diff line
@@ -26,8 +26,8 @@ module sens_parallel12 #(
    parameter SENSIO_CTRL =        'h0,
    parameter SENSIO_CTRL =        'h0,
    parameter SENSIO_STATUS =      'h1,
    parameter SENSIO_STATUS =      'h1,
    parameter SENSIO_JTAG =        'h2,
    parameter SENSIO_JTAG =        'h2,
    parameter SENSIO_WIDTH =       'h3, // 1.. 2^16, 0 - use HACT
    parameter SENSIO_WIDTH =       'h3, // set line width (1.. 2^16) if 0 - use HACT
    parameter SENSIO_DELAYS =      'h4, // 'h4..'h7
    parameter SENSIO_DELAYS =      'h4, // 'h4..'h7 - each address sets 4 delays through 4 bytes of 32-bit data
    parameter SENSIO_STATUS_REG =  'h31,
    parameter SENSIO_STATUS_REG =  'h31,


    parameter SENS_JTAG_PGMEN =    8,
    parameter SENS_JTAG_PGMEN =    8,
@@ -78,9 +78,11 @@ module sens_parallel12 #(
    output        ipclk,  // re-generated sensor output clock (regional clock to drive external fifo) 
    output        ipclk,  // re-generated sensor output clock (regional clock to drive external fifo) 
    output        ipclk2x,// twice frequency regenerated sensor clock (possibly to run external fifo)
    output        ipclk2x,// twice frequency regenerated sensor clock (possibly to run external fifo)
//    input         pclk2x, // maybe not needed here
//    input         pclk2x, // maybe not needed here
    input         trigger_mode, // running in triggered mode (0 - free running mode)
    input         trig,      // per-sensor trigger input
    // sensor pads excluding i2c
    // sensor pads excluding i2c
    input         vact,
    inout         vact,
    input         hact, //output in fillfactory mode
    inout         hact, //output in fillfactory mode
    inout         bpf,  // output in fillfactory mode
    inout         bpf,  // output in fillfactory mode
    inout  [11:0] pxd, //actually only 2 LSBs are inouts
    inout  [11:0] pxd, //actually only 2 LSBs are inouts
    inout         mrst,
    inout         mrst,
@@ -88,7 +90,7 @@ module sens_parallel12 #(
    
    
    inout         arst,
    inout         arst,
    inout         aro,
    inout         aro,
    output        dclk,
    output        dclk, // externally connected to inout port
    // output
    // output
    output [11:0] pxd_out,
    output [11:0] pxd_out,
    output        vact_out, 
    output        vact_out, 
@@ -142,13 +144,14 @@ module sens_parallel12 #(
    wire        clkfb_pxd_stopped_mmcm;
    wire        clkfb_pxd_stopped_mmcm;
    
    
    // programmed resets to the sensor 
    // programmed resets to the sensor 
    reg         iaro  = 0;
    reg         iaro_soft  = 0;
    wire        iaro;
    reg         iarst = 0;
    reg         iarst = 0;
    reg         imrst = 0;
    reg         imrst = 0;
    reg         rst_mmcm=1; // rst and command - en/dis 
    reg         rst_mmcm=1; // rst and command - en/dis 
    reg  [5:0]  quadrants=0;
    reg  [5:0]  quadrants=0; //90-degree shifts for data {1:0], hact [3:2] and vact [5:4]
    reg         ld_idelay=0;
    reg         ld_idelay=0;
    reg         sel_ext_clk=0; // select clock source from the sensor (0 - use internal clock - to sesnor)
    reg         sel_ext_clk=0; // select clock source from the sensor (0 - use internal clock - to sensor)






@@ -175,15 +178,16 @@ module sens_parallel12 #(
    assign set_other_delay = set_idelay[3];
    assign set_other_delay = set_idelay[3];
    assign status = {locked_pxd_mmcm,clkin_pxd_stopped_mmcm,clkfb_pxd_stopped_mmcm,xfpgadone,ps_rdy, ps_out,xfpgatdo,senspgmin};
    assign status = {locked_pxd_mmcm,clkin_pxd_stopped_mmcm,clkfb_pxd_stopped_mmcm,xfpgadone,ps_rdy, ps_out,xfpgatdo,senspgmin};
    assign hact_out = hact_r;
    assign hact_out = hact_r;
    assign iaro = trigger_mode?  ~trig : iaro_soft;
    
    
    always @(posedge rst or posedge mclk) begin
    always @(posedge rst or posedge mclk) begin
        if      (rst)     data_r <= 0;
        if      (rst)     data_r <= 0;
        else if (cmd_we)  data_r <= cmd_data;
        else if (cmd_we)  data_r <= cmd_data;
        if      (rst)     set_idelay <= 0;
        if      (rst)     set_idelay <= 0;
        else   set_idelay <=  {4{cmd_we}} & {(cmd_a==(SENSIO_DELAYS+3))?1'b1:1'b0,
        else   set_idelay <=  {4{cmd_we}} & {(cmd_a==(SENSIO_DELAYS+3)),
                                             (cmd_a==(SENSIO_DELAYS+2))?1'b1:1'b0,
                                             (cmd_a==(SENSIO_DELAYS+2)),
                                             (cmd_a==(SENSIO_DELAYS+1))?1'b1:1'b0,
                                             (cmd_a==(SENSIO_DELAYS+1)),
                                             (cmd_a==(SENSIO_DELAYS+0))?1'b1:1'b0};
                                             (cmd_a==(SENSIO_DELAYS+0))};
        if (rst) set_status_r <=0;
        if (rst) set_status_r <=0;
        else     set_status_r <= cmd_we && (cmd_a== SENSIO_STATUS);                             
        else     set_status_r <= cmd_we && (cmd_a== SENSIO_STATUS);                             
        if (rst) set_ctrl_r <=0;
        if (rst) set_ctrl_r <=0;
@@ -212,8 +216,8 @@ module sens_parallel12 #(
        if      (rst)                                           iarst <= 0;
        if      (rst)                                           iarst <= 0;
        else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1])      iarst <= data_r[SENS_CTRL_ARST]; 
        else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1])      iarst <= data_r[SENS_CTRL_ARST]; 
         
         
        if      (rst)                                           iaro <= 0;
        if      (rst)                                           iaro_soft <= 0;
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      iaro <= data_r[SENS_CTRL_ARO]; 
        else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1])      iaro_soft <= data_r[SENS_CTRL_ARO]; 
         
         
        if      (rst)                                           rst_mmcm <= 0;
        if      (rst)                                           rst_mmcm <= 0;
        else if (set_ctrl_r && data_r[SENS_CTRL_RST_MMCM + 1])  rst_mmcm <= data_r[SENS_CTRL_RST_MMCM]; 
        else if (set_ctrl_r && data_r[SENS_CTRL_RST_MMCM + 1])  rst_mmcm <= data_r[SENS_CTRL_RST_MMCM]; 
@@ -538,7 +542,7 @@ module sens_parallel12 #(
        .I  (xpgmen?(~xfpgaprog):force_senspgm), // input
        .I  (xpgmen?(~xfpgaprog):force_senspgm), // input
        .T  (~(xpgmen || force_senspgm))         // input - disable when reading DONE
        .T  (~(xpgmen || force_senspgm))         // input - disable when reading DONE
    );
    );
    // pullup for mrst (used as input for "DONE") and senspgm (grounded on sesnor boards)
    // pullup for mrst (used as input for "DONE") and senspgm (grounded on sensor boards)
    mpullup i_mrst_pullup(mrst);
    mpullup i_mrst_pullup(mrst);
    mpullup i_senspgm_pullup(senspgm);
    mpullup i_senspgm_pullup(senspgm);
    always @ (posedge mclk or posedge rst) begin
    always @ (posedge mclk or posedge rst) begin

sensor/sens_sync.v

0 → 100644
+198 −0
Original line number Original line Diff line number Diff line
/*******************************************************************************
 * Module: sens_sync
 * Date:2015-07-13  
 * Author: andrey     
 * 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/> .
 *******************************************************************************/
`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?) 
    
)(
    input         rst,         // global reset
    input         pclk,        // global clock input, pixel rate (96MHz for MT9P006)
    input         mclk,        // global system clock, synchronizes commands
    input         en,          // enable channel (0 resets counters)
    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;
        
        trigger_mode_pclk <= trigger_mode;
        
        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;
        
        if (!en || !trigger_mode_pclk) trig_r <=0;
        else if (trig_in)              trig_r <= ~trig_r;

        // 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 (
        .rst         (rst),           // input
        .clk         (mclk),          // input
        .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 (
        .rst         (rst),           // input
        .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 (
        .rst         (rst),           // input
        .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 (
        .rst         (rst),           // input
        .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 (
        .rst         (rst),           // input
        .src_clk     (pclk),          // input
        .dst_clk     (mclk),          // input
        .in_pulse    (pre_sof_late),  // input
        .out_pulse   (sof_late),      // output
        .busy() // output
    );
    
    
    


endmodule
Loading