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
2a260f5a
Commit
2a260f5a
authored
Oct 07, 2015
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
continue on sensor i2c
parent
730d8ca4
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
307 additions
and
41 deletions
+307
-41
sensor_i2c_prot.v
sensor/sensor_i2c_prot.v
+181
-41
sensor_i2c_scl_sda.v
sensor/sensor_i2c_scl_sda.v
+126
-0
No files found.
sensor/sensor_i2c_prot.v
View file @
2a260f5a
...
...
@@ -21,65 +21,205 @@
`timescale
1
ns
/
1
ps
module
sensor_i2c_prot
(
input
mrst
,
// @ posedge mclk
input
mclk
,
// global clock
input
i2c_rst
,
input
i2c_start
,
input
[
7
:
0
]
i2c_dly
,
// bit duration-1 (>=2?), 1 unit - 4 mclk periods
input
mrst
,
// @ posedge mclk
input
mclk
,
// global clock
input
i2c_rst
,
input
i2c_start
,
input
[
7
:
0
]
i2c_dly
,
// bit duration-1 (>=2?), 1 unit - 4 mclk periods
// setup LUT to translate address page into SA, actual address MSB and number of bytes to write (second word bypasses translation)
input
tand
,
// table address/not data
input
[
19
:
0
]
td
,
// table address/data in
input
twe
,
// table write enable
output
reg
sda
,
output
reg
sda_en
,
output
reg
scl
,
output
i2c_run
,
output
[
1
:
0
]
seq_mem_ra
,
// number of byte to read from the sequencer memory
output
[
1
:
0
]
seq_mem_re
,
// [0] - re, [1] - regen to teh sequencer memory
input
[
7
:
0
]
seq_rd
,
// data from the sequencer memory
output
[
7
:
0
]
rdata
,
output
rvalid
input
tand
,
// table address/not data
input
[
19
:
0
]
td
,
// table address/data in
input
twe
,
// table write enable
input
sda_in
,
// data from sda pad
output
reg
sda
,
output
reg
sda_en
,
output
reg
scl
,
output
i2c_run
,
output
reg
[
1
:
0
]
seq_mem_ra
,
// number of byte to read from the sequencer memory
output
[
1
:
0
]
seq_mem_re
,
// [0] - re, [1] - regen to teh sequencer memory
input
[
7
:
0
]
seq_rd
,
// data from the sequencer memory
output
[
7
:
0
]
rdata
,
output
rvalid
)
;
reg
[
7
:
0
]
twa
;
wire
[
31
:
0
]
tdout
;
wire
[
7
:
0
]
reg_ah
=
tdout
[
7
:
0
]
;
// MSB of the register address (instead of the byte 2)
wire
[
6
:
0
]
slave_a
=
tdout
[
14
:
8
]
;
// 7-bit slave address (lsb == 1), used instead of the byte 3
wire
[
3
:
0
]
num_bytes_send
=
tdout
[
19
:
16
]
;
// number of bytes to send (if more than 4 will skip stop and continue with next data
reg
[
7
:
0
]
reg_ah
;
// MSB of the register address (instead of the byte 2)
reg
[
7
:
0
]
slave_a_rah
;
// 8-bit slave address , used instead of the byte 3, later replaced with reg_ah
reg
[
3
:
0
]
num_bytes_send
;
// number of bytes to send (if more than 4 will skip stop and continue with next data
reg
[
3
:
0
]
bytes_left_send
;
// Number of bytes left in register write sequence (not counting sa?)
reg
run_reg_wr
;
// run register write
reg
run_extra_wr
;
// continue register write (if more than sa + 4bytes)
reg
run_reg_rd
;
reg
[
6
:
0
]
run_reg_wr
;
// run register write [6] - start, [5] - send sa, [4] - send high byte (from table),..[0] - send stop
reg
[
4
:
0
]
run_extra_wr
;
// continue register write (if more than sa + 4bytes) [4] - byte 3, .. [1]- byte0, [0] - stop
reg
run_extra_wr_d
;
// any of run_extra_wr bits, delayed by 1
reg
[
7
:
0
]
run_reg_rd
;
// [7] - start, [6] SA (byte 3), [5] (optional) - RA_msb, [4] - RA_lsb, [3] - restart, [2] - SA, [1] - read bytes, [0] - stop
reg
i2c_done
;
wire
i2c_next_byte
;
reg
[
2
:
0
]
mem_re
;
reg
[
2
:
0
]
table_re
;
reg
mem_valid
;
reg
[
3
:
0
]
table_re
;
reg
read_mem_msb
;
wire
decode_reg_rd
=
&
seq_rd
[
7
:
4
]
;
wire
start_wr_seq_w
=
!
run_extra_wr_d
&&
!
decode_reg_rd
&&
read_mem_msb
;
wire
decode_reg_rd
=
&
seq_rd
[
7
:
5
]
;
wire
start_wr_seq
=
!
run_extra_wr
&&
!
decode_reg_rd
&&
read_mem_msb
;
reg
read_mem_msb
;
wire
snd_start_w
=
run_reg_wr
[
6
]
||
1'b0
;
// add start & restart of read
wire
snd_stop_w
=
run_reg_wr
[
0
]
||
1'b0
;
// add stop of read
wire
snd9_w
=
(
|
run_reg_wr
[
5
:
1
])
||
1'b0
;
// add for read and extra write;
reg
snd_start
;
reg
snd_stop
;
reg
snd9
;
// the following signals are mutually exclusive, can be encoded to 2 bits. Invaluid during next_cmd_d
reg
send_seq_data
;
// including first SA for read
reg
send_rd_sa
;
// from the table
reg
send_sa_rah
;
// send slave address/ high address from the table
reg
send_rd
;
// send 1fe/1ff to read data
reg
[
6
:
0
]
rd_sa
;
// 7-bit slave address for reading
wire
[
1
:
0
]
sel_sr_in
=
{
// select source for the shift register
send_sa_rah
|
send_rd
,
send_rd_sa
|
send_rd
};
reg
[
8
:
0
]
sr_in
;
// input data for the shift register
wire
i2c_rdy
;
reg
next_cmd
;
// i2c command (start/stop/data) accepted, proceed to the next stage
reg
next_cmd_d
;
// next cycle after next_cmd (first at new state)
wire
pre_next_cmd
=
(
snd_start
||
snd_stop
||
snd9
)
&&
i2c_rdy
;
reg
next_byte_wr
;
reg
read_address_bytes
;
// 0 - single-byte register adderss, 1 - two-byte register address
reg
[
2
:
0
]
read_data_bytes
;
// 1..8 bytes to read from teh i2c slave (0 is 8!)
reg
[
1
:
0
]
initial_address
;
// initial data byte to read: usually 3 but for extra write may be different
wire
[
3
:
0
]
initial_address_w
=
bytes_left_send
-
1
;
// if bytes left to send == 0 - will be 3
wire
unused
;
// unused ackn signal
assign
seq_mem_re
=
mem_re
[
1
:
0
]
;
always
@
(
posedge
mclk
)
begin
read_mem_msb
<=
mem_re
[
1
]
&&
(
seq_mem_ra
==
3
)
;
// reading sequencer data MSB
mem_re
<=
{
mem_re
[
1
:
0
]
,
i2c_start
|
i2c_next_byte
};
table_re
<=
{
table_re
[
1
:
0
]
,
start_wr_seq
};
run_extra_wr_d
<=
|
run_extra_wr
;
read_mem_msb
<=
mem_re
[
1
]
&&
(
seq_mem_ra
==
3
)
;
// reading sequencer data MSB - change to other one-hot?
table_re
<=
{
table_re
[
2
:
0
]
,
start_wr_seq_w
};
if
(
table_re
[
2
])
begin
reg_ah
<=
tdout
[
7
:
0
]
;
// MSB of the register address (instead of the byte 2)
num_bytes_send
<=
tdout
[
19
:
16
]
;
// number of bytes to send (if more than 4 will skip stop and continue with next data
end
if
(
table_re
[
2
])
slave_a_rah
<=
{
tdout
[
14
:
8
]
,
1'b0
};
else
if
(
next_cmd
&&
run_reg_wr
[
6
])
slave_a_rah
<=
reg_ah
;
// will copy even if not used
next_cmd
<=
pre_next_cmd
;
next_cmd_d
<=
next_cmd
;
if
(
mrst
||
i2c_rst
)
run_extra_wr
<=
0
;
else
if
(
i2c_start
&&
(
bytes_left_send
!=
0
))
run_extra_wr
<=
1
;
else
if
(
i2c_done
)
run_extra_wr
<=
0
;
next_byte_wr
<=
snd9
&&
i2c_rdy
;
// same time as next_cmd
if
(
mrst
||
i2c_rst
)
run_reg_wr
<=
0
;
else
if
(
start_wr_seq
)
run_reg_wr
<=
1
;
else
if
(
i2c_done
)
run_reg_wr
<=
0
;
snd_start
<=
snd_start_w
;
// add & i2c_ready? Not really needed as any i2c stage will be busy for long enough
snd_stop
<=
snd_stop_w
;
snd9
<=
snd9_w
;
if
(
mrst
||
i2c_rst
)
bytes_left_send
<=
0
;
else
if
(
start_wr_seq_w
)
bytes_left_send
<=
num_bytes_send
;
else
if
(
next_byte_wr
)
bytes_left_send
<=
bytes_left_send
-
1
;
// calculate stages for each type of commands
// start and write sa and some bytes, stop if number of bytes <= 4 at teh end
if
(
mrst
||
i2c_rst
)
run_reg_wr
<=
0
;
else
if
(
start_wr_seq_w
)
run_reg_wr
<=
7'h40
;
else
if
(
next_cmd
)
run_reg_wr
<=
{
1'b0
,
// first "start"
run_reg_wr
[
6
]
,
// slave_addr - always after start
run_reg_wr
[
5
]
&
(
|
num_bytes_send
[
3
:
2
])
,
// MSB (from the table)
run_reg_wr
[
4
]
|
(
run_reg_wr
[
5
]
&
(
num_bytes_send
==
4'h3
))
,
// byte 2 (from input)
run_reg_wr
[
3
]
|
(
run_reg_wr
[
5
]
&
(
num_bytes_send
==
4'h2
))
,
// byte 1 (from input)
run_reg_wr
[
2
]
|
(
run_reg_wr
[
5
]
&
(
num_bytes_send
==
4'h1
))
,
// byte 0 (from input)
run_reg_wr
[
1
]
&
(
bytes_left_send
==
4'h1
)
};
// send just bytes (up to 4), stop if nothing left
if
(
mrst
||
i2c_rst
)
run_extra_wr
<=
0
;
else
if
(
i2c_start
&&
(
bytes_left_send
!=
0
))
run_extra_wr
<=
{
|
bytes_left_send
[
3
:
2
]
,
// >= 4 bytes left
(
bytes_left_send
==
3
)
,
// exactly 3 bytes left
(
bytes_left_send
==
2
)
,
// exactly 2 bytes left
(
bytes_left_send
==
1
)
,
// exactly 1 bytes left (zero should never be left)
1'b0
};
else
if
(
next_cmd
)
run_extra_wr
<=
{
1'b0
,
run_extra_wr
[
4
]
,
run_extra_wr
[
3
]
,
run_extra_wr
[
2
]
,
run_extra_wr
[
1
]
&
(
bytes_left_send
==
4'h1
)
};
// reg [ 7:0] run_reg_rd; // [7] - start, [6] SA (byte 3), [5] (optional) - RA_msb, [4] - RA_lsb, [3] - restart, [2] - SA, [1] - read bytes, [0] - stop
if
(
mrst
||
i2c_rst
)
run_reg_rd
<=
0
;
else
if
(
!
run_extra_wr
&&
decode_reg_rd
&&
read_mem_msb
)
run_reg_rd
<=
1
;
else
if
(
i2c_done
)
run_reg_rd
<=
0
;
if
(
!
run_extra_wr
&&
decode_reg_rd
&&
read_mem_msb
)
read_address_bytes
<=
seq_rd
[
3
]
;
if
(
!
run_extra_wr
&&
decode_reg_rd
&&
read_mem_msb
)
read_data_bytes
<=
seq_rd
[
2
:
0
]
;
else
if
(
run_reg_rd
[
1
]
&&
next_cmd
)
read_data_bytes
<=
read_data_bytes
-
1
;
// read i2c data
if
(
mrst
||
i2c_rst
)
run_reg_rd
<=
0
;
else
if
(
!
run_extra_wr_d
&&
decode_reg_rd
&&
read_mem_msb
)
run_reg_rd
<=
8'h80
;
else
if
(
next_cmd
)
run_reg_rd
<=
{
1'b0
,
// first "start"
run_reg_rd
[
7
]
,
// slave_addr - always after start (bit0 = 0)
run_reg_rd
[
6
]
&
read_address_bytes
,
// optional MSB of the register address
run_reg_rd
[
5
]
|
(
run_reg_rd
[
6
]
&
~
read_address_bytes
)
,
// LSB of the register address
run_reg_rd
[
4
]
,
// restart
run_reg_rd
[
3
]
,
// send slave address with 1 in bit[0]
run_reg_rd
[
2
]
|
(
run_reg_rd
[
1
]
&
(
read_data_bytes
!=
3'h1
))
,
// repeat reading bytes
run_reg_rd
[
1
]
&
(
read_data_bytes
==
3'h1
)
};
// read sequencer memory byte (for the current word)
mem_re
<=
{
mem_re
[
1
:
0
]
,
i2c_start
|
next_cmd_d
&
(
(
|
run_reg_wr
[
3
:
1
])
|
(
|
run_extra_wr
[
4
:
1
])
|
(
|
run_reg_rd
[
6
:
4
]))
};
initial_address
<=
initial_address_w
[
1
:
0
]
;
// if bytes left to send is 0 mod 4 - will be 3 (read MSB)
seq_mem_ra
<=
i2c_start
?
initial_address
:
{
// run_extra_wr[4] is not needed - it will be read by i2c_start
run_reg_wr
[
3
]
|
run_extra_wr
[
3
]
|
run_reg_rd
[
6
]
,
run_reg_wr
[
2
]
|
run_extra_wr
[
2
]
|
run_reg_rd
[
5
]
};
if
(
mrst
||
i2c_rst
||
i2c_start
||
next_cmd
)
mem_valid
<=
0
;
else
if
(
mem_re
[
2
])
mem_valid
<=
1
;
// calculate snd9 and delay it if waiting for memory using mem_valid, set din[8:0]
if
(
run_reg_rd
[
6
]
&&
mem_re
[
2
])
rd_sa
<=
seq_rd
[
7
:
1
]
;
// store sa to use with read
send_seq_data
<=
!
next_cmd
&&
mem_valid
&&
((
|
run_reg_wr
[
3
:
1
])
||
(
|
run_extra_wr
[
4
:
1
])
||
(
|
run_reg_rd
[
6
:
4
]))
;
send_rd_sa
<=
!
next_cmd
&&
run_reg_rd
[
2
]
;
send_sa_rah
<=
!
next_cmd
&&
(
|
run_reg_wr
[
6
:
5
])
;
send_rd
<=
!
next_cmd
&&
run_reg_rd
[
1
]
;
if
(
mrst
||
i2c_rst
)
snd9
<=
0
;
else
snd9
<=
snd9
?
(
!
i2c_rdy
)
:
((
send_seq_data
||
send_rd_sa
||
send_sa_rah
||
send_rd
)
&&
!
next_cmd
)
;
case
(
sel_sr_in
)
2'h0
:
sr_in
<=
{
seq_rd
,
1'b1
};
2'h1
:
sr_in
<=
{
rd_sa
,
2'b11
};
2'h2
:
sr_in
<=
{
slave_a_rah
,
1'b1
};
2'h3
:
sr_in
<=
{
8'hff
,
(
read_data_bytes
==
3'h1
)
};
endcase
// table_re[2] - valid table data (slave_a, reg_ah, reg_ah
end
sensor_i2c_scl_sda
sensor_i2c_scl_sda_i
(
.
mrst
(
mrst
)
,
// input
.
mclk
(
mclk
)
,
// input
.
i2c_rst
(
i2c_rst
)
,
// input
.
i2c_dly
(
i2c_dly
)
,
// input[7:0]
.
snd_start
(
snd_start
)
,
// input
.
snd_stop
(
snd_stop
)
,
// input
.
snd9
(
snd9
)
,
// input
.
din
(
sr_in
)
,
// input[8:0]
.
dout
(
{
rdata
,
unused
}
)
,
// output[8:0]
.
dout_stb
(
rvalid
)
,
// output reg
.
scl
()
,
// output reg
.
sda_in
(
sda_in
)
,
// input
.
sda
()
,
// output reg
.
ready
(
i2c_rdy
)
,
// output register
.
bus_busy
()
,
// output reg
.
is_open
()
// output
)
;
// table write
...
...
sensor/sensor_i2c_scl_sda.v
0 → 100644
View file @
2a260f5a
/*******************************************************************************
* Module: sensor_i2c_scl_sda
* Date:2015-10-06
* Author: andrey
* Description: Generation of i2c signals
*
* Copyright (c) 2015 Elphel, Inc .
* sensor_i2c_scl_sda.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.
*
* sensor_i2c_scl_sda.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
1
ns
/
1
ps
module
sensor_i2c_scl_sda
(
input
mrst
,
// @ posedge mclk
input
mclk
,
// global clock
input
i2c_rst
,
input
[
7
:
0
]
i2c_dly
,
// bit duration-1 (>=2?), 1 unit - 4 mclk periods
input
snd_start
,
input
snd_stop
,
input
snd9
,
input
[
8
:
0
]
din
,
output
[
8
:
0
]
dout
,
//
output
reg
dout_stb
,
// dout contains valid data
output
reg
scl
,
// i2c SCL signal
input
sda_in
,
// i2c SDA signal form I/O pad
output
reg
sda
,
// i2c SDA signal
output
ready
,
// ready to accept commands
output
reg
bus_busy
,
// i2c bus busy (1 cycle behind !ready)
output
is_open
// i2c channel is open (started, no stop yet)
)
;
wire
rst
=
mrst
||
i2c_rst
;
reg
is_open_r
;
reg
[
8
:
0
]
sr
;
reg
[
7
:
0
]
dly_cntr
;
reg
busy_r
;
wire
snd_start_w
=
snd_start
&&
!
busy_r
;
wire
snd_stop_w
=
snd_stop
&&
!
busy_r
;
wire
snd9_w
=
snd9
&&
!
busy_r
;
wire
start_w
=
(
snd_start
||
snd_stop
||
snd9_w
)
&&
!
busy_r
;
reg
pre_dly_over
;
reg
dly_over
;
reg
[
3
:
0
]
seq_start_restart
;
reg
[
2
:
0
]
seq_stop
;
reg
[
3
:
0
]
seq_bit
;
reg
[
3
:
0
]
bits_left
;
reg
done_r
;
reg
sda_r
;
reg
first_cyc
;
// first clock cycle for the delay interval - update SCL/SDA outputs
assign
ready
=
!
busy_r
;
assign
is_open
=
is_open_r
;
assign
dout
=
sr
;
always
@
(
posedge
mclk
)
begin
if
(
rst
)
seq_start_restart
<=
0
;
else
if
(
snd_start_w
)
seq_start_restart
<=
is_open_r
?
4'h8
:
4'h4
;
else
if
(
dly_over
)
seq_start_restart
<=
{
1'b0
,
seq_start_restart
[
3
:
1
]
};
if
(
rst
)
seq_stop
<=
0
;
else
if
(
snd_stop_w
)
seq_stop
<=
3'h4
;
else
if
(
dly_over
)
seq_stop
<=
{
1'b0
,
seq_stop
[
2
:
1
]
};
if
(
rst
)
seq_bit
<=
0
;
else
if
(
snd_start_w
||
(
seq_bit
[
0
]
&&
(
bits_left
!=
0
)))
seq_bit
<=
4'h8
;
else
if
(
dly_over
)
seq_bit
<=
{
1'b0
,
seq_bit
[
3
:
1
]
};
if
(
rst
)
bits_left
<=
0
;
else
if
(
snd9_w
)
bits_left
<=
4'h8
;
else
if
(
dly_over
&&
seq_bit
[
0
])
bits_left
<=
bits_left
-
1
;
if
(
rst
)
busy_r
<=
0
;
else
if
(
start_w
)
busy_r
<=
1
;
else
if
(
done_r
)
busy_r
<=
0
;
pre_dly_over
<=
(
dly_cntr
==
2
)
;
dly_over
<=
pre_dly_over
;
if
(
rst
)
done_r
<=
0
;
else
done_r
<=
pre_dly_over
&&
(
bits_left
==
0
)
&&
(
seq_start_restart
[
3
:
1
]
==
0
)
&&
(
seq_stop
[
2
:
1
]
==
0
)
&&
(
bits_left
[
3
:
1
]
==
0
)
;
if
(
!
busy_r
||
dly_over
)
dly_cntr
<=
i2c_dly
;
else
dly_cntr
<=
dly_cntr
-
1
;
if
(
dly_over
&&
seq_bit
[
1
])
sda_r
<=
sda_in
;
// just before the end of SCL pulse - delay it by a few clocks to match external latencies?
if
(
snd_start_w
)
sr
<=
din
;
else
if
(
dly_over
&&
seq_bit
[
0
])
sr
<=
{
sr
[
7
:
0
]
,
sda_r
};
dout_stb
<=
dly_over
&&
seq_bit
[
0
]
&&
(
bits_left
==
0
)
;
if
(
rst
)
is_open_r
<=
0
;
else
if
(
dly_over
&&
seq_start_restart
[
0
])
is_open_r
<=
1
;
else
if
(
dly_over
&&
seq_stop
[
0
])
is_open_r
<=
0
;
first_cyc
<=
start_w
||
dly_over
;
if
(
rst
)
scl
<=
1
;
else
if
(
first_cyc
)
scl
<=
!
busy_r
||
seq_start_restart
[
2
]
||
seq_start_restart
[
1
]
||
seq_stop
[
1
]
||
seq_stop
[
0
]
||
seq_bit
[
2
]
||
seq_bit
[
1
]
;
if
(
rst
)
sda
<=
1
;
else
if
(
first_cyc
)
sda
<=
!
busy_r
||
seq_start_restart
[
3
]
||
seq_start_restart
[
2
]
||
seq_stop
[
0
]
||
(
sr
[
8
]
&&
(
|
seq_bit
))
;
bus_busy
<=
busy_r
;
end
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