Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
x393
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
x393
Commits
eb7ba9a4
Commit
eb7ba9a4
authored
Apr 10, 2019
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New modules for LWIR sensor
parent
cc525170
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
892 additions
and
0 deletions
+892
-0
sens_lepton3.v
sensor/sens_lepton3.v
+448
-0
vospi_packet_80.v
sensor/vospi_packet_80.v
+150
-0
vospi_segment_61.v
sensor/vospi_segment_61.v
+294
-0
No files found.
sensor/sens_lepton3.v
0 → 100644
View file @
eb7ba9a4
/*!
* <b>Module:</b>sens_lepton3
* @file sens_lepton3.v
* @date 2015-05-10
* @author Andrey Filippov
*
* @brief Sensor interface with 12-bit for parallel bus
*
* @copyright Copyright (c) 2015 Elphel, Inc.
*
* <b>License:</b>
*
* sens_lepton3.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_lepton3.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*/
`timescale
1
ns
/
1
ps
`include
"system_defines.vh"
// just for debugging histograms
module
sens_lepton3
#(
parameter
SENSIO_ADDR
=
'h330
,
parameter
SENSIO_ADDR_MASK
=
'h7f8
,
parameter
SENSIO_CTRL
=
'h0
,
parameter
SENSIO_STATUS
=
'h1
,
parameter
SENSIO_JTAG
=
'h2
,
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
=
'h21
,
parameter
SENS_JTAG_PGMEN
=
8
,
parameter
SENS_JTAG_PROG
=
6
,
parameter
SENS_JTAG_TCK
=
4
,
parameter
SENS_JTAG_TMS
=
2
,
parameter
SENS_JTAG_TDI
=
0
,
parameter
SENS_CTRL_MRST
=
0
,
// 1: 0
parameter
SENS_CTRL_ARST
=
2
,
// 3: 2
parameter
SENS_CTRL_ARO
=
4
,
// 5: 4
parameter
SENS_CTRL_RST_MMCM
=
6
,
// 7: 6
parameter
SENS_CTRL_EXT_CLK
=
8
,
// 9: 8
parameter
SENS_CTRL_LD_DLY
=
10
,
// 10
parameter
SENS_CTRL_QUADRANTS
=
12
,
// 17:12, enable - 20
parameter
SENS_CTRL_QUADRANTS_WIDTH
=
7
,
// 6,
parameter
SENS_CTRL_ODD
=
6
,
//
parameter
SENS_CTRL_QUADRANTS_EN
=
20
,
// 18:12, enable - 20 (1 bits reserved)
parameter
LINE_WIDTH_BITS
=
16
,
parameter
IODELAY_GRP
=
"IODELAY_SENSOR"
,
// may need different for different channels?
parameter
integer
IDELAY_VALUE
=
0
,
parameter
integer
PXD_DRIVE
=
12
,
parameter
PXD_IBUF_LOW_PWR
=
"TRUE"
,
parameter
PXD_IOSTANDARD
=
"DEFAULT"
,
parameter
PXD_SLEW
=
"SLOW"
,
parameter
real
SENS_REFCLK_FREQUENCY
=
300.0
,
parameter
SENS_HIGH_PERFORMANCE_MODE
=
"FALSE"
,
parameter
SENS_PHASE_WIDTH
=
8
,
// number of bits for te phase counter (depends on divisors)
// parameter SENS_PCLK_PERIOD = 10.000, // input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
parameter
SENS_BANDWIDTH
=
"OPTIMIZED"
,
//"OPTIMIZED", "HIGH","LOW"
parameter
CLKIN_PERIOD_SENSOR
=
10.000
,
// input period in ns, 0..100.000 - MANDATORY, resolution down to 1 ps
parameter
CLKFBOUT_MULT_SENSOR
=
8
,
// 100 MHz --> 800 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
,
// Expected 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
STATUS_ALIVE_WIDTH
=
4
)(
// programming interface
input
mrst
,
// @posedge mclk, sync reset
input
mclk
,
// global clock, half DDR3 clock, synchronizes all I/O through the command port
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
output
[
7
:
0
]
status_ad
,
// status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
output
status_rq
,
// input request to send status downstream
input
status_start
,
// Acknowledge of the first status packet byte (address)
input
prst
,
output
prsts
,
// @pclk - includes sensor reset and sensor PLL reset
input
pclk
,
// global clock input, SPI rate (10-20 MHz) - defines internal pixel rate
input
sns_mclk
,
// 25Mz for the sensor
// sensor pads excluding i2c
inout
spi_miso
,
// input
inout
spi_mosi
,
// not used
output
spi_cs
,
// output, externally connected to inout port
output
spi_clk
,
// output, externally connected to inout port
inout
[
3
:
0
]
gpio
,
// only [3] may be used as input from sensor
output
lwir_mclk
,
// output, externally connected to inout port
output
lwir_mrst
,
// output, externally connected to inout port
output
lwir_pwdn
,
// output, externally connected to inout port
inout
mipi_dp
,
// input diff, not implemented in lepton3 sensor
inout
mipi_dn
,
// input diff, not implemented in lepton3 sensor
inout
mipi_clkp
,
// input diff, not implemented in lepton3 sensor
inout
mipi_clkn
,
// input diff, not implemented in lepton3 sensor
inout
senspgm
,
// SENSPGM I/O pin
inout
sns_ctl
,
// npot used at all
// output
output
[
15
:
0
]
pxd
,
// @pclk
output
hact
,
// @pclktwice per actual line
output
sof
,
// @pclk
output
eof
// @pclk
)
;
wire
fake_out
;
wire
fake_in
;
wire
[
25
:
0
]
status
;
// added byte-wide xfpgatdo
wire
cmd_we
;
wire
[
2
:
0
]
cmd_a
;
wire
[
31
:
0
]
cmd_data
;
reg
[
31
:
0
]
data_r
;
wire
spi_clk_en_mclk
;
wire
sns_mclk_en_mclk
;
reg
[
1
:
0
]
spi_clk_en_pclk
;
reg
[
1
:
0
]
sns_mclk_en_lwir_mclk
;
wire
spi_miso_int
;
wire
spi_cs_int
;
wire
spi_mosi_int
;
wire
[
3
:
0
]
gpio_in
;
// only [3] may be used
wire
[
3
:
0
]
gpio_out
;
// none currently used
wire
[
3
:
0
]
gpio_en
=
0
;
// none currently used
wire
lwir_mrst_int
;
wire
lwir_pwdn_int
;
wire
senspgm_int
;
wire
sns_ctl_int
;
// not implemented in the sesnor, put dummy input buffer5s
wire
mipi_dp_int
;
wire
mipi_dn_int
;
wire
mipi_clkp_int
;
wire
mipi_clkn_int
;
// temporary?
assign
fake_in
=
senspgm_int
^
sns_ctl_int
^
mipi_dp_int
^
mipi_dn_int
^
mipi_clkp_int
^
mipi_clkn_int
;
// assign fake_out = data_r[31];
assign
status
[
25
]
=
fake_in
;
// bit assignment will change
assign
spi_clk_en_mclk
=
data_r
[
2
]
;
assign
sns_mclk_en_mclk
=
data_r
[
3
]
;
always
@
(
posedge
mclk
)
begin
if
(
mrst
)
data_r
<=
0
;
else
if
(
cmd_we
)
data_r
<=
cmd_data
;
end
always
@
(
posedge
pclk
)
begin
spi_clk_en_pclk
[
1
:
0
]
<=
{
spi_clk_en_pclk
[
0
]
,
spi_clk_en_mclk
};
end
always
@
(
posedge
sns_mclk
)
begin
sns_mclk_en_lwir_mclk
[
1
:
0
]
<=
{
sns_mclk_en_lwir_mclk
[
0
]
,
sns_mclk_en_mclk
};
end
// implement I/O ports, including fake ones, to be able to assign them I/O pads
// generate clocka to sesnor output, controlled by control word bits
// SPI clock (10..20MHz)
oddr_ss
#(
// spi_clk
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
,
.
DDR_CLK_EDGE
(
"OPPOSITE_EDGE"
)
,
.
INIT
(
1'b0
)
,
.
SRTYPE
(
"SYNC"
)
)
spi_clk_i
(
.
clk
(
pclk
)
,
// input
.
ce
(
spi_clk_en_pclk
[
1
])
,
// input
.
rst
(
prst
)
,
// input
.
set
(
1'b0
)
,
// input
.
din
(
2'b01
)
,
// input[1:0]
.
tin
(
1'b0
)
,
// input
.
dq
(
spi_clk
)
// output
)
;
// sensor master clock (25MHz)
oddr_ss
#(
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
,
.
DDR_CLK_EDGE
(
"OPPOSITE_EDGE"
)
,
.
INIT
(
1'b0
)
,
.
SRTYPE
(
"SYNC"
)
)
lwir_mclk_i
(
.
clk
(
sns_mclk
)
,
// input
.
ce
(
sns_mclk_en_lwir_mclk
[
1
])
,
// input
.
rst
(
prst
)
,
// input
.
set
(
1'b0
)
,
// input
.
din
(
2'b01
)
,
// input[1:0]
.
tin
(
1'b0
)
,
// input
.
dq
(
lwir_mclk
)
// output
)
;
iobuf
#(
// spi_miso
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
spi_miso_i
(
.
O
(
spi_miso_int
)
,
// output
.
IO
(
spi_miso
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
iobuf
#(
// spi_mosi, not implemented in the sensor
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
spi_mosi_i
(
.
O
()
,
// output - currently not used
.
IO
(
spi_mosi
)
,
// inout I/O pad
.
I
(
spi_mosi_int
)
,
// input
.
T
(
!
fake_out
)
// input - always off
)
;
iobuf
#(
// spi_cs
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
spi_cs_i
(
.
O
()
,
// output - currently not used
.
IO
(
spi_cs
)
,
// inout I/O pad
.
I
(
spi_cs_int
)
,
// input
.
T
(
1'b0
)
// input - always on
)
;
generate
// gpio[3:0]
genvar
i
;
for
(
i
=
0
;
i
<
4
;
i
=
i
+
1
)
begin
:
gpio_block
iobuf
#(
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
gpio_i
(
.
O
(
gpio_in
[
i
])
,
// output - currently not used
.
IO
(
gpio
[
i
])
,
// inout I/O pad
.
I
(
gpio_out
[
i
])
,
// input
.
T
(
!
gpio_en
[
i
])
// input - always on
)
;
end
endgenerate
iobuf
#(
// lwir_mrst
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
lwir_mrst_i
(
.
O
()
,
// output - currently not used
.
IO
(
lwir_mrst
)
,
// inout I/O pad
.
I
(
lwir_mrst_int
)
,
// input
.
T
(
1'b0
)
// input - always on
)
;
iobuf
#(
// lwir_pwdn
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
lwir_pwdn_i
(
.
O
()
,
// output - currently not used
.
IO
(
lwir_pwdn
)
,
// inout I/O pad
.
I
(
lwir_pwdn_int
)
,
// input
.
T
(
1'b0
)
// input - always on
)
;
// MIPI - anyway it is not implemented, IOSTANDARD not known, put just single-ended input buffers
iobuf
#(
// mipi_dp
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
mipi_dp_i
(
.
O
(
mipi_dp_int
)
,
// output - currently not used
.
IO
(
mipi_dp
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
iobuf
#(
// mipi_dn
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
mipi_dn_i
(
.
O
(
mipi_dn_int
)
,
// output - currently not used
.
IO
(
mipi_dn
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
iobuf
#(
// mipi_clkp
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
mipi_clkp_i
(
.
O
(
mipi_clkp_int
)
,
// output - currently not used
.
IO
(
mipi_clkp
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
iobuf
#(
// mipi_clkn
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
mipi_clkn_i
(
.
O
(
mipi_clkn_int
)
,
// output - currently not used
.
IO
(
mipi_clkn
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
iobuf
#(
// senspgm
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
senspgm_i
(
.
O
(
senspgm_int
)
,
// output (detection of the SFE
.
IO
(
senspgm
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
iobuf
#(
// sns_ctl
.
DRIVE
(
PXD_DRIVE
)
,
.
IBUF_LOW_PWR
(
PXD_IBUF_LOW_PWR
)
,
.
IOSTANDARD
(
PXD_IOSTANDARD
)
,
.
SLEW
(
PXD_SLEW
)
)
sns_ctl_i
(
.
O
(
sns_ctl_int
)
,
// output - currently not used
.
IO
(
sns_ctl
)
,
// inout I/O pad
.
I
(
1'b0
)
,
// input
.
T
(
1'b1
)
// input - always off
)
;
cmd_deser
#(
.
ADDR
(
SENSIO_ADDR
)
,
.
ADDR_MASK
(
SENSIO_ADDR_MASK
)
,
.
NUM_CYCLES
(
6
)
,
.
ADDR_WIDTH
(
3
)
,
.
DATA_WIDTH
(
32
)
)
cmd_deser_sens_io_i
(
.
rst
(
1'b0
)
,
// rst), // input
.
clk
(
mclk
)
,
// input
.
srst
(
mrst
)
,
// 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
)
;
status_generate
#(
.
STATUS_REG_ADDR
(
SENSIO_STATUS_REG
)
,
.
PAYLOAD_BITS
(
26
)
// STATUS_PAYLOAD_BITS)
)
status_generate_sens_io_i
(
.
rst
(
1'b0
)
,
// rst), // input
.
clk
(
mclk
)
,
// input
.
srst
(
mrst
)
,
// input
.
we
(
set_status_r
)
,
// input
.
wd
(
data_r
[
7
:
0
])
,
// input[7:0]
.
status
(
{
status
}
)
,
// input[25:0]
.
ad
(
status_ad
)
,
// output[7:0]
.
rq
(
status_rq
)
,
// output
.
start
(
status_start
)
// input
)
;
// for debug/test alive
pulse_cross_clock
pulse_cross_clock_vact_a_mclk_i
(
.
rst
(
irst
)
,
// input
.
src_clk
(
ipclk
)
,
// input
.
dst_clk
(
mclk
)
,
// input
.
in_pulse
(
vact_out_pre
&&
!
vact_r
)
,
// input
.
out_pulse
(
vact_a_mclk
)
,
// output
.
busy
()
// output
)
;
pulse_cross_clock
pulse_cross_clock_hact_ext_a_mclk_i
(
.
rst
(
irst
)
,
// input
.
src_clk
(
ipclk
)
,
// input
.
dst_clk
(
mclk
)
,
// input
.
in_pulse
(
hact_ext
&&
!
hact_ext_r
)
,
// input
.
out_pulse
(
hact_ext_a_mclk
)
,
// output
.
busy
()
// output
)
;
pulse_cross_clock
pulse_cross_clock_hact_a_mclk_i
(
.
rst
(
irst
)
,
// input
.
src_clk
(
ipclk
)
,
// input
.
dst_clk
(
mclk
)
,
// input
.
in_pulse
(
hact_r
&&
!
hact_r2
)
,
// input
.
out_pulse
(
hact_a_mclk
)
,
// output
.
busy
()
// output
)
;
endmodule
sensor/vospi_packet_80.v
0 → 100644
View file @
eb7ba9a4
/*!
* <b>Module:</b> vospi_packet_80
* @file vospi_packet_80.v
* @date 2019-04-08
* @author Andrey Filippov
*
* @brief VoSPI receive 160 byte packets
*
* @copyright Copyright (c) 2019 Elphel, Inc.
*
* <b>License </b>
*
* vospi_packet_80.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.
*
* vospi_packet_80.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*/
`timescale
1
ns
/
1
ps
module
vospi_packet_80
#(
parameter
VOSPI_PACKET_WORDS
=
80
,
parameter
VOSPI_NO_INVALID
=
1
// do not output invalid packets data
)(
input
rst
,
input
clk
,
input
start
,
// @posedge clk
output
spi_clken
,
// enable clock on spi_clk
output
spi_cs
,
// active low
input
miso
,
// input from the sensor
output
[
15
:
0
]
dout
,
// 16-bit data received,valid at dv and 15 cycles after
output
dv
,
// data valid strobe
output
packet_done
,
// packet received,
output
packet_busy
,
// packet busy (same as spi_clken, !spi_cs)
output
crc_err
,
// crc error, valid with packet_done
output
[
15
:
0
]
id
,
// packet ID (0x*f** - invlaid, if packet index = 20, 4 MSb - segment (- 0 invalid)
output
packet_invalid
,
// set early, valid with packet done
output
reg
id_stb
// id, packet invalid are set
)
;
reg
[
6
:
0
]
wcntr
;
reg
[
3
:
0
]
bcntr
;
wire
pre_lsb_w
;
reg
lsb_r
;
// reading last bit from miso
reg
copy_word
;
// copy 16-bit word from the SR (next after lsb_r);
reg
[
15
:
0
]
d_r
;
reg
[
1
:
0
]
cs_r
;
wire
pre_last_w
;
reg
[
2
:
0
]
packet_end
;
reg
set_id_r
;
reg
set_crc_r
;
reg
set_d_r
;
reg
den_r
;
reg
[
15
:
0
]
d_sr
;
reg
[
1
:
0
]
start_r
;
reg
dv_r
;
reg
[
15
:
0
]
crc_r
;
// required crc
wire
[
15
:
0
]
crc_w
;
// current crc
reg
[
15
:
0
]
id_r
;
wire
[
15
:
0
]
dmask
;
reg
packet_invalid_r
;
assign
packet_busy
=
cs_r
[
0
]
;
// clk_en_r;
assign
spi_clken
=
cs_r
[
0
]
;
// clk_en_r;
assign
spi_cs
=
~
cs_r
[
0
]
;
assign
pre_lsb_w
=
bcntr
==
4'he
;
assign
pre_last_w
=
pre_lsb_w
&&
(
wcntr
==
(
VOSPI_PACKET_WORDS
+
1
))
;
assign
packet_done
=
packet_end
[
2
]
;
assign
id
=
id_r
;
assign
dmask
=
den_r
?
16'hffff
:
(
wcntr
[
0
]
?
16'h0
:
16'h0fff
)
;
assign
crc_err
=
packet_end
[
2
]
&&
(
crc_r
!=
crc_w
)
;
assign
dv
=
dv_r
;
assign
dout
=
d_r
;
assign
packet_invalid
=
packet_invalid_r
;
always
@
(
posedge
clk
)
begin
if
(
rst
||
packet_end
[
0
])
cs_r
[
0
]
<=
0
;
else
if
(
start
)
cs_r
[
1
]
<=
1
;
cs_r
[
1
]
<=
cs_r
[
0
]
;
if
(
rst
||
!
cs_r
[
0
]
||
packet_end
[
0
])
bcntr
<=
0
;
else
bcntr
<=
bcntr
+
1
;
if
(
rst
||
!
cs_r
[
0
]
||
packet_end
[
0
])
lsb_r
<=
0
;
else
lsb_r
<=
pre_lsb_w
;
copy_word
<=
!
rst
&&
lsb_r
;
if
(
rst
||
!
cs_r
[
0
]
||
packet_end
[
0
])
wcntr
<=
0
;
else
if
(
lsb_r
)
wcntr
<=
wcntr
+
1
;
if
(
rst
||
!
cs_r
[
0
]
)
packet_end
<=
0
;
else
packet_end
<=
{
packet_end
[
1
:
0
]
,
pre_last_w
};
if
(
rst
)
start_r
<=
0
;
else
start_r
<=
{
start_r
[
0
]
,
start
};
set_id_r
<=
!
rst
&&
(
wcntr
==
0
)
&&
lsb_r
;
set_crc_r
<=
!
rst
&&
(
wcntr
==
1
)
&&
lsb_r
;
set_d_r
<=
!
rst
&&
den_r
&&
lsb_r
;
if
(
rst
||
!
cs_r
[
1
])
den_r
<=
0
;
else
if
(
set_crc_r
)
den_r
<=
1
;
if
(
cs_r
[
0
])
d_sr
<=
{
miso
,
d_sr
[
15
:
1
]
};
if
(
set_id_r
)
id_r
<=
d_sr
;
if
(
set_crc_r
)
crc_r
<=
d_sr
;
if
(
set_d_r
)
d_r
<=
d_sr
;
dv_r
<=
set_d_r
&&
!
(
packet_invalid_r
&&
VOSPI_NO_INVALID
)
;
if
(
rst
||
start
)
packet_invalid_r
<=
0
;
else
if
(
set_id_r
)
packet_invalid_r
<=
(
d_sr
[
11
:
8
]
==
4'hf
)
;
id_stb
<=
set_id_r
;
end
crc16_x16x12x5x0
crc16_x16x12x5x0_i
(
.
clk
(
clk
)
,
// input
.
srst
(
!
cs_r
[
1
])
,
// input
.
en
(
copy_word
)
,
// input
.
din
(
d_sr
&
dmask
)
,
// input[15:0]
.
dout
(
crc_w
)
// output[15:0]
)
;
endmodule
sensor/vospi_segment_61.v
0 → 100644
View file @
eb7ba9a4
/*!
* <b>Module:</b> vospi_segment_61
* @file vospi_segment_61.v
* @date 2019-04-08
* @author eyesis
*
* @brief Read one 61-packet segment from the sensor
*
* @copyright Copyright (c) 2019 Elphel, Inc.
*
* <b>License </b>
*
* vospi_segment_61.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.
*
* vospi_segment_61.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/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*/
`timescale
1
ns
/
1
ps
module
vospi_segment_61
#(
parameter
VOSPI_PACKET_WORDS
=
80
,
parameter
VOSPI_PACKETS_PER_LINE
=
2
,
parameter
VOSPI_SEGMENT_FIRST
=
1
,
parameter
VOSPI_SEGMENT_LAST
=
4
,
parameter
VOSPI_PACKET_FIRST
=
0
,
parameter
VOSPI_PACKET_LAST
=
60
,
parameter
VOSPI_PACKET_TTT
=
20
,
// line number where segment number is provided
parameter
VOSPI_SOF_TO_HACT
=
2
,
// clock cycles from SOF to HACT
parameter
VOSPI_HACT_TO_HACT_EOF
=
2
// minimal clock cycles from HACT to HACT or to EOF
// parameter VOSPI_HACT_TO_EOF = 2 // clock cycles from HACT to EOF
)(
input
rst
,
input
clk
,
input
start
,
// start reading segment
input
[
3
:
0
]
exp_segment
,
// expected segment (1,2,3,4)
input
segm0_ok
,
// OK to read segment 0 instead of the current ( exp_segment still has to be 1..4)
input
out_en
,
// enable frame output generation (will finish current frame if disabled, single-pulse
// runs a single frame
// SPI signals
output
spi_clken
,
// enable clock on spi_clk
output
spi_cs
,
// active low
input
miso
,
// input from the sensor
output
[
15
:
0
]
dout
,
// 16-bit data received
output
hact
,
// data valid
output
sof
,
// start of frame
output
eof
,
// end of frame
output
crc_err
,
// crc error happened for any packet (valid at eos)
output
[
3
:
0
]
id
// segment number (valid at eos)
)
;
localparam
VOSPI_PACKETS_FRAME
=
(
VOSPI_SEGMENT_LAST
-
VOSPI_SEGMENT_FIRST
+
1
)
*
(
VOSPI_PACKET_LAST
-
VOSPI_PACKET_FIRST
+
1
)
;
localparam
VOSPI_LINE_WIDTH
=
VOSPI_PACKET_WORDS
*
VOSPI_PACKETS_PER_LINE
;
// save fifo write pointer, write packet full index (in the frame)
// read and buffer first 20 valid packets, then (in packet 20) verify that the segment is correct.
// if correct - generate sof if appropriate/eof), proceed with hact, readout data
// if incorrect - restore write pointer and write packet index, read rest of the segment without writing to the buffer
// reg first_segment_in; // processing first segment in a frame
reg
last_segment_in
;
// processing last segment in a frame
reg
[
10
:
0
]
segment_start_waddr
;
// write address for the beginning of the current packet
reg
[
10
:
0
]
waddr
;
// current frite address
reg
[
7
:
0
]
segment_start_packet
;
// full packet number in a fragment for the start of the segment
reg
[
7
:
0
]
full_packet
;
// current full packet number in a fragment
reg
[
7
:
0
]
full_packet_verified
;
// next packet verified (will not be discarded later)
reg
full_packet_frame
;
// lsb of the input frame // not needed?
reg
discard_set
;
// start discard_segment
wire
segment_good_w
;
// recognized expected segment, OK to read FIFO
reg
segment_good
;
// recognized expected segment, OK to read FIFO
reg
discard_segment
;
// read and discard the rest of the current segment
reg
running_good
;
// passed packet 20
wire
packet_done
;
// read full packet
wire
packet_busy
;
// receiving SPI packet (same as spi_clken, !spi_cs)
wire
packet_dv
;
// read full packet
wire
[
15
:
0
]
packet_dout
;
// read full packet
wire
[
15
:
0
]
packet_id
;
wire
id_stb
;
wire
is_first_segment_w
;
wire
is_last_segment_w
;
reg
start_d
;
wire
segment_stb
;
reg
crc_err_r
;
wire
packet_crc_err
;
reg
packet_start
;
wire
we
;
// write data to buffer
wire
segment_done
;
reg
segment_busy
;
reg
segment_running
;
// may be discarded
reg
[
3
:
0
]
segment_id_r
;
wire
frame_in_done
;
// reg packet_running; // may be discarded
assign
is_first_segment_w
=
(
exp_segment
==
VOSPI_SEGMENT_FIRST
)
;
assign
is_last_segment_w
=
(
exp_segment
==
VOSPI_SEGMENT_LAST
)
;
assign
segment_good_w
=
(
packet_id
[
15
:
12
]
==
exp_segment
)
||
((
packet_id
[
15
:
12
]
==
0
)
&&
segm0_ok
)
;
assign
segment_stb
=
id_stb
&&
(
packet_id
[
11
:
0
]
==
VOSPI_PACKET_TTT
)
;
assign
we
=
segment_running
&&
!
discard_segment
&&
packet_dv
;
assign
crc_err
=
crc_err_r
;
assign
segment_done
=
segment_running
&&
packet_done
&&
(
packet_id
[
11
:
0
]
==
VOSPI_PACKET_LAST
)
;
assign
id
=
segment_id_r
;
assign
frame_in_done
=
segment_done
&&
last_segment_in
;
// To Buffer
always
@
(
posedge
clk
)
begin
// if (rst) first_segment_in <= 0;
// else if (start) first_segment_in <= is_first_segment_w;
if
(
rst
)
last_segment_in
<=
0
;
else
if
(
start
)
last_segment_in
<=
is_last_segment_w
;
start_d
<=
start
;
discard_set
<=
segment_running
&&
!
discard_segment
&&
segment_stb
&&
!
segment_good_w
;
segment_good
<=
segment_running
&&
!
discard_segment
&&
segment_stb
&&
segment_good_w
;
if
(
segment_running
&&
!
discard_segment
&&
segment_stb
)
segment_id_r
<=
packet_id
[
15
:
12
]
;
if
(
start
)
discard_segment
<=
0
;
else
if
(
discard_set
)
discard_segment
<=
1
;
if
(
start
)
running_good
<=
0
;
else
if
(
segment_good
)
running_good
<=
1
;
if
(
start_d
||
running_good
)
full_packet_verified
<=
full_packet
;
if
(
start_d
)
segment_start_packet
<=
full_packet
;
if
(
start_d
)
segment_start_waddr
<=
waddr
;
if
(
rst
||
(
start
&&
is_first_segment_w
))
full_packet
<=
0
;
else
if
(
discard_set
)
full_packet
<=
segment_start_packet
;
else
if
(
!
discard_segment
&&
packet_done
)
full_packet
<=
full_packet
+
1
;
if
(
rst
||
start
)
crc_err_r
<=
0
;
else
if
(
packet_done
&&
packet_crc_err
)
crc_err_r
<=
0
;
if
(
rst
)
segment_busy
<=
0
;
else
if
(
start
)
segment_busy
<=
1'b1
;
else
if
(
segment_done
)
segment_busy
<=
1'b0
;
if
(
!
segment_busy
||
start
)
segment_running
<=
0
;
else
if
(
id_stb
&&
(
packet_id
[
11
:
0
]
==
VOSPI_PACKET_FIRST
))
segment_running
<=
1
;
packet_start
<=
!
rst
&&
!
packet_busy
&&
segment_busy
;
if
(
rst
)
waddr
<=
0
;
else
if
(
discard_set
)
waddr
<=
segment_start_waddr
;
else
if
(
we
)
waddr
<=
waddr
+
1
;
if
(
rst
)
full_packet_frame
<=
0
;
// not needed?
else
if
(
frame_in_done
)
full_packet_frame
<=~
full_packet_frame
;
end
// From buffer, generating frame
reg
out_request
;
reg
out_frame
;
wire
sof_w
;
reg
sof_r
;
wire
eof_w
;
reg
[
2
:
0
]
eof_r
;
wire
start_out_frame_w
;
reg
[
7
:
0
]
full_packet_out
;
// current full packet number in a fragment
wire
[
8
:
0
]
packets_avail
;
// line_avail; //
reg
out_pending
;
// frame read from the sensor, but not yet output
// reg packet_out_done;
wire
frame_out_done_w
;
// last packet data was sent out
wire
frame_dav
;
wire
hact_start_w
;
// (hact will start next cycle
wire
hact_end_w
;
reg
[
7
:
0
]
duration_cntr
;
reg
[
2
:
0
]
hact_r
;
reg
pend_eof_r
;
reg
[
10
:
0
]
raddr
;
assign
start_out_frame_w
=
segment_good
&&
is_first_segment_w
&&
out_request
;
assign
packets_avail
=
{
1'b0
,
full_packet_verified
}
-
{
1'b0
,
full_packet_out
}
-
VOSPI_PACKETS_PER_LINE
;
// assign frame_out_done_w = packet_out_done && (full_packet_out == (VOSPI_PACKETS_FRAME - 1));
assign
frame_out_done_w
=
hact_end_w
&&
(
full_packet_out
==
(
VOSPI_PACKETS_FRAME
-
1
))
;
assign
frame_dav
=
!
packets_avail
[
8
]
||
out_pending
;
assign
hact_start_w
=
out_frame
&&
(
duration_cntr
==
0
)
&&
!
hact_r
[
0
]
&&
frame_dav
;
assign
hact_end_w
=
(
duration_cntr
==
0
)
&&
hact_r
[
0
]
;
assign
eof_w
=
out_frame
&&
(
duration_cntr
==
0
)
&&
pend_eof_r
;
assign
sof_w
=
rst
&&
start_out_frame_w
;
assign
hact
=
hact_r
[
2
]
;
assign
eof
=
eof_r
[
2
]
;
assign
sof
=
sof_r
;
always
@
(
posedge
clk
)
begin
if
(
rst
)
hact_r
<=
0
;
else
hact_r
<=
{
hact_r
[
1
:
0
]
,
hact_start_w
|
(
hact_r
[
0
]
&
~
hact_end_w
)
};
if
(
rst
||
start_out_frame_w
)
full_packet_out
<=
0
;
else
if
(
hact_end_w
)
full_packet_out
<=
full_packet_out
+
VOSPI_PACKETS_PER_LINE
;
if
(
rst
)
out_request
<=
0
;
else
if
(
out_en
)
out_request
<=
1
;
else
if
(
sof_r
)
out_request
<=
0
;
if
(
rst
)
out_frame
<=
0
;
else
if
(
start_out_frame_w
)
out_frame
<=
1
;
else
if
(
eof_r
[
0
])
out_frame
<=
0
;
sof_r
<=
sof_w
;
eof_r
<=
{
eof_r
[
1
:
0
]
,
eof_w
};
if
(
rst
)
out_pending
<=
0
;
// not needed?
else
if
(
frame_in_done
)
out_pending
<=
1
;
else
if
(
frame_out_done_w
)
out_pending
<=
0
;
if
(
rst
)
pend_eof_r
<=
0
;
// not needed?
else
if
(
frame_out_done_w
)
pend_eof_r
<=
1
;
else
if
(
eof_r
[
0
])
pend_eof_r
<=
0
;
if
(
rst
)
duration_cntr
<=
0
;
else
if
(
start_out_frame_w
)
duration_cntr
<=
VOSPI_SOF_TO_HACT
;
else
if
(
hact_start_w
)
duration_cntr
<=
VOSPI_LINE_WIDTH
-
1
;
else
if
(
hact_end_w
)
duration_cntr
<=
VOSPI_HACT_TO_HACT_EOF
;
else
if
(
|
duration_cntr
)
duration_cntr
<=
duration_cntr
-
1
;
if
(
sof_w
)
raddr
<=
segment_start_waddr
;
else
if
(
hact_r
[
0
])
raddr
<=
raddr
+
1
;
end
vospi_packet_80
#(
.
VOSPI_PACKET_WORDS
(
80
)
,
.
VOSPI_NO_INVALID
(
1
)
)
vospi_packet_80_i
(
.
rst
(
rst
)
,
// input
.
clk
(
clk
)
,
// input
.
start
(
packet_start
)
,
// input
.
spi_clken
(
spi_clken
)
,
// output
.
spi_cs
(
spi_cs
)
,
// output
.
miso
(
miso
)
,
// input
.
dout
(
packet_dout
)
,
// output[15:0]
.
dv
(
packet_dv
)
,
// output
.
packet_done
(
packet_done
)
,
// output
.
packet_busy
(
packet_busy
)
,
// output
.
crc_err
(
packet_crc_err
)
,
// output
.
id
(
packet_id
)
,
// output[15:0]
.
packet_invalid
()
,
// output - not used, processed internally, no dv generated
.
id_stb
(
id_stb
)
// output reg
)
;
ram_var_w_var_r
#(
.
COMMENT
(
"vospi_segment"
)
,
.
REGISTERS
(
1
)
,
.
LOG2WIDTH_WR
(
4
)
,
.
LOG2WIDTH_RD
(
4
)
)
buf_i
(
.
rclk
(
clk
)
,
// input
.
raddr
(
raddr
)
,
// input[11:0]
.
ren
(
hact_r
[
0
])
,
// input
.
regen
(
hact_r
[
1
])
,
// input
.
data_out
(
dout
)
,
// output[7:0]
.
wclk
(
clk
)
,
// input
.
waddr
(
waddr
)
,
// input[11:0]
.
we
(
we
)
,
// input
.
web
(
8'hff
)
,
// input[7:0]
.
data_in
(
packet_dout
)
// input[7:0]
)
;
endmodule
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment