Commit 1b4f3f2c authored by Andrey Filippov's avatar Andrey Filippov

Working on HiSPi decoder

parent c7ad1d57
...@@ -760,12 +760,19 @@ ...@@ -760,12 +760,19 @@
parameter CLKFBOUT_MULT_AXIHP = 18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE parameter CLKFBOUT_MULT_AXIHP = 18, // Fvco=Fclkin*CLKFBOUT_MULT_F/DIVCLK_DIVIDE, Fout=Fvco/CLKOUT#_DIVIDE
parameter CLKOUT_DIV_AXIHP = 6, // To get 150MHz for the reference clock parameter CLKOUT_DIV_AXIHP = 6, // To get 150MHz for the reference clock
parameter BUF_CLK1X_AXIHP = "BUFG", // "BUFG", "BUFH", "BUFR", "NONE" parameter BUF_CLK1X_AXIHP = "BUFG", // "BUFG", "BUFH", "BUFR", "NONE"
`ifdef HISPI
parameter CLKIN_PERIOD_PCLK = 42, // 24MHz (actually needed is 24.4444
parameter DIVCLK_DIVIDE_PCLK = 1,
parameter CLKFBOUT_MULT_PCLK = 36, // 880 MHz
parameter CLKOUT_DIV_PCLK = 4, // 220 MHz
parameter CLKOUT_DIV_PCLK2X = 2, // 440 MHz
`else
parameter CLKIN_PERIOD_PCLK = 42, // 24MHz parameter CLKIN_PERIOD_PCLK = 42, // 24MHz
parameter DIVCLK_DIVIDE_PCLK = 1, parameter DIVCLK_DIVIDE_PCLK = 1,
parameter CLKFBOUT_MULT_PCLK = 40, // 960 MHz parameter CLKFBOUT_MULT_PCLK = 40, // 960 MHz
parameter CLKOUT_DIV_PCLK = 10, // 96MHz parameter CLKOUT_DIV_PCLK = 10, // 96MHz
parameter CLKOUT_DIV_PCLK2X = 5, // 192 MHz parameter CLKOUT_DIV_PCLK2X = 5, // 192 MHz
`endif
parameter PHASE_CLK2X_PCLK = 0.000, parameter PHASE_CLK2X_PCLK = 0.000,
parameter BUF_CLK1X_PCLK = "BUFG", parameter BUF_CLK1X_PCLK = "BUFG",
parameter BUF_CLK1X_PCLK2X = "BUFG", parameter BUF_CLK1X_PCLK2X = "BUFG",
......
...@@ -38,8 +38,8 @@ module pxd_single#( ...@@ -38,8 +38,8 @@ module pxd_single#(
output pxd_in, // data output (@posedge ipclk?) output pxd_in, // data output (@posedge ipclk?)
input ipclk, // restored clock from the sensor, phase-shifted input ipclk, // restored clock from the sensor, phase-shifted
input ipclk2x, // restored clock from the sensor, phase-shifted, twice frequency input ipclk2x, // restored clock from the sensor, phase-shifted, twice frequency
input mrst, // reset @ posxedge mclk input mrst, // reset @ posedge mclk
input irst, // reset @ posxedge iclk input irst, // reset @ posedge iclk
input mclk, // clock for setting delay values input mclk, // clock for setting delay values
input [7:0] dly_data, // delay value (3 LSB - fine delay) - @posedge mclk input [7:0] dly_data, // delay value (3 LSB - fine delay) - @posedge mclk
input set_idelay, // mclk synchronous load idelay value input set_idelay, // mclk synchronous load idelay value
......
/*******************************************************************************
* Module: sens_hispi12l4
* Date:2015-10-13
* Author: andrey
* Description: Decode HiSPi 4-lane, 12 bits Packetized-SP data from the sensor
*
* Copyright (c) 2015 Elphel, Inc .
* sens_hispi12l4.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_hispi12l4.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_hispi12l4#(
parameter IODELAY_GRP = "IODELAY_SENSOR",
parameter integer IDELAY_VALUE = 0,
parameter real REFCLK_FREQUENCY = 200.0,
parameter HIGH_PERFORMANCE_MODE = "FALSE",
parameter SENS_PHASE_WIDTH= 8, // number of bits for te phase counter (depends on divisors)
parameter SENS_PCLK_PERIOD = 3.000, // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
parameter SENS_BANDWIDTH = "OPTIMIZED", //"OPTIMIZED", "HIGH","LOW"
parameter CLKFBOUT_MULT_SENSOR = 4, // 220 MHz --> 880 MHz
parameter CLKFBOUT_PHASE_SENSOR = 0.000, // CLOCK FEEDBACK phase in degrees (3 significant digits, -360.000...+360.000)
parameter IPCLK_PHASE = 0.000,
parameter IPCLK2X_PHASE = 0.000,
parameter BUF_IPCLK = "BUFR",
parameter BUF_IPCLK2X = "BUFR",
parameter SENS_DIVCLK_DIVIDE = 1, // Integer 1..106. Divides all outputs with respect to CLKIN
parameter SENS_REF_JITTER1 = 0.010, // Expectet jitter on CLKIN1 (0.000..0.999)
parameter SENS_REF_JITTER2 = 0.010,
parameter SENS_SS_EN = "FALSE", // Enables Spread Spectrum mode
parameter SENS_SS_MODE = "CENTER_HIGH",//"CENTER_HIGH","CENTER_LOW","DOWN_HIGH","DOWN_LOW"
parameter SENS_SS_MOD_PERIOD = 10000, // integer 4000-40000 - SS modulation period in ns
parameter HISPI_NUMLANES = 4,
parameter HISPI_CAPACITANCE = "DONT_CARE",
parameter HISPI_DIFF_TERM = "TRUE",
parameter HISPI_DQS_BIAS = "TRUE",
parameter HISPI_IBUF_DELAY_VALUE = "0",
parameter HISPI_IBUF_LOW_PWR = "TRUE",
parameter HISPI_IFD_DELAY_VALUE = "AUTO",
parameter HISPI_IOSTANDARD = "DEFAULT"
)(
input pclk, // global clock input, pixel rate (220MHz for MT9F002)
input prst,
output irst,
input trigger_mode, // running in triggered mode (0 - free running mode)
input trig, // per-sensor trigger input
// I/O pads
input [HISPI_NUMLANES-1:0] sns_dp,
input [HISPI_NUMLANES-1:0] sns_dn,
input sns_clkp,
input sns_clkn,
// output
output reg [11:0] pxd_out,
output reg vact_out,
output hact_out,
// delay control inputs
input mclk,
input mrst,
input [HISPI_NUMLANES * 8-1:0] dly_data, // delay value (3 LSB - fine delay) - @posedge mclk
input [HISPI_NUMLANES-1:0] set_idelay, // mclk synchronous load idelay value
input ld_idelay, // mclk synchronous set idealy value
input set_clk_phase, // mclk synchronous set idealy value
input rst_mmcm,
// MMCP output status
output ps_rdy, // output
output [7:0] ps_out, // output[7:0] reg
output locked_pxd_mmcm,
output clkin_pxd_stopped_mmcm, // output
output clkfb_pxd_stopped_mmcm // output
);
wire ipclk; // re-generated half HiSPi clock (165 MHz)
wire ipclk2x;// re-generated HiSPi clock (330 MHz)
wire [HISPI_NUMLANES * 4-1:0] sns_d;
sens_hispi_clock #(
.SENS_PHASE_WIDTH (SENS_PHASE_WIDTH),
.SENS_PCLK_PERIOD (SENS_PCLK_PERIOD),
.SENS_BANDWIDTH (SENS_BANDWIDTH),
.CLKFBOUT_MULT_SENSOR (CLKFBOUT_MULT_SENSOR),
.CLKFBOUT_PHASE_SENSOR (CLKFBOUT_PHASE_SENSOR),
.IPCLK_PHASE (IPCLK_PHASE),
.IPCLK2X_PHASE (IPCLK2X_PHASE),
.BUF_IPCLK (BUF_IPCLK),
.BUF_IPCLK2X (BUF_IPCLK2X),
.SENS_DIVCLK_DIVIDE (SENS_DIVCLK_DIVIDE),
.SENS_REF_JITTER1 (SENS_REF_JITTER1),
.SENS_REF_JITTER2 (SENS_REF_JITTER2),
.SENS_SS_EN (SENS_SS_EN),
.SENS_SS_MODE (SENS_SS_MODE),
.SENS_SS_MOD_PERIOD (SENS_SS_MOD_PERIOD),
.HISPI_CAPACITANCE (HISPI_CAPACITANCE),
.HISPI_DIFF_TERM (HISPI_DIFF_TERM),
.HISPI_DQS_BIAS (HISPI_DQS_BIAS),
.HISPI_IBUF_DELAY_VALUE (HISPI_IBUF_DELAY_VALUE),
.HISPI_IBUF_LOW_PWR (HISPI_IBUF_LOW_PWR),
.HISPI_IFD_DELAY_VALUE (HISPI_IFD_DELAY_VALUE),
.HISPI_IOSTANDARD (HISPI_IOSTANDARD)
) sens_hispi_clock_i (
.mclk (mclk), // input
.mrst (mrst), // input
.phase (dly_data[7:0]), // input[7:0]
.set_phase (set_clk_phase), // input
.rst_mmcm (rst_mmcm), // input
.clp_p (sns_clkp), // input
.clk_n (sns_clkn), // input
.ipclk (ipclk), // output
.ipclk2x (ipclk2x), // output
.ps_rdy (ps_rdy), // output
.ps_out (ps_out), // output[7:0]
.locked_pxd_mmcm (locked_pxd_mmcm), // output
.clkin_pxd_stopped_mmcm (clkin_pxd_stopped_mmcm), // output
.clkfb_pxd_stopped_mmcm (clkfb_pxd_stopped_mmcm) // output
);
sens_hispi_din #(
.IODELAY_GRP (IODELAY_GRP),
.IDELAY_VALUE (IDELAY_VALUE),
.REFCLK_FREQUENCY (REFCLK_FREQUENCY),
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE),
.HISPI_NUMLANES (HISPI_NUMLANES),
.HISPI_CAPACITANCE (HISPI_CAPACITANCE),
.HISPI_DIFF_TERM (HISPI_DIFF_TERM),
.HISPI_DQS_BIAS (HISPI_DQS_BIAS),
.HISPI_IBUF_DELAY_VALUE (HISPI_IBUF_DELAY_VALUE),
.HISPI_IBUF_LOW_PWR (HISPI_IBUF_LOW_PWR),
.HISPI_IFD_DELAY_VALUE (HISPI_IFD_DELAY_VALUE),
.HISPI_IOSTANDARD (HISPI_IOSTANDARD)
) sens_hispi_din_i (
.mclk (mclk), // input
.mrst (mrst), // input
.dly_data (dly_data), // input[31:0]
.set_idelay (set_idelay), // input[3:0]
.ld_idelay (ld_idelay), // input
.ipclk (ipclk), // input
.ipclk2x (ipclk2x), // input
.irst (irst), // input
.din_p (sns_dp), // input[3:0]
.din_n (sns_dn), // input[3:0]
.dout (sns_d) // output[15:0]
);
endmodule
/*******************************************************************************
* Module: sens_hispi_clock
* Date:2015-10-13
* Author: andrey
* Description: Recover iclk/iclk2x from the HiSPi differntial clock
*
* Copyright (c) 2015 Elphel, Inc .
* sens_hispi_clock.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_hispi_clock.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_hispi_clock#(
parameter SENS_PHASE_WIDTH= 8, // number of bits for te phase counter (depends on divisors)
parameter SENS_PCLK_PERIOD = 3.000, // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
parameter SENS_BANDWIDTH = "OPTIMIZED", //"OPTIMIZED", "HIGH","LOW"
parameter CLKFBOUT_MULT_SENSOR = 4, // 220 MHz --> 880 MHz
parameter CLKFBOUT_PHASE_SENSOR = 0.000, // CLOCK FEEDBACK phase in degrees (3 significant digits, -360.000...+360.000)
parameter IPCLK_PHASE = 0.000,
parameter IPCLK2X_PHASE = 0.000,
parameter BUF_IPCLK = "BUFR",
parameter BUF_IPCLK2X = "BUFR",
parameter SENS_DIVCLK_DIVIDE = 1, // Integer 1..106. Divides all outputs with respect to CLKIN
parameter SENS_REF_JITTER1 = 0.010, // Expectet jitter on CLKIN1 (0.000..0.999)
parameter SENS_REF_JITTER2 = 0.010,
parameter SENS_SS_EN = "FALSE", // Enables Spread Spectrum mode
parameter SENS_SS_MODE = "CENTER_HIGH",//"CENTER_HIGH","CENTER_LOW","DOWN_HIGH","DOWN_LOW"
parameter SENS_SS_MOD_PERIOD = 10000, // integer 4000-40000 - SS modulation period in ns
parameter HISPI_CAPACITANCE = "DONT_CARE",
parameter HISPI_DIFF_TERM = "TRUE",
parameter HISPI_DQS_BIAS = "TRUE",
parameter HISPI_IBUF_DELAY_VALUE = "0",
parameter HISPI_IBUF_LOW_PWR = "TRUE",
parameter HISPI_IFD_DELAY_VALUE = "AUTO",
parameter HISPI_IOSTANDARD = "DEFAULT"
)(
input mclk,
input mrst,
input [7:0] phase,
input set_phase,
input rst_mmcm,
input clp_p,
input clk_n,
output ipclk, // 165 MHz
output ipclk2x, // 330 MHz
output ps_rdy, // output
output [7:0] ps_out, // output[7:0] reg
output locked_pxd_mmcm,
output clkin_pxd_stopped_mmcm, // output
output clkfb_pxd_stopped_mmcm // output
);
wire ipclk_pre;
wire ipclk2x_pre; // output
wire clk_fb;
wire prst = mrst;
wire clk_in;
ibufds_ibufgds #(
.CAPACITANCE (HISPI_CAPACITANCE),
.DIFF_TERM (HISPI_DIFF_TERM),
.DQS_BIAS (HISPI_DQS_BIAS),
.IBUF_DELAY_VALUE (HISPI_IBUF_DELAY_VALUE),
.IBUF_LOW_PWR (HISPI_IBUF_LOW_PWR),
.IFD_DELAY_VALUE (HISPI_IFD_DELAY_VALUE),
.IOSTANDARD (HISPI_IOSTANDARD)
) ibufds_ibufgds0_i (
.O (clk_in), // output
.I (clp_p), // input
.IB (clk_n) // input
);
// generate phase-shifterd pixel clock (and 2x version) from either the internal clock (that is output to the sensor) or from the clock
// received from the sensor (may need to reset MMCM after resetting sensor)
mmcm_phase_cntr #(
.PHASE_WIDTH (SENS_PHASE_WIDTH),
.CLKIN_PERIOD (SENS_PCLK_PERIOD),
.BANDWIDTH (SENS_BANDWIDTH),
.CLKFBOUT_MULT_F (CLKFBOUT_MULT_SENSOR), // 4
.DIVCLK_DIVIDE (SENS_DIVCLK_DIVIDE),
.CLKFBOUT_PHASE (CLKFBOUT_PHASE_SENSOR),
.CLKOUT0_PHASE (IPCLK_PHASE),
.CLKOUT1_PHASE (IPCLK2X_PHASE),
.CLKFBOUT_USE_FINE_PS("FALSE"),
.CLKOUT0_USE_FINE_PS ("TRUE"),
.CLKOUT1_USE_FINE_PS ("TRUE"),
.CLKOUT0_DIVIDE_F (CLKFBOUT_MULT_SENSOR), // 4 // 8.000),
.CLKOUT1_DIVIDE (CLKFBOUT_MULT_SENSOR / 2), //2 // 4),
.COMPENSATION ("ZHOLD"),
.REF_JITTER1 (SENS_REF_JITTER1),
.REF_JITTER2 (SENS_REF_JITTER2),
.SS_EN (SENS_SS_EN),
.SS_MODE (SENS_SS_MODE),
.SS_MOD_PERIOD (SENS_SS_MOD_PERIOD),
.STARTUP_WAIT ("FALSE")
) mmcm_phase_cntr_i (
.clkin1 (clk_in), // input
.clkin2 (1'b0), // input
.sel_clk2 (1'b0), // input
.clkfbin (clk_fb), // input
.rst (rst_mmcm), // input
.pwrdwn (1'b0), // input
.psclk (mclk), // input
.ps_we (set_phase), // input
.ps_din (phase), // input[7:0]
.ps_ready (ps_rdy), // output
.ps_dout (ps_out), // output[7:0] reg
.clkout0 (ipclk_pre), // output
.clkout1 (ipclk2x_pre), // output
.clkout2(), // output
.clkout3(), // output
.clkout4(), // output
.clkout5(), // output
.clkout6(), // output
.clkout0b(), // output
.clkout1b(), // output
.clkout2b(), // output
.clkout3b(), // output
.clkfbout (clk_fb), // output
.clkfboutb(), // output
.locked (locked_pxd_mmcm),
.clkin_stopped (clkin_pxd_stopped_mmcm), // output
.clkfb_stopped (clkfb_pxd_stopped_mmcm) // output
// output
);
generate
if (BUF_IPCLK == "BUFG") BUFG clk1x_i (.O(ipclk), .I(ipclk_pre));
else if (BUF_IPCLK == "BUFH") BUFH clk1x_i (.O(ipclk), .I(ipclk_pre));
else if (BUF_IPCLK == "BUFR") BUFR clk1x_i (.O(ipclk), .I(ipclk_pre), .CE(1'b1), .CLR(prst));
else if (BUF_IPCLK == "BUFMR") BUFMR clk1x_i (.O(ipclk), .I(ipclk_pre));
else if (BUF_IPCLK == "BUFIO") BUFIO clk1x_i (.O(ipclk), .I(ipclk_pre));
else assign ipclk = ipclk_pre;
endgenerate
generate
if (BUF_IPCLK2X == "BUFG") BUFG clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
else if (BUF_IPCLK2X == "BUFH") BUFH clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
else if (BUF_IPCLK2X == "BUFR") BUFR clk2x_i (.O(ipclk2x), .I(ipclk2x_pre), .CE(1'b1), .CLR(prst));
else if (BUF_IPCLK2X == "BUFMR") BUFMR clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
else if (BUF_IPCLK2X == "BUFIO") BUFIO clk2x_i (.O(ipclk2x), .I(ipclk2x_pre));
else assign ipclk2x = ipclk2x_pre;
endgenerate
endmodule
/*******************************************************************************
* Module: sens_hispi_din
* Date:2015-10-13
* Author: andrey
* Description: Input differential receivers for HiSPi lanes
*
* Copyright (c) 2015 Elphel, Inc .
* sens_hispi_din.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_hispi_din.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_hispi_din #(
parameter IODELAY_GRP = "IODELAY_SENSOR", // may need different for different channels?
parameter integer IDELAY_VALUE = 0,
parameter real REFCLK_FREQUENCY = 200.0,
parameter HIGH_PERFORMANCE_MODE = "FALSE",
parameter HISPI_NUMLANES = 4,
parameter HISPI_CAPACITANCE = "DONT_CARE",
parameter HISPI_DIFF_TERM = "TRUE",
parameter HISPI_DQS_BIAS = "TRUE",
parameter HISPI_IBUF_DELAY_VALUE = "0",
parameter HISPI_IBUF_LOW_PWR = "TRUE",
parameter HISPI_IFD_DELAY_VALUE = "AUTO",
parameter HISPI_IOSTANDARD = "DEFAULT"
)(
input mclk,
input mrst,
input [HISPI_NUMLANES * 8-1:0] dly_data, // delay value (3 LSB - fine delay) - @posedge mclk
input [HISPI_NUMLANES-1:0] set_idelay, // mclk synchronous load idelay value
input ld_idelay, // mclk synchronous set idealy value
input ipclk, // 165 MHz
input ipclk2x, // 330 MHz
input irst, // reset @posedge iclk
input [HISPI_NUMLANES-1:0] din_p,
input [HISPI_NUMLANES-1:0] din_n,
output [HISPI_NUMLANES * 4-1:0] dout
);
wire [HISPI_NUMLANES-1:0] din;
wire [HISPI_NUMLANES-1:0] din_dly;
generate
genvar i;
for (i=1; i < HISPI_NUMLANES; i=i+1) begin: din_block
ibufds_ibufgds #(
.CAPACITANCE (HISPI_CAPACITANCE),
.DIFF_TERM (HISPI_DIFF_TERM),
.DQS_BIAS (HISPI_DQS_BIAS),
.IBUF_DELAY_VALUE (HISPI_IBUF_DELAY_VALUE),
.IBUF_LOW_PWR (HISPI_IBUF_LOW_PWR),
.IFD_DELAY_VALUE (HISPI_IFD_DELAY_VALUE),
.IOSTANDARD (HISPI_IOSTANDARD)
) ibufds_ibufgds0_i (
.O (din[i]), // output
.I (din_p[i]), // input
.IB (din_n[i]) // input
);
idelay_nofine # (
.IODELAY_GRP (IODELAY_GRP),
.DELAY_VALUE (IDELAY_VALUE),
.REFCLK_FREQUENCY (REFCLK_FREQUENCY),
.HIGH_PERFORMANCE_MODE (HIGH_PERFORMANCE_MODE)
) pxd_dly_i(
.clk (mclk),
.rst (mrst),
.set (set_idelay[i]),
.ld (ld_idelay),
.delay (dly_data[3 + 8*i +: 5]),
.data_in (din[i]),
.data_out (din_dly[i])
);
iserdes_mem #(
.DYN_CLKDIV_INV_EN("FALSE")
) iserdes_pxd_i (
.iclk(ipclk2x), // source-synchronous clock
.oclk(ipclk2x), // system clock, phase should allow iclk-to-oclk jitter with setup/hold margin
.oclk_div(ipclk), // oclk divided by 2, front aligned
.inv_clk_div(1'b0), // invert oclk_div (this clock is shared between iserdes and oserdes. Works only in MEMORY_DDR3 mode?
.rst(irst), // reset
.d_direct(1'b0), // direct input from IOB, normally not used, controlled by IOBDELAY parameter (set to "NONE")
.ddly(din_dly[i]), // serial input from idelay
.dout(dout[4*i +:4]), // parallel data out
.comb_out() // output
);
end
endgenerate
endmodule
/*******************************************************************************
* Module: sens_hispi_lane
* Date:2015-10-13
* Author: andrey
* Description: Decode a single lane of the HiSPi data assuming packetized-SP protocol
*
* Copyright (c) 2015 Elphel, Inc .
* sens_hispi_lane.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_hispi_lane.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_hispi_lane#(
parameter HISPI_MSB_FIRST = 0
)(
input ipclk, // half HiSPi recovered clock (165 MHz for 660 bps of MT9F002)
input irst, // reset sync to ipclk
input [3:0] din, // @posedge ipclk, din[3] came first
output reg [3:0] dout, // data output, aligned (decide about bit order)
output reg dv, // data valid - continuous marks line
output reg embed, // valid @sol and up through all dv
output reg sof, // always before first sol - not instead of
output reg eof, // always after last eol (not instead of)
output reg sol, // start of line - 1 cycle before dv
output reg eol // end of line - last dv
);
localparam [3:0] SYNC_SOF = HISPI_MSB_FIRST ? 4'h3 : 4'hc;
localparam [3:0] SYNC_SOL = HISPI_MSB_FIRST ? 4'h1 : 4'h8;
localparam [3:0] SYNC_EOF = HISPI_MSB_FIRST ? 4'h7 : 4'he;
// localparam [3:0] SYNC_EOL = 6;
localparam [3:0] SYNC_EMBED = HISPI_MSB_FIRST ? 4'h1 : 4'h8; // other nibble (bit 4)
localparam SYNC_NIBBLE = HISPI_MSB_FIRST ? 2 : 0; // decode which nibble of the last sync word
reg [3:0] d_r; // rehistered input data
wire [2:0] num_trail_0_w; // number of trailing 0-s in the last nibble
wire [2:0] num_lead_0_w; // number of leading 0-s in the last nibble
wire [2:0] num_trail_1_w; // number of trailing 1-s in the last nibble
wire [2:0] num_lead_1_w; // number of leading 1-s in the last nibble
wire zero_after_ones_w;
reg [3:0] num_running_ones;
reg [4:0] num_running_zeros; // after sufficient ones
reg prev4ones; // previous data nibble was 4'hf
reg [1:0] num_first_zeros; // number of zeros in a first nibble after all ones
reg [1:0] shift_val; // barrel shifter select (0 is 4!)
wire got_sync_w = !num_running_zeros[3] && (&num_running_zeros_w[4:3]);
reg got_sync; // Got 24 zeros after >=16 1-s
reg [3:0] barrel;
reg [3:0] sync_decode; // 1-hot decoding of the last sync word
reg got_sof;
reg got_eof;
reg got_sol;
// reg got_eol;
reg got_embed;
reg pre_dv;
wire [3:0] dout_w;
wire [4:0] num_running_zeros_w = num_running_zeros + {1'b0, num_lead_0_w};
wire start_line = sync_decode[3] && (got_sol || got_sof);
wire start_line_d; // delayed just to turn on pre_dv;
assign num_trail_0_w = (|din) ? ((|din[2:0]) ? ((|din[1:0]) ? (din[0] ? 3'h0 : 3'h1) : 3'h2) : 3'h3) : 3'h4;
assign num_lead_0_w = (|din) ? ((|din[3:1]) ? ((|din[3:2]) ? (din[3] ? 3'h0 : 3'h1) : 3'h2) : 3'h3) : 3'h4;
assign num_trail_1_w = (&din) ? 3'h4 : ((&din[2:0]) ? 3'h3 : ((&din[1:0]) ? 3'h2 :((&din[0]) ? 3'h1 : 3'h0)));
assign num_lead_1_w = (&din) ? 3'h4 : ((&din[3:1]) ? 3'h3 : ((&din[3:2]) ? 3'h2 :((&din[3]) ? 3'h1 : 3'h0)));
assign zero_after_ones_w = !((din[0] && !din[1]) || (din[1] && !din[2]) || (din[2] && !din[3]) || (d_r[3] && !din[0]));
always @(posedge ipclk) begin
d_r <= din;
prev4ones <= num_trail_1_w[2];
if (prev4ones && !num_trail_1_w[2]) num_first_zeros <= num_trail_0_w[1:0]; // 4 will be 0
// first stage - get at least 12 consecutive 1-s, expecting many consecutive 0-s after, so any
// 1 after zero should restart counting.
if (irst) num_running_ones <= 0;
else if ((num_running_ones == 0) || !zero_after_ones_w) num_running_ones <= {1'b0,num_trail_1_w};
// keep number of running 1-s saturated to 12 (to prevent roll over). Temporary there could be 13..15
// When running 1-s turn to running zeros, the count will not reset and stay on through counting
// of 0-s (will only reset by 1 after 0)
else num_running_ones <= (&num_running_ones[3:2]) ? 4'hc :
(num_running_ones + {1'b0, num_lead_1_w});
// Now count consecutive 0-s after (>=12) 1-s. Not using zero_after_ones in the middle of the run - will
// rely on the number of running ones being reset in that case
// Saturate number with 24 (5'h18), but only first transition from <24 to >=24 is used for sync
// detection.
if (irst || !num_running_ones[3]) num_running_zeros <= 0;
else if (!num_running_ones[2]) num_running_zeros <= {2'b0,num_trail_0_w};
else num_running_zeros <= (&num_running_zeros[4:3])? 5'h18 : num_running_zeros_w;
if (irst) got_sync <= 0;
else got_sync <= got_sync_w;
// got_sync should also abort data run - delayed by 10 clocks
if (irst) shift_val <= 0;
else if (got_sync) shift_val <= num_first_zeros;
case (shift_val)
2'h0: barrel <= din;
2'h1: barrel <= {d_r[2:0], din[3]};
2'h2: barrel <= {d_r[1:0], din[3:2]};
2'h3: barrel <= {d_r[0], din[3:1]};
endcase
if (irst) sync_decode <= 0;
else if (got_sync) sync_decode <= 4'h1;
else sync_decode <= sync_decode << 1;
if (got_sync) got_sof <= 0;
else if (sync_decode[SYNC_NIBBLE] && (barrel == SYNC_SOF)) got_sof <= 1;
if (got_sync) got_eof <= 0;
else if (sync_decode[SYNC_NIBBLE] && (barrel == SYNC_EOF)) got_eof <= 1;
if (got_sync) got_sol <= 0;
else if (sync_decode[SYNC_NIBBLE] && (barrel == SYNC_SOL)) got_sol <= 1;
// if (got_sync) got_eol <= 0;
// else if (sync_decode[SYNC_NIBBLE] && (barrel == SYNC_EOL)) got_eol <= 1;
if (got_sync) got_embed <= 0;
else if (sync_decode[1] && (barrel == SYNC_EMBED)) got_embed <= 1;
if (irst) dout <= 0;
else dout <= dout_w;
if (irst || got_sync) pre_dv <= 0;
else if (start_line_d) pre_dv <= 1;
if (irst) dv <= 0;
else dv <= pre_dv;
if (irst) sol <= 0;
else sol <= start_line_d;
if (irst) eol <= 0;
else eol <= got_sync && pre_dv;
if (irst) sof <= 0;
else sof <= sync_decode[3] && got_sof;
if (irst) eof <= 0;
else eof <= sync_decode[3] && got_eof;
if (irst) embed <= 0;
else if (sync_decode[3]) embed <= got_embed && (got_sof || got_sol);
end
dly_16 #(
.WIDTH(4)
) dly_16_dout_i (
.clk (ipclk), // input
.rst (1'b0), // input
.dly (8), // input[3:0]
.din (HISPI_MSB_FIRST ? barrel :{barrel[0],barrel[1],barrel[2],barrel[3]}), // input[0:0]
.dout (dout_w) // output[0:0]
);
dly_16 #(
.WIDTH(1)
) dly_16_pre_start_line_i (
.clk (ipclk), // input
.rst (1'b0), // input
.dly (7), // input[3:0]
.din (start_line), // input[0:0]
.dout (start_line_d) // output[0:0]
);
endmodule
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/> . * along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/ *******************************************************************************/
`timescale 1ns/1ps `timescale 1ns/1ps
// TODO: get rid of pclk2x by doubling memories (making 1 write port and 2 read ones)
// How to erase?
// Alternative: copy/erase to a separate buffer in the beginning/end of a frame?
module sens_histogram #( module sens_histogram #(
parameter HISTOGRAM_RAM_MODE = "NOBUF", // valid: "NOBUF" (32-bits, no buffering), "BUF18", "BUF32" parameter HISTOGRAM_RAM_MODE = "NOBUF", // valid: "NOBUF" (32-bits, no buffering), "BUF18", "BUF32"
......
...@@ -214,7 +214,11 @@ module sensor_channel#( ...@@ -214,7 +214,11 @@ module sensor_channel#(
) ( ) (
// input rst, // input rst,
input pclk, // global clock input, pixel rate (96MHz for MT9P006) input pclk, // global clock input, pixel rate (96MHz for MT9P006)
// TODO: get rid of pclk2x in histograms by doubling memories (making 1 write port and 2 read ones)
// How to erase?
// Alternative: copy/erase to a separate buffer in the beginning/end of a frame?
input pclk2x, // global clock input, double pixel rate (192MHz for MT9P006) input pclk2x, // global clock input, double pixel rate (192MHz for MT9P006)
input mrst, // @posedge mclk, sync reset input mrst, // @posedge mclk, sync reset
input prst, // @posedge pclk, sync reset input prst, // @posedge pclk, sync reset
......
...@@ -300,7 +300,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb ...@@ -300,7 +300,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb
assign PX1_MCLK_PRE = sns1_dp[6]; // from FPGA to sensor assign PX1_MCLK_PRE = sns1_dp[6]; // from FPGA to sensor
assign PX1_MRST = sns1_dp[7]; // from FPGA to sensor assign PX1_MRST = sns1_dp[7]; // from FPGA to sensor
assign PX1_ARST = sns1_dn[7]; // same as GP[3] assign PX1_ARST = sns1_dn[7]; // same as GP[3]
assign PX1_ARO = sns1_dn[6]; // same as GP[2] assign PX1_ARO = sns1_dn[5]; // same as GP[2]
assign sns2_dp[3:0] = PX2_LANE_P; assign sns2_dp[3:0] = PX2_LANE_P;
assign sns2_dn[3:0] = PX2_LANE_N; assign sns2_dn[3:0] = PX2_LANE_N;
...@@ -313,7 +313,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb ...@@ -313,7 +313,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb
assign PX2_MCLK_PRE = sns2_dp[6]; // from FPGA to sensor assign PX2_MCLK_PRE = sns2_dp[6]; // from FPGA to sensor
assign PX2_MRST = sns2_dp[7]; // from FPGA to sensor assign PX2_MRST = sns2_dp[7]; // from FPGA to sensor
assign PX2_ARST = sns2_dn[7]; // same as GP[3] assign PX2_ARST = sns2_dn[7]; // same as GP[3]
assign PX2_ARO = sns2_dn[6]; // same as GP[2] assign PX2_ARO = sns2_dn[5]; // same as GP[2]
assign sns3_dp[3:0] = PX3_LANE_P; assign sns3_dp[3:0] = PX3_LANE_P;
assign sns3_dn[3:0] = PX3_LANE_N; assign sns3_dn[3:0] = PX3_LANE_N;
...@@ -326,7 +326,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb ...@@ -326,7 +326,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb
assign PX3_MCLK_PRE = sns3_dp[6]; // from FPGA to sensor assign PX3_MCLK_PRE = sns3_dp[6]; // from FPGA to sensor
assign PX3_MRST = sns3_dp[7]; // from FPGA to sensor assign PX3_MRST = sns3_dp[7]; // from FPGA to sensor
assign PX3_ARST = sns3_dn[7]; // same as GP[3] assign PX3_ARST = sns3_dn[7]; // same as GP[3]
assign PX3_ARO = sns3_dn[6]; // same as GP[2] assign PX3_ARO = sns3_dn[5]; // same as GP[2]
assign sns4_dp[3:0] = PX4_LANE_P; assign sns4_dp[3:0] = PX4_LANE_P;
assign sns4_dn[3:0] = PX4_LANE_N; assign sns4_dn[3:0] = PX4_LANE_N;
...@@ -339,7 +339,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb ...@@ -339,7 +339,7 @@ parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - emb
assign PX4_MCLK_PRE = sns4_dp[6]; // from FPGA to sensor assign PX4_MCLK_PRE = sns4_dp[6]; // from FPGA to sensor
assign PX4_MRST = sns4_dp[7]; // from FPGA to sensor assign PX4_MRST = sns4_dp[7]; // from FPGA to sensor
assign PX4_ARST = sns4_dn[7]; // same as GP[3] assign PX4_ARST = sns4_dn[7]; // same as GP[3]
assign PX4_ARO = sns4_dn[6]; // same as GP[2] assign PX4_ARO = sns4_dn[5]; // same as GP[2]
`else `else
//connect parallel12 sensor to sensor port 1 //connect parallel12 sensor to sensor port 1
assign sns1_dp[6:1] = {PX1_D[10], PX1_D[8], PX1_D[6], PX1_D[4], PX1_D[2], PX1_HACT}; assign sns1_dp[6:1] = {PX1_D[10], PX1_D[8], PX1_D[6], PX1_D[4], PX1_D[2], PX1_HACT};
......
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