Commit d4f2714d authored by Andrey Filippov's avatar Andrey Filippov

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

parent 3023d860
......@@ -70,7 +70,7 @@ module event_logger#(
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
input ts_stb_chn0, // @mclk 1 clock before ts_rcv_data is valid
......
......@@ -21,7 +21,7 @@
`timescale 1ns/1ps
/*
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(
......@@ -29,7 +29,7 @@ module imu_exttime393(
input mclk, // system clock, negedge TODO:COnvert to posedge!
input xclk, // half frequency (80 MHz nominal)
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
input ts_stb_chn0, // @mclk 1 clock before ts_rcv_data is valid
......
......@@ -260,7 +260,7 @@ module sens_histogram #(
.ADDR_MASK1 (0),
.ADDR2 (0),
.ADDR_MASK2 (0)
) cmd_deser_sens_i2c_i (
) cmd_deser_sens_histogram_i (
.rst (rst), // input
.clk (mclk), // input
.ad (cmd_ad), // input[7:0]
......
......@@ -26,8 +26,8 @@ module sens_parallel12 #(
parameter SENSIO_CTRL = 'h0,
parameter SENSIO_STATUS = 'h1,
parameter SENSIO_JTAG = 'h2,
parameter SENSIO_WIDTH = 'h3, // 1.. 2^16, 0 - use HACT
parameter SENSIO_DELAYS = 'h4, // 'h4..'h7
parameter SENSIO_WIDTH = 'h3, // set line width (1.. 2^16) if 0 - use HACT
parameter SENSIO_DELAYS = 'h4, // 'h4..'h7 - each address sets 4 delays through 4 bytes of 32-bit data
parameter SENSIO_STATUS_REG = 'h31,
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 ipclk2x,// twice frequency regenerated sensor clock (possibly to run external fifo)
// 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
input vact,
input hact, //output in fillfactory mode
inout vact,
inout hact, //output in fillfactory mode
inout bpf, // output in fillfactory mode
inout [11:0] pxd, //actually only 2 LSBs are inouts
inout mrst,
......@@ -88,7 +90,7 @@ module sens_parallel12 #(
inout arst,
inout aro,
output dclk,
output dclk, // externally connected to inout port
// output
output [11:0] pxd_out,
output vact_out,
......@@ -142,13 +144,14 @@ module sens_parallel12 #(
wire clkfb_pxd_stopped_mmcm;
// programmed resets to the sensor
reg iaro = 0;
reg iaro_soft = 0;
wire iaro;
reg iarst = 0;
reg imrst = 0;
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 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 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 iaro = trigger_mode? ~trig : iaro_soft;
always @(posedge rst or posedge mclk) begin
if (rst) data_r <= 0;
else if (cmd_we) data_r <= cmd_data;
if (rst) set_idelay <= 0;
else set_idelay <= {4{cmd_we}} & {(cmd_a==(SENSIO_DELAYS+3))?1'b1:1'b0,
(cmd_a==(SENSIO_DELAYS+2))?1'b1:1'b0,
(cmd_a==(SENSIO_DELAYS+1))?1'b1:1'b0,
(cmd_a==(SENSIO_DELAYS+0))?1'b1:1'b0};
else set_idelay <= {4{cmd_we}} & {(cmd_a==(SENSIO_DELAYS+3)),
(cmd_a==(SENSIO_DELAYS+2)),
(cmd_a==(SENSIO_DELAYS+1)),
(cmd_a==(SENSIO_DELAYS+0))};
if (rst) set_status_r <=0;
else set_status_r <= cmd_we && (cmd_a== SENSIO_STATUS);
if (rst) set_ctrl_r <=0;
......@@ -212,8 +216,8 @@ module sens_parallel12 #(
if (rst) iarst <= 0;
else if (set_ctrl_r && data_r[SENS_CTRL_ARST + 1]) iarst <= data_r[SENS_CTRL_ARST];
if (rst) iaro <= 0;
else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1]) iaro <= data_r[SENS_CTRL_ARO];
if (rst) iaro_soft <= 0;
else if (set_ctrl_r && data_r[SENS_CTRL_MRST + 1]) iaro_soft <= data_r[SENS_CTRL_ARO];
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];
......@@ -538,7 +542,7 @@ module sens_parallel12 #(
.I (xpgmen?(~xfpgaprog):force_senspgm), // input
.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_senspgm_pullup(senspgm);
always @ (posedge mclk or posedge rst) begin
......
/*******************************************************************************
* 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
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment