Commit 2675a8a1 authored by Andrey Filippov's avatar Andrey Filippov

Modified camsync393 to support individual delays/timestamps for 4 sesnor...

Modified camsync393 to support individual delays/timestamps for 4 sesnor channels, changed I/O to mclk domain
parent 919c5382
......@@ -32,14 +32,20 @@ module camsync393 #(
parameter CAMSYNC_ADDR = 'h160, //TODO: assign valid address
parameter CAMSYNC_MASK = 'h3f8,
parameter CAMSYNC_MODE = 'h0,
parameter CAMSYNC_TRIG_SRC = 'h4, // setup trigger source
parameter CAMSYNC_TRIG_DELAY = 'h5, // setup input trigger delay
parameter CAMSYNC_TRIG_DST = 'h6, // setup trigger destination line(s)
parameter CAMSYNC_TRIG_PERIOD = 'h7, // setup output trigger period
parameter CAMSYNC_TRIG_SRC = 'h1, // setup trigger source
parameter CAMSYNC_TRIG_DST = 'h2, // setup trigger destination line(s)
parameter CAMSYNC_TRIG_PERIOD = 'h3, // setup output trigger period
parameter CAMSYNC_TRIG_DELAY0 = 'h4, // setup input trigger delay
parameter CAMSYNC_TRIG_DELAY1 = 'h5, // setup input trigger delay
parameter CAMSYNC_TRIG_DELAY2 = 'h6, // setup input trigger delay
parameter CAMSYNC_TRIG_DELAY3 = 'h7, // setup input trigger delay
parameter CAMSYNC_SNDEN_BIT = 'h1, // enable writing ts_snd_en
parameter CAMSYNC_EXTERNAL_BIT = 'h3, // enable writing ts_external
parameter CAMSYNC_TRIGGERED_BIT = 'h5, // enable writing ts_external
parameter CAMSYNC_MASTER_BIT = 'h8, // select a 2-bit master channel (master delay may be used as a flash delay)
parameter CAMSYNC_CHN_EN_BIT = 'hd, // per-channel enable timestamp generation
parameter CAMSYNC_PRE_MAGIC = 6'b110100,
parameter CAMSYNC_POST_MAGIC = 6'b001101
......@@ -53,69 +59,116 @@ module camsync393 #(
// [3:2] +8 - reset ts_external, +'hc - set ts_external:
// 1 - use external timestamp, if available. 0 - always use local ts
// [5:4] +'h20 - reset triggered mode (free running sensor), +'h30 - set sensor triggered mode
// 4 - source of trigger (10 bit pairs, LSB - level to trigger, MSB - use this bit). All 0 - internal trigger
// in internal mode output has variable delay from the internal trigger (relative to sensor trigger)
// [8:6] +'h100 - set master channel (zero delay in internal trigger mode, delay used for flash output)
// [13:9] +'h2000 - set which channels to generate timestamp mesages
// 5 - input trigger delay (pixel clocks) (NOTE: 0 - trigger disabled - WRONG)
// 6 - 10 bit pairs: MSB - enable selected line, LSB - level to send when trigger active
// 1 - source of trigger (10 bit pairs, LSB - level to trigger, MSB - use this bit). All 0 - internal trigger
// in internal mode output has variable delay from the internal trigger (relative to sensor trigger)
// 2 - 10 bit pairs: MSB - enable selected line, LSB - level to send when trigger active
// bit 25==1 some of the bits use test mode signals:
// 7 - output trigger period (duration constant of 256 pixel clocks).
// 3 - output trigger period (duration constant of 256 pixel clocks).
// d==0 - disable (stop periodic mode)
// d==1 - single trigger
// d==2..255 - set output pulse / input-output serial bit duration (no start generated)
// 256>=d - repetitive trigger
input pclk, // pixel clock (global)
// 4..7 - input trigger delay (in pclk periods)
input pclk, // pixel clock (global) - switch it to 100MHz (mclk/2)?
output triggered_mode, // use triggered mode (0 - sensor is free-running) @mclk
// trigrst is already combined with cb_sensor_trigger
input trigrst, // single-clock start of frame input (resets trigger output) posedge
input [9:0] gpio_in, // 12-bit input from GPIO pins -> 10 bit
output [9:0] gpio_out,// 12-bit output to GPIO pins
output reg [9:0] gpio_out_en,// 12-bit output enable to GPIO pins
output trigger1, // 1 cycle-long trigger output
output trigger, // active high trigger to the sensor (reset by vacts)
output reg overdue, // prevents lock-up when no vact was detected during one period and trigger was toggled
// TODO: change to control bit fields
// input ts_snd_en, // enable sending timestamp over sync line
// input ts_external, // 1 - use external timestamp, if available. 0 - always use local ts
output triggered_mode, // use triggered mode (0 - sensors are free-running) @mclk
input frsync_chn0, // @mclk trigrst, // single-clock start of frame input (resets trigger output) posedge (@pclk)
output trigger1_chn0, // @mclk 1 cycle-long trigger output
output trigger_chn0, // @mclk active high trigger to the sensor (reset by vacts)
output overdue_chn0, // @mclk prevents lock-up when no vact was detected during one period and trigger was toggled
input frsync_chn1, // @mclk trigrst, // single-clock start of frame input (resets trigger output) posedge (@pclk)
output trigger1_chn1, // 1 cycle-long trigger output
output trigger_chn1, // active high trigger to the sensor (reset by vacts)
output overdue_chn1, // prevents lock-up when no vact was detected during one period and trigger was toggled
input frsync_chn2, // @mclk trigrst, // single-clock start of frame input (resets trigger output) posedge (@pclk)
output trigger1_chn2, // 1 cycle-long trigger output
output trigger_chn2, // active high trigger to the sensor (reset by vacts)
output overdue_chn2, // prevents lock-up when no vact was detected during one period and trigger was toggled
input frsync_chn3, // @mclk trigrst, // single-clock start of frame input (resets trigger output) posedge (@pclk)
output trigger1_chn3, // 1 cycle-long trigger output
output trigger_chn3, // active high trigger to the sensor (reset by vacts)
output overdue_chn3, // prevents lock-up when no vact was detected during one period and trigger was toggled
// getting timestamp from rtc module, all @posedge mclk (from timestmp_snapshot)
// this timestmp is used either to send local timestamp for synchronization, or
// to acquire local timestamp of sync pulse for logging
output ts_snap_mclk, // make a timestamp pulse single @(posedge pclk)
// timestamp should be valid in <16 pclk cycles
input ts_snd_stb, // 1 clk before ts_snd_data is valid
input [7:0] ts_snd_data, // byte-wide serialized timestamp message
// TODO: remove next 2
// input [31:0] ts_snd_sec, // [31:0] timestamp seconds to be sent over the sync line
// input [19:0] ts_snd_usec, // [19:0] timestamp microseconds to be sent over the sync line
output ts_snap_mclk_chn0, // ts_snap_mclk make a timestamp pulse single @(posedge pclk)
input ts_snd_stb_chn0, // 1 clk before ts_snd_data is valid
input [7:0] ts_snd_data_chn0, // byte-wide serialized timestamp message
output ts_snap_mclk_chn1, // ts_snap_mclk make a timestamp pulse single @(posedge pclk)
input ts_snd_stb_chn1, // 1 clk before ts_snd_data is valid
input [7:0] ts_snd_data_chn1, // byte-wide serialized timestamp message
output ts_snap_mclk_chn2, // ts_snap_mclk make a timestamp pulse single @(posedge pclk)
input ts_snd_stb_chn2, // 1 clk before ts_snd_data is valid
input [7:0] ts_snd_data_chn2, // byte-wide serialized timestamp message
output ts_snap_mclk_chn3, // ts_snap_mclk make a timestamp pulse single @(posedge pclk)
input ts_snd_stb_chn3, // 1 clk before ts_snd_data is valid
input [7:0] ts_snd_data_chn3, // byte-wide serialized timestamp message
//ts_rcv_*sec (@mclk) goes to the following receivers:
//ts_sync_*sec (synchronized to sensor clock) -> timestamp353
//ts_sync_*sec (synchronized to sensor clock) -> timestamp353 REMOVED
//ts_sync_*sec (synchronized to sensor clock) -> compressor
//ts_sync_*sec (synchronized to sensor clock) -> imu_logger
output ts_rcv_stb, // 1 clock before ts_rcv_data is valid
output [7:0] ts_rcv_data // byte-wide serialized timestamp message received or local
// This timestamp is either received, got from internal timer (both common to all 4 channels)
// or it is a free-running timestamp
output ts_rcv_stb_chn0, // 1 clock before ts_rcv_data is valid
output [7:0] ts_rcv_data_chn0, // byte-wide serialized timestamp message received or local
output ts_rcv_stb_chn1, // 1 clock before ts_rcv_data is valid
output [7:0] ts_rcv_data_chn1, // byte-wide serialized timestamp message received or local
// TODO: remove next 3
// output reg [31:0] ts_rcv_sec, // [31:0] timestamp seconds received over the sync line
// output reg [19:0] ts_rcv_usec,// [19:0] timestamp microseconds received over the sync line
// output ts_stb); // strobe when received timestamp is valid
output ts_rcv_stb_chn2, // 1 clock before ts_rcv_data is valid
output [7:0] ts_rcv_data_chn2, // byte-wide serialized timestamp message received or local
output ts_rcv_stb_chn3, // 1 clock before ts_rcv_data is valid
output [7:0] ts_rcv_data_chn3 // byte-wide serialized timestamp message received or local
);
// TODO: change to control bit fields
reg ts_snd_en; // enable sending timestamp over sync line
reg ts_external; // 1 - use external timestamp, if available. 0 - always use local ts
reg triggered_mode_r;
// TODO: remove next 2
wire [31:0] ts_snd_sec; // [31:0] timestamp seconds to be sent over the sync line
wire [19:0] ts_snd_usec; // [19:0] timestamp microseconds to be sent over the sync line
reg [31:0] ts_rcv_sec; // [31:0] timestamp seconds received over the sync line
reg [19:0] ts_rcv_usec;// [19:0] timestamp microseconds received over the sync line
wire ts_stb; // strobe when received timestamp is valid
reg [31:0] ts_snd_sec; // [31:0] timestamp seconds to be sent over the sync line - multiplexed from master channel
reg [19:0] ts_snd_usec; // [19:0] timestamp microseconds to be sent over the sync line
wire [31:0] ts_snd_sec_chn0; // [31:0] timestamp seconds to be sent over the sync line
wire [19:0] ts_snd_usec_chn0; // [19:0] timestamp microseconds to be sent over the sync line
reg [31:0] ts_rcv_sec_chn0; // [31:0] timestamp seconds received over the sync line
reg [19:0] ts_rcv_usec_chn0;// [19:0] timestamp microseconds received over the sync line
wire [3:0] ts_stb; // strobe when received timestamp is valid
wire [31:0] ts_snd_sec_chn1; // [31:0] timestamp seconds to be sent over the sync line
wire [19:0] ts_snd_usec_chn1; // [19:0] timestamp microseconds to be sent over the sync line
reg [31:0] ts_rcv_sec_chn1; // [31:0] timestamp seconds received over the sync line
reg [19:0] ts_rcv_usec_chn1;// [19:0] timestamp microseconds received over the sync line
wire [31:0] ts_snd_sec_chn2; // [31:0] timestamp seconds to be sent over the sync line
wire [19:0] ts_snd_usec_chn2; // [19:0] timestamp microseconds to be sent over the sync line
reg [31:0] ts_rcv_sec_chn2; // [31:0] timestamp seconds received over the sync line
reg [19:0] ts_rcv_usec_chn2;// [19:0] timestamp microseconds received over the sync line
wire [31:0] ts_snd_sec_chn3; // [31:0] timestamp seconds to be sent over the sync line
wire [19:0] ts_snd_usec_chn3; // [19:0] timestamp microseconds to be sent over the sync line
reg [31:0] ts_rcv_sec_chn3; // [31:0] timestamp seconds received over the sync line
reg [19:0] ts_rcv_usec_chn3;// [19:0] timestamp microseconds received over the sync line
......@@ -125,12 +178,14 @@ module camsync393 #(
wire set_mode_reg_w;
wire set_trig_src_w;
wire set_trig_delay_w;
wire set_trig_delay0_w;
wire set_trig_delay1_w;
wire set_trig_delay2_w;
wire set_trig_delay3_w;
wire set_trig_dst_w;
wire set_trig_period_w;
wire [9:0] pre_input_use;
wire [9:0] pre_input_pattern;
// delaying everything by 1 clock to reduce data fan in
reg high_zero; // 24 MSBs are zero
......@@ -138,7 +193,12 @@ module camsync393 #(
reg [9:0] input_pattern; // data to be compared for trigger event to take place
reg pre_input_use_intern;// @(posedge mclk) Use internal trigger generator, 0 - use external trigger (also switches delay from input to output)
reg input_use_intern;// @(posedge clk)
reg [31:0] input_dly; // delay value for the trigger
reg [31:0] input_dly_chn0; // delay value for the trigger
reg [31:0] input_dly_chn1; // delay value for the trigger
reg [31:0] input_dly_chn2; // delay value for the trigger
reg [31:0] input_dly_chn3; // delay value for the trigger
reg [3:0] chn_en; // enable channels
reg [1:0] master_chn; // master channel (internal mode - delay used for flash)
reg [9:0] gpio_active; // output levels on the selected GPIO lines during output pulse (will be negated when inactive)
reg testmode; // drive some internal signals to GPIO bits
reg outsync; // during output active
......@@ -156,13 +216,18 @@ module camsync393 #(
reg trigger_condition_d; // GPIO input trigger condition met, delayed (for edge detection)
reg trigger_condition_filtered; // trigger condition filtered
reg [6:0] trigger_filter_cntr;
reg trigger1_r;
reg [3:0] trigger1_r;
wire [3:0] trigger1_r_mclk;
// wire trigger1_dly16; // trigger1 delayed by 16 clk cycles to get local timestamp
reg trigger_r=0; // for happy simulator
reg [3:0] trigger_r=0; // for happy simulator
reg start_dly; // start delay (external input filtered or from internal single/rep)
reg [31:0] dly_cntr; // trigger delay counter
reg dly_cntr_run=0; // trigger delay counter running (to use FD for simulation)
reg dly_cntr_run_d=0; // trigger delay counter running - delayed by 1
reg [31:0] dly_cntr_chn0; // trigger delay counter
reg [31:0] dly_cntr_chn1; // trigger delay counter
reg [31:0] dly_cntr_chn2; // trigger delay counter
reg [31:0] dly_cntr_chn3; // trigger delay counter
reg [3:0] dly_cntr_run=0; // trigger delay counter running (to use FD for simulation)
reg [3:0] dly_cntr_run_d=0; // trigger delay counter running - delayed by 1
wire [3:0] dly_cntr_end;
wire pre_start_out_pulse;
reg start_out_pulse; /// start generation of output pulse. In internal trigger mode uses delay counter, in external - no delay
reg [31:0] pre_period;
......@@ -205,72 +270,95 @@ module camsync393 #(
reg ts_external_pclk; // 1 - use external timestamp (combines ts_external and input_use_intern)
reg triggered_mode_pclk;
// reg ts_stb_r; // strobe when received timestamp is valid (single mclk cycle)
// reg ts_stb_pclk;
// reg [2:0] ts_pre_stb;
wire local_got; // received local timestamp (@ posedge mclk)
wire local_got_pclk; // local_got reclocked @pclk
reg ts_snap; // make a timestamp pulse single @(posedge pclk)
wire trigrst_or_freerun; // trigger reset (2pclk, vacts) or sensor is in fre running mode
wire [3:0] local_got; // received local timestamp (@ posedge mclk)
wire [3:0] local_got_pclk; // local_got reclocked @pclk
wire [3:0] frame_sync;
reg [3:0] ts_snap_triggered; // make a timestamp pulse single @(posedge pclk)
wire [3:0] ts_snap_triggered_mclk; // make a timestamp pulse single @(posedge pclk)
reg [3:0] overdue;
//! in testmode GPIO[9] and GPIO[8] use internal signals instead of the outsync:
//! bit 11 - same as TRIGGER output to the sensor (signal to the sensor may be disabled externally)
//! then that bit will be still from internall trigger to frame valid
//! bit 10 - dly_cntr_run (delay counter run) - active during trigger delay
assign rcv_run=rcv_run_or_deaf && bit_rcv_counter[6];
assign bit_length_plus1 [ 7:0] =bit_length[7:0]+1;
assign pre_start_out_pulse=input_use_intern?(dly_cntr_run_d && !dly_cntr_run):start_late;
assign dly_cntr_end= dly_cntr_run_d & ~dly_cntr_run;
assign pre_start_out_pulse=input_use_intern?dly_cntr_end[master_chn]:start_late;
assign gpio_out[7: 0] = out_data? gpio_active[7: 0]: ~gpio_active[7: 0];
assign gpio_out[8] = (testmode? dly_cntr_run: out_data)? gpio_active[8]: ~gpio_active[8];
assign gpio_out[9] = (testmode? trigger_r: out_data)? gpio_active[9]: ~gpio_active[9];
assign gpio_out[8] = (testmode? dly_cntr_run[0]: out_data)? gpio_active[8]: ~gpio_active[8];
assign gpio_out[9] = (testmode? trigger_r[0]: out_data)? gpio_active[9]: ~gpio_active[9];
assign restart= restart_cntr_run[1] && !restart_cntr_run[0];
assign pre_set_bit= (|cmd_data[31:8]==0) && |cmd_data[7:1]; // 2..255
assign pre_start0= |cmd_data[31:0] && !pre_set_bit;
assign pre_set_period = !pre_set_bit;
assign trigger = trigger_r;
assign trigger1 = trigger1_r;
// assign ts_stb = ts_stb_r;
assign {trigger_chn3, trigger_chn2, trigger_chn1, trigger_chn0} = trigger_r;
assign {trigger1_chn3, trigger1_chn2, trigger1_chn1, trigger1_chn0} = trigger1_r_mclk;
assign {overdue_chn3, overdue_chn2, overdue_chn1, overdue_chn0} = overdue;
assign frame_sync = {frsync_chn3, frsync_chn2, frsync_chn1, frsync_chn0};
assign set_mode_reg_w = cmd_we && (cmd_a == CAMSYNC_MODE);
assign set_trig_src_w = cmd_we && (cmd_a == CAMSYNC_TRIG_SRC);
assign set_trig_delay_w = cmd_we && (cmd_a == CAMSYNC_TRIG_DELAY);
assign set_trig_dst_w = cmd_we && (cmd_a == CAMSYNC_TRIG_DST);
assign set_trig_period_w = cmd_we && (cmd_a == CAMSYNC_TRIG_PERIOD);
assign set_trig_delay0_w = cmd_we && (cmd_a == CAMSYNC_TRIG_DELAY0);
assign set_trig_delay1_w = cmd_we && (cmd_a == CAMSYNC_TRIG_DELAY1);
assign set_trig_delay2_w = cmd_we && (cmd_a == CAMSYNC_TRIG_DELAY2);
assign set_trig_delay3_w = cmd_we && (cmd_a == CAMSYNC_TRIG_DELAY3);
assign pre_input_use = {cmd_data[19],cmd_data[17],cmd_data[15],cmd_data[13],cmd_data[11],cmd_data[9],cmd_data[7],cmd_data[5],cmd_data[3],cmd_data[1]};
assign pre_input_pattern = {cmd_data[18],cmd_data[16],cmd_data[14],cmd_data[12],cmd_data[10],cmd_data[8],cmd_data[6],cmd_data[4],cmd_data[2],cmd_data[0]};
assign triggered_mode = triggered_mode_r;
assign trigrst_or_freerun = trigrst || !triggered_mode_pclk;
assign {ts_snap_mclk_chn3, ts_snap_mclk_chn2, ts_snap_mclk_chn1, ts_snap_mclk_chn0 } = triggered_mode? ts_snap_triggered_mclk: frame_sync;
always @(posedge mclk) begin
if (set_mode_reg_w) begin
if (cmd_data[CAMSYNC_SNDEN_BIT]) ts_snd_en <= cmd_data[CAMSYNC_SNDEN_BIT - 1];
if (cmd_data[CAMSYNC_EXTERNAL_BIT]) ts_external <= cmd_data[CAMSYNC_EXTERNAL_BIT - 1];
if (cmd_data[CAMSYNC_TRIGGERED_BIT]) triggered_mode_r <= cmd_data[CAMSYNC_TRIGGERED_BIT - 1];
if (cmd_data[CAMSYNC_MASTER_BIT]) master_chn <= cmd_data[CAMSYNC_MASTER_BIT - 1 -: 2];
if (cmd_data[CAMSYNC_CHN_EN_BIT]) chn_en <= cmd_data[CAMSYNC_CHN_EN_BIT - 1 -: 4];
end
if (set_trig_src_w) begin
input_use <= pre_input_use;
input_pattern <= pre_input_pattern;
pre_input_use_intern <= (pre_input_use == 0); // use internal source for triggering
end
if (set_trig_delay_w) begin
input_dly[31:0] <= cmd_data[31:0];
if (set_trig_delay0_w) begin
input_dly_chn0[31:0] <= cmd_data[31:0];
end
if (set_trig_delay1_w) begin
input_dly_chn1[31:0] <= cmd_data[31:0];
end
if (set_trig_delay2_w) begin
input_dly_chn2[31:0] <= cmd_data[31:0];
end
if (set_trig_delay3_w) begin
input_dly_chn3[31:0] <= cmd_data[31:0];
end
if (set_trig_dst_w) begin
gpio_out_en[9:0] <= {cmd_data[19],cmd_data[17],cmd_data[15],cmd_data[13],cmd_data[11],cmd_data[9],cmd_data[7],cmd_data[5],cmd_data[3],cmd_data[1]};
gpio_active[9:0] <= {cmd_data[18],cmd_data[16],cmd_data[14],cmd_data[12],cmd_data[10],cmd_data[8],cmd_data[6],cmd_data[4],cmd_data[2],cmd_data[0]};
testmode <= cmd_data[24];
end
if (set_trig_period_w) begin
pre_period[31:0] <= cmd_data[31:0];
high_zero <= cmd_data[31:8]==24'b0;
end
start0 <= set_trig_period_w && pre_start0;
set_bit <= set_trig_period_w && pre_set_bit;
set_period <= set_trig_period_w && pre_set_period;
......@@ -284,53 +372,90 @@ module camsync393 #(
start_en <= (repeat_period[31:0]!=0);
if (set_period) rep_en <= !high_zero;
end
always @ (posedge pclk) begin
ts_snap <= (start_pclk[2] && ts_snd_en_pclk) || //strobe by internal generator if output timestamp is enabled
(trigger1_r && !ts_external_pclk); // get local timestamp of trigger1_r if it is used
case (master_chn)
2'h0: begin
ts_snd_sec <= ts_snd_sec_chn0;
ts_snd_usec <= ts_snd_usec_chn0;
end
2'h1: begin
ts_snd_sec <= ts_snd_sec_chn1;
ts_snd_usec <= ts_snd_usec_chn1;
end
2'h2: begin
ts_snd_sec <= ts_snd_sec_chn2;
ts_snd_usec <= ts_snd_usec_chn2;
end
2'h3: begin
ts_snd_sec <= ts_snd_sec_chn3;
ts_snd_usec <= ts_snd_usec_chn3;
end
endcase
end
always @ (posedge pclk) begin
ts_snap_triggered <= chn_en & ({4{(start_pclk[2] & ts_snd_en_pclk)}} | //strobe by internal generator if output timestamp is enabled
(trigger1_r & ~{4{ts_external_pclk}})); // get local timestamp of the trigger (ext/int)
ts_snd_en_pclk<=ts_snd_en;
input_use_intern <= pre_input_use_intern;
ts_external_pclk<= ts_external && !input_use_intern;
ts_snd_en_pclk<=ts_snd_en;
input_use_intern <= pre_input_use_intern;
ts_external_pclk<= ts_external && !input_use_intern;
start_pclk[2:0] <= {(restart && rep_en) || (start_pclk[1] && !restart_cntr_run[1] && !restart_cntr_run[0] && !start_pclk[2]),
start_pclk[0],
start_to_pclk && !start_pclk[0]};
restart_cntr_run[1:0] <= {restart_cntr_run[0],start_en && (start_pclk[2] || (restart_cntr_run[0] && (restart_cntr[31:2] !=0)))};
if (restart_cntr_run[0]) restart_cntr[31:0] <= restart_cntr[31:0] - 1;
else restart_cntr[31:0] <= repeat_period[31:0];
start_pclk[2:0] <= {(restart && rep_en) || (start_pclk[1] && !restart_cntr_run[1] && !restart_cntr_run[0] && !start_pclk[2]),
start_pclk[0],
start_to_pclk && !start_pclk[0]};
restart_cntr_run[1:0] <= {restart_cntr_run[0],start_en && (start_pclk[2] || (restart_cntr_run[0] && (restart_cntr[31:2] !=0)))};
if (restart_cntr_run[0]) restart_cntr[31:0] <= restart_cntr[31:0] - 1;
else restart_cntr[31:0] <= repeat_period[31:0];
start_out_pulse <= pre_start_out_pulse;
start_out_pulse <= pre_start_out_pulse;
/// Generating output pulse - 64* bit_length if timestamp is disabled or
/// 64 bits with encoded timestamp, including pre/post magic for error detectrion
outsync <= start_en && (start_out_pulse || (outsync && !((bit_snd_duration[7:0]==0) &&(bit_snd_counter[5:0]==0))));
if (!outsync || (bit_snd_duration[7:0]==0)) bit_snd_duration[7:0] <= bit_length[7:0];
else bit_snd_duration[7:0] <= bit_snd_duration[7:0] - 1;
bit_snd_duration_zero <= bit_snd_duration[7:0]==8'h1;
outsync <= start_en && (start_out_pulse || (outsync && !((bit_snd_duration[7:0]==0) &&(bit_snd_counter[5:0]==0))));
if (!outsync || (bit_snd_duration[7:0]==0)) bit_snd_duration[7:0] <= bit_length[7:0];
else bit_snd_duration[7:0] <= bit_snd_duration[7:0] - 1;
bit_snd_duration_zero <= bit_snd_duration[7:0]==8'h1;
if (!outsync) bit_snd_counter[5:0] <=ts_snd_en_pclk?63:3; /// when no ts serial, send pulse 4 periods long (max 1024 pclk)
if (!outsync) bit_snd_counter[5:0] <=ts_snd_en_pclk?63:3; /// when no ts serial, send pulse 4 periods long (max 1024 pclk)
/// Same bit length (1/4) is used in input filter/de-glitcher
else if (bit_snd_duration[7:0]==0) bit_snd_counter[5:0] <= bit_snd_counter[5:0] -1;
else if (bit_snd_duration[7:0]==0) bit_snd_counter[5:0] <= bit_snd_counter[5:0] -1;
if (!outsync) sr_snd_first[31:0] <= {CAMSYNC_PRE_MAGIC,ts_snd_sec[31:6]};
else if (bit_snd_duration_zero) sr_snd_first[31:0] <={sr_snd_first[30:0],sr_snd_second[31]};
if (!outsync) sr_snd_second[31:0] <= {ts_snd_sec[5:0], ts_snd_usec[19:0],CAMSYNC_POST_MAGIC};
else if (bit_snd_duration_zero) sr_snd_second[31:0] <={sr_snd_second[30:0],1'b0};
out_data <=outsync && (ts_snd_en_pclk?sr_snd_first[31]:1'b1);
if (!outsync) sr_snd_first[31:0] <= {CAMSYNC_PRE_MAGIC,ts_snd_sec[31:6]};
else if (bit_snd_duration_zero) sr_snd_first[31:0] <={sr_snd_first[30:0],sr_snd_second[31]};
if (!outsync) sr_snd_second[31:0] <= {ts_snd_sec[5:0], ts_snd_usec[19:0],CAMSYNC_POST_MAGIC};
else if (bit_snd_duration_zero) sr_snd_second[31:0] <={sr_snd_second[30:0],1'b0};
out_data <=outsync && (ts_snd_en_pclk?sr_snd_first[31]:1'b1);
end
always @ (posedge rst or posedge pclk) begin
if (rst) dly_cntr_run <= 0;
else dly_cntr_run <= triggered_mode_pclk && (start_dly || (dly_cntr_run && (dly_cntr[31:0]!=0)));
if (rst) trigger_r <= 0;
else trigger_r <= trigrst_or_freerun ? 1'b0 : (trigger1_r ^ trigger_r);
if (rst) dly_cntr_run <= 0;
else if (!triggered_mode_pclk) dly_cntr_run <= 0;
else if (start_dly) dly_cntr_run <= 4'hf;
else dly_cntr_run <= dly_cntr_run &
{(dly_cntr_chn3[31:0]!=0)?1'b1:1'b0,
(dly_cntr_chn2[31:0]!=0)?1'b1:1'b0,
(dly_cntr_chn1[31:0]!=0)?1'b1:1'b0,
(dly_cntr_chn0[31:0]!=0)?1'b1:1'b0};
end
always @ (posedge rst or posedge mclk) begin
if (rst) trigger_r <= 0;
else if (!triggered_mode) trigger_r <= 0;
else trigger_r <= ~frame_sync & (trigger1_r_mclk ^ trigger_r);
if (rst) overdue <= 0;
else if (!triggered_mode) overdue <= 0;
else overdue <= ((overdue ^ trigger_r) & trigger1_r_mclk) ^ overdue;
end
// Detecting input sync pulse (filter - 64 pclk, pulse is 256 pclk)
// even more for simulator
// FD i_dly_cntr_run (.C(pclk),.D(triggered_mode && (start_dly || (dly_cntr_run && (dly_cntr[31:0]!=0)))),.Q(dly_cntr_run)); // for simulator to be happy
/// Now trigger1_r toggles trigger output to prevent lock-up if no vacts
/// Lock-up could take place if:
......@@ -341,66 +466,102 @@ module camsync393 #(
assign pre_rcv_error= (sr_rcv_first[31:26]!=CAMSYNC_PRE_MAGIC) || (sr_rcv_second[5:0]!=CAMSYNC_POST_MAGIC);
always @ (posedge pclk) begin
if (trigrst_or_freerun) overdue <= 1'b0;
else if (trigger1_r) overdue <= trigger;
triggered_mode_pclk<= triggered_mode_r;
bit_length_short[7:0] <= bit_length[7:0]-bit_length_plus1[7:2]-1; // 3/4 of the duration
triggered_mode_pclk<= triggered_mode_r;
bit_length_short[7:0] <= bit_length[7:0]-bit_length_plus1[7:2]-1; // 3/4 of the duration
trigger_condition <= (((gpio_in[9:0] ^ input_pattern[9:0]) & input_use[9:0]) == 10'b0);
trigger_condition_d <= trigger_condition;
trigger_condition <= (((gpio_in[9:0] ^ input_pattern[9:0]) & input_use[9:0]) == 10'b0);
trigger_condition_d <= trigger_condition;
if (!triggered_mode_pclk || (trigger_condition !=trigger_condition_d)) trigger_filter_cntr <= {1'b0,bit_length[7:2]};
else if (!trigger_filter_cntr[6]) trigger_filter_cntr<=trigger_filter_cntr-1;
if (!triggered_mode_pclk || (trigger_condition !=trigger_condition_d)) trigger_filter_cntr <= {1'b0,bit_length[7:2]};
else if (!trigger_filter_cntr[6]) trigger_filter_cntr<=trigger_filter_cntr-1;
if (input_use_intern) trigger_condition_filtered <= 1'b0;
else if (trigger_filter_cntr[6]) trigger_condition_filtered <= trigger_condition_d;
if (input_use_intern) trigger_condition_filtered <= 1'b0;
else if (trigger_filter_cntr[6]) trigger_condition_filtered <= trigger_condition_d;
rcv_run_or_deaf <= start_en && (trigger_condition_filtered ||
(rcv_run_or_deaf && !(bit_rcv_duration_zero && (bit_rcv_counter[6:0]==0))));
rcv_run_or_deaf <= start_en && (trigger_condition_filtered ||
(rcv_run_or_deaf && !(bit_rcv_duration_zero && (bit_rcv_counter[6:0]==0))));
rcv_run_d <= rcv_run;
start_dly <= input_use_intern ? (start_late && start_en) : (rcv_run && !rcv_run_d);
rcv_run_d <= rcv_run;
start_dly <= input_use_intern ? (start_late && start_en) : (rcv_run && !rcv_run_d); // all start at the same time - master/others
// simulation problems w/o "start_en &&" ?
dly_cntr_run_d <= dly_cntr_run;
if (dly_cntr_run) dly_cntr[31:0] <= dly_cntr[31:0] -1;
else dly_cntr[31:0] <= input_dly[31:0];
trigger1_r <= input_use_intern ? (start_late && start_en):(dly_cntr_run_d && !dly_cntr_run);/// bypass delay to trigger1_r in internal trigger mode
dly_cntr_run_d <= dly_cntr_run;
if (dly_cntr_run[0]) dly_cntr_chn0[31:0] <= dly_cntr_chn0[31:0] -1;
else dly_cntr_chn0[31:0] <= input_dly_chn0[31:0];
if (dly_cntr_run[1]) dly_cntr_chn1[31:0] <= dly_cntr_chn1[31:0] -1;
else dly_cntr_chn1[31:0] <= input_dly_chn1[31:0];
if (dly_cntr_run[2]) dly_cntr_chn2[31:0] <= dly_cntr_chn2[31:0] -1;
else dly_cntr_chn2[31:0] <= input_dly_chn2[31:0];
if (dly_cntr_run[3]) dly_cntr_chn3[31:0] <= dly_cntr_chn3[31:0] -1;
else dly_cntr_chn3[31:0] <= input_dly_chn3[31:0];
/// bypass delay to trigger1_r in internal trigger mode
trigger1_r[0] <= (input_use_intern && (master_chn ==0)) ? (start_late && start_en):(dly_cntr_run_d[0] && !dly_cntr_run[0]);
trigger1_r[1] <= (input_use_intern && (master_chn ==1)) ? (start_late && start_en):(dly_cntr_run_d[1] && !dly_cntr_run[1]);
trigger1_r[2] <= (input_use_intern && (master_chn ==2)) ? (start_late && start_en):(dly_cntr_run_d[2] && !dly_cntr_run[2]);
trigger1_r[3] <= (input_use_intern && (master_chn ==3)) ? (start_late && start_en):(dly_cntr_run_d[3] && !dly_cntr_run[3]);
/// 64-bit serial receiver (52 bit payload, 6 pre magic and 6 bits post magic for error checking
if (!rcv_run_or_deaf) bit_rcv_duration[7:0] <= bit_length_short[7:0]; // 3/4 bit length-1
else if (bit_rcv_duration[7:0]==0) bit_rcv_duration[7:0] <= bit_length[7:0]; // bit length-1
else bit_rcv_duration[7:0] <= bit_rcv_duration[7:0]-1;
bit_rcv_duration_zero <= bit_rcv_duration[7:0]==8'h1;
if (!rcv_run_or_deaf) bit_rcv_counter[6:0] <= 127;
else if (bit_rcv_duration_zero) bit_rcv_counter[6:0] <= bit_rcv_counter[6:0] -1;
if (rcv_run && bit_rcv_duration_zero) begin
sr_rcv_first[31:0] <={sr_rcv_first[30:0],sr_rcv_second[31]};
sr_rcv_second[31:0] <={sr_rcv_second[30:0],trigger_condition_filtered};
end
rcv_done_rq <= start_en && ((ts_external_pclk && local_got_pclk) || (rcv_done_rq && rcv_run));
rcv_done_rq_d <= rcv_done_rq;
rcv_done <= rcv_done_rq_d && !rcv_done_rq;
if (!rcv_run_or_deaf) bit_rcv_duration[7:0] <= bit_length_short[7:0]; // 3/4 bit length-1
else if (bit_rcv_duration[7:0]==0) bit_rcv_duration[7:0] <= bit_length[7:0]; // bit length-1
else bit_rcv_duration[7:0] <= bit_rcv_duration[7:0]-1;
bit_rcv_duration_zero <= bit_rcv_duration[7:0]==8'h1;
if (!rcv_run_or_deaf) bit_rcv_counter[6:0] <= 127;
else if (bit_rcv_duration_zero) bit_rcv_counter[6:0] <= bit_rcv_counter[6:0] -1;
if (rcv_run && bit_rcv_duration_zero) begin
sr_rcv_first[31:0] <={sr_rcv_first[30:0],sr_rcv_second[31]};
sr_rcv_second[31:0] <={sr_rcv_second[30:0],trigger_condition_filtered};
end
rcv_done_rq <= start_en && ((ts_external_pclk && local_got_pclk) || (rcv_done_rq && rcv_run));
rcv_done_rq_d <= rcv_done_rq;
rcv_done <= rcv_done_rq_d && !rcv_done_rq;
rcv_error <= pre_rcv_error;
if (rcv_done) begin
ts_rcv_sec [31:0] <= {sr_rcv_first[25:0],sr_rcv_second[31:26]};
ts_rcv_usec [19:0] <= rcv_error?20'hfffff: sr_rcv_second[25:6];
end else if (!triggered_mode_pclk || (!ts_external_pclk && local_got_pclk )) begin
ts_rcv_sec [31:0] <= ts_snd_sec [31:0];
ts_rcv_usec [19:0] <= ts_snd_usec[19:0];
end
rcv_error <= pre_rcv_error;
if (rcv_done) begin
ts_rcv_sec_chn0 [31:0] <= {sr_rcv_first[25:0],sr_rcv_second[31:26]};
ts_rcv_usec_chn0 [19:0] <= rcv_error?20'hfffff: sr_rcv_second[25:6];
end else if (!triggered_mode_pclk || (!ts_external_pclk && local_got_pclk[0])) begin
ts_rcv_sec_chn0[31:0] <= ts_snd_sec_chn0 [31:0];
ts_rcv_usec_chn0[19:0] <= ts_snd_usec_chn0[19:0];
end
if (rcv_done) begin
ts_rcv_sec_chn1 [31:0] <= {sr_rcv_first[25:0],sr_rcv_second[31:26]};
ts_rcv_usec_chn1 [19:0] <= rcv_error?20'hfffff: sr_rcv_second[25:6];
end else if (!triggered_mode_pclk || (!ts_external_pclk && local_got_pclk[1])) begin
ts_rcv_sec_chn1[31:0] <= ts_snd_sec_chn1 [31:0];
ts_rcv_usec_chn1[19:0] <= ts_snd_usec_chn1[19:0];
end
if (rcv_done) begin
ts_rcv_sec_chn2 [31:0] <= {sr_rcv_first[25:0],sr_rcv_second[31:26]};
ts_rcv_usec_chn2 [19:0] <= rcv_error?20'hfffff: sr_rcv_second[25:6];
end else if (!triggered_mode_pclk || (!ts_external_pclk && local_got_pclk[2])) begin
ts_rcv_sec_chn2[31:0] <= ts_snd_sec_chn2 [31:0];
ts_rcv_usec_chn2[19:0] <= ts_snd_usec_chn2[19:0];
end
if (rcv_done) begin
ts_rcv_sec_chn3 [31:0] <= {sr_rcv_first[25:0],sr_rcv_second[31:26]};
ts_rcv_usec_chn3 [19:0] <= rcv_error?20'hfffff: sr_rcv_second[25:6];
end else if (!triggered_mode_pclk || (!ts_external_pclk && local_got_pclk[3])) begin
ts_rcv_sec_chn3[31:0] <= ts_snd_sec_chn3 [31:0];
ts_rcv_usec_chn3[19:0] <= ts_snd_usec_chn3[19:0];
end
end
assign ts_stb = rcv_done_mclk || (local_got && (!ts_external || pre_input_use_intern));
assign ts_stb = (!ts_external || pre_input_use_intern) ? local_got : {4{rcv_done_mclk}};
// Making delayed start that waits for timestamp use timestamp_got, otherwize - nothing to wait
assign start_late = ts_snd_en_pclk?local_got_pclk : start_pclk[2];
assign start_late = ts_snd_en_pclk?local_got_pclk[master_chn] : start_pclk[2];
cmd_deser #(
......@@ -419,27 +580,93 @@ module camsync393 #(
.we (cmd_we) // output
);
timestamp_to_parallel timestamp_to_parallel_i (
timestamp_to_parallel timestamp_to_parallel0_i (
.clk (mclk), // input
.pre_stb (ts_snd_stb_chn0), // input
.tdata (ts_snd_data_chn0), // input[7:0]
.sec (ts_snd_sec_chn0), // output[31:0] reg
.usec (ts_snd_usec_chn0), // output[19:0] reg
.done (local_got[0]) // output
);
timestamp_to_parallel timestamp_to_parallel1_i (
.clk (mclk), // input
.pre_stb (ts_snd_stb_chn1), // input
.tdata (ts_snd_data_chn1), // input[7:0]
.sec (ts_snd_sec_chn1), // output[31:0] reg
.usec (ts_snd_usec_chn1), // output[19:0] reg
.done (local_got[1]) // output
);
timestamp_to_parallel timestamp_to_parallel2_i (
.clk (mclk), // input
.pre_stb (ts_snd_stb), // input
.tdata (ts_snd_data), // input[7:0]
.sec (ts_snd_sec), // output[31:0] reg
.usec (ts_snd_usec), // output[19:0] reg
.done (local_got) // output
.pre_stb (ts_snd_stb_chn2), // input
.tdata (ts_snd_data_chn2), // input[7:0]
.sec (ts_snd_sec_chn2), // output[31:0] reg
.usec (ts_snd_usec_chn2), // output[19:0] reg
.done (local_got[2]) // output
);
timestamp_to_serial timestamp_to_serial_i (
timestamp_to_parallel timestamp_to_parallel3_i (
.clk (mclk), // input
.stb (ts_stb), // input
.sec (ts_rcv_sec), // input[31:0]
.usec (ts_rcv_usec), // input[19:0]
.tdata (ts_rcv_data) // output[7:0] reg
.pre_stb (ts_snd_stb_chn3), // input
.tdata (ts_snd_data_chn3), // input[7:0]
.sec (ts_snd_sec_chn3), // output[31:0] reg
.usec (ts_snd_usec_chn3), // output[19:0] reg
.done (local_got[3]) // output
);
timestamp_to_serial timestamp_to_serial0_i (
.clk (mclk), // input
.stb (ts_stb[0]), // input
.sec (ts_rcv_sec_chn0), // input[31:0]
.usec (ts_rcv_usec_chn0), // input[19:0]
.tdata (ts_rcv_data_chn0) // output[7:0] reg
);
assign ts_rcv_stb= ts_stb;
timestamp_to_serial timestamp_to_serial1_i (
.clk (mclk), // input
.stb (ts_stb[1]), // input
.sec (ts_rcv_sec_chn1), // input[31:0]
.usec (ts_rcv_usec_chn1), // input[19:0]
.tdata (ts_rcv_data_chn1) // output[7:0] reg
);
timestamp_to_serial timestamp_to_serial2_i (
.clk (mclk), // input
.stb (ts_stb[2]), // input