|
找到一个I2C Slave的代码,可惜Verlog看不懂,发上来给大家参考
# z8 H4 P$ o- {: M* R. ?) K6 | K' T, f, @
///////////////////////////////////////////////////////////////////////////////5 W+ o* `$ _1 i* c
//
7 |$ W+ O6 I }2 n( e// Alacron Inc. - Confidential: All Rights Reserved l/ C9 D! M& n/ H5 L5 M
// Copyright (C) 2003+ N& @3 i3 [5 f7 b6 p* P. ?1 |
//7 c2 j, X" J! s7 h* p N6 ]
// Title : I2C Slave Control Logic
! s7 l' M/ \. v$ b// File : I2CSLAVE.v! Z4 J& d' F( o q- ^# H% q, }+ X
// Author : Gabor Szakacs% L& a! H: c; P2 t5 E
// Created : 25-May-2004 - Adapted from I2CSLAVE.abl
% G& E9 k0 F- h1 V3 B; t7 [' W3 _//9 F, D& Q# o, T# ~1 b) Z" w
//$ O9 f8 F' a% j, H4 K0 m
///////////////////////////////////////////////////////////////////////////////
: o9 k1 t5 H) K1 u- }3 j- L- p//, B" x3 S9 ~5 l( w" a* W
// Description :
2 J" k! V8 Q! l// This code implements an I2C slave-only controller.
1 o6 T9 x' a* E// Access to internal registers uses the sub-address
- t" y5 e% z. m// protocol like a serial EEPROM. No registers are/ L7 E+ G: l! ?8 c) \
// implemented in this module, however the module
" r; `# i3 c* ?) U// provides a simple bus interface to external registers.* g9 ~2 u! G% V5 T. @
// GLS - 12/13/00! A, r# N# V1 {
// I2C inputs are oversampled by clk_in, which should run
) S* h5 Z2 j% E! ?// at a minimum of 5 MHz for a 100 KHz I2C bus. The
8 C$ a4 w# }* @// debouncing on the inputs has been tested at up to 80 MHz.& d0 o8 z- g9 F4 W8 ^
// The I2C 7-bit device address is set by i2c_address. Address1 A H6 I. G t/ h6 L4 z4 B
// 0x6A was selected for FastImage because it doesn't/ E( v) G9 [( g7 @' Y8 B& x
// conflict with other devices on board.- K! {) d" S' n: m. i- C
// Because of limitations in Xilinx Abel, the I/O buffers
3 i" U4 b) |( y4 n" h4 z( a// for the I2C SDA and SCL signals were external to this
6 @; t9 t& i' P3 ?$ n; B6 k// macro.$ R# s i a }1 x& F b
// Three 8-bit buses are implemented for read data, write
1 g& I( h+ ^; a% E4 M# M; Q; K% r// data and subaddress. For a simple implementation where( g' h* N% ?! G9 v0 H% a ?3 \0 }
// only one 8-bit register is required, the subaddress may1 ]9 d$ U0 z+ X4 S
// be used as the register output using simple write and
$ l& ~6 Q3 U" h v; `& w) \// read protocol on the I2C bus. In this case looping the# @2 }8 c) U& a# D6 p
// subaddress output to the read data bus allows register& Y6 b: H4 n8 ~1 R/ Q' v, P) v
// read-back.6 ?1 {7 z% Y# A9 M
// For use with multiple internal registers, the subaddress8 S5 w. V4 _% T6 x& i: q" P
// provides the register address. The rd_wr_out output indicates
$ o8 N/ N5 V# v# O r$ r$ D8 e* `: r// the direction of the current I2C bus transaction and may8 Y( O3 \# D4 L
// be used to enable read data onto an externally combined
: K4 ^7 _% j) S# \$ v& x// read/write data bus. The wr_pulse_out signal can be used as
7 X2 N; t n3 Q5 } d// an active-high latch enable or clock enable for the
. c! C, q: M) M$ D) D// external registers. It comes on for one period of clk_in
; b, m+ W5 {& p8 I6 p+ `// and the subaddress and data are valid for at least one
# ^5 n! W* Y0 s. N0 V* t1 j9 C) \// clk_in period before and after wr_pulse_out.4 t. @* N( ~/ R4 q
// A rd_pulse_out output goes high for one clk_in period at the. f: b* X2 n! A9 j/ `( s; v4 X# p: a
// beginning of each data byte read. This indicates the
. b: R4 H6 @5 E// time when external data is latched from the read data
8 v9 u# o: e2 S( F// bus. It may be used to create side-effects on read
0 D6 J# A9 S8 a, c: w// such as clearing sticky status bits.
; k5 d) I- m, w( g* K//
; [3 p4 k0 A1 f. t" N///////////////////////////////////////////////////////////////////////////////
3 J3 [2 W1 F& I8 o7 Q5 x//9 F$ g& A, o" A, E# k" Z2 I, K) M7 k
// Modules Instantiated: none
+ J. E/ X4 ?/ q$ x# `& u8 H//# w1 I0 O9 _" b+ D0 A3 \
///////////////////////////////////////////////////////////////////////////////
% X8 K9 ]# m* @ b2 ]) j W//+ e, y/ V' L" g! p% K. U
// Modification History:* c$ x$ T/ q" u( N* b
//3 N4 w' A. g d% {
// Added clock enable to slow down state logic with fast input clock- ^. k: ]8 ]5 d' s/ C
// 6/9/05 - GLS.
/ ?! g9 O2 f/ y4 ^//4 H1 i; d f4 s I* G
//$ G5 N! x/ H2 j2 b- h: I4 ?) i
///////////////////////////////////////////////////////////////////////////////
8 ]" E8 s( B3 ?* Q1 s0 d& S- _///////////////////////////////////////////////////////////////////////////////
$ `2 q$ l; s' U% z( T# T+ i6 G5 n9 _0 c///////////////////////////////////////////////////////////////////////////////9 V: r) M) D) e7 i. U
`timescale 1 ns / 100 ps
# c# r, R# C, v- p" dmodule I2Cslave
# w3 r3 T8 Q5 [(" \. g$ r: X, G/ {7 ]
sda_io,
8 S8 H- y) B6 }5 O7 [ scl_in,
l) @# p. s5 v, U# C) ` rd_bus_7_0_in,% o" z% s; C$ V/ E& p0 X3 `4 O
clk_in,0 |9 o& i" J- |
clr_in,( U1 k5 a$ n. H% o0 E) r- F
subaddr_7_0_out,7 q& `6 X, o0 q/ r. ^! {
wr_bus_7_0_out,: U( I( \0 v7 s- V
wr_pulse_out,5 Y5 L! J- D- H* G( B) q
rd_pulse_out,
' S1 G$ ]9 {% u8 G) e5 F0 h rd_wr_out
: H) g, _8 j- q3 a6 f);# r, @! K* _6 h
// Inputs:8 C6 e, K( p8 R' N) T7 v# V
// I2C inputs (SDA is I/O externally)0 T: ^9 y1 |0 u( {9 d, I5 i+ a$ P
inout sda_io;
2 m: V, ~ ^( R7 {input scl_in;5 h) e4 U! p: h$ z- w6 o0 Q5 q: w
// 8-bit bus for reading registers, Z7 h( l: _+ f( k
input [7:0] rd_bus_7_0_in;3 w7 v a$ k3 }! F" I9 `
// High-speed clock for state machine logic
3 |" T+ R! Y$ ainput clk_in;
; i$ @& e# g* }9 G D ~// Asynchronous reset can be grounded for synthesis
3 X0 D) |$ ]* S. S& S% {4 Pinput clr_in;9 }# g4 a' a( L2 C
// Outputs:7 }& T. z# V( \' t
// 8-bit subaddress for register selection. X0 g0 c$ H6 {/ E4 v+ K; [
output [7:0] subaddr_7_0_out;# _8 M8 a* W0 [% @8 X
reg [7:0] subaddr_7_0_out;6 K7 Y8 O3 L$ d% g
// 8-bit bus for writing registers
% Q8 B4 r9 @' C) xoutput [7:0] wr_bus_7_0_out;: q; \' e/ u- T$ G ~/ W5 ^- V
reg [7:0] wr_bus_7_0_out;
5 c [, W; p& g, E// I2C data output drive low signal (1 = drive SDA low)
2 g' E5 K! e3 i" F' A7 B: y' v7 `reg drive_sda;) e7 v3 O( X' r- w) \% e' r& x
// Register write pulse. On for one clk_in cycle.$ M, p8 }+ _" ~, w! w0 N, o) o: }
output wr_pulse_out;/ z e1 Z' V1 R! |1 R' J
reg wr_pulse_out; J1 y9 I' q S' F" l
// Register read pulse. On for one clk_in cycle.
! U9 s8 e5 n. Z9 e9 Z; toutput rd_pulse_out;
B( s+ W% O0 E" m- K4 Greg rd_pulse_out;
1 ^: I$ z8 \. A6 _1 B. U, [7 q// Read / not Write. For external bus drivers if necessary.
! g; z* |4 v4 N1 v" Boutput rd_wr_out;
3 _9 h9 e) G3 q% w* Y" J7 s/ @reg rd_wr_out;
) Y4 t, ]$ _9 J" d// Internal Nodes:
' Q$ @+ |4 k: T8 t% P3 |9 `1 A// I2C input debounced nodes:- N. P) O* w4 ~& A: L
reg [3:0] sda_sr, scl_sr;
# W# }+ U" g4 M8 R% lreg sda, scl;% L8 K. R! l) A B3 A
// I2C edge detection nodes:$ U" t, F6 l! I
reg was_sda, was_scl;
5 F% q: ]% R/ J# m. [// Delayed pulses for address increment:2 U0 b$ ?1 { x3 r0 K! |
reg rd_pls_dly, wr_pls_dly;
0 P0 k- t6 L& M& O// I2C protocol state nodes:3 [0 X1 R+ r/ i/ g
reg i2c_start, i2c_stop;
9 y# B3 u& B- k; E$ ]1 I+ u( C1 F& Hreg [2:0] byte_count;6 W( U% ?3 d+ ^
reg ack_cyc;+ Y/ j8 |- @6 w
reg addr_byte, addr_ack, subad_byte, subad_ack, data_byte;; G F* }( m9 X7 z; E) ~- v
// Edge detection:5 d" L" Z0 D) i! R3 N2 {: K
reg was_ack;
, W2 R9 w$ a: p4 F+ {7 kreg my_cyc;; _; Z6 y# v, \, F# V9 p& o
// Input data shift register0 ^1 }- W2 }# _+ g, }
reg [7:0] in_sr;! J( A( H/ Z/ e7 W6 S1 b
// Output data shift register
6 ?2 u) f6 A2 F9 D/ T2 B0 S1 nreg [7:0] out_sr;
* Y4 R( \1 D! d1 ~+ [) n// internal node for bidirectional SDA line:
+ u! V- h( @1 j5 @% Zwire sda_in;5 f8 \7 v$ e7 b/ ^8 R0 ]# v y. o
IBUF sda_ibuf (.I (sda_io), .O (sda_in));2 [, ~' Z' W' w/ H4 n
OBUFE sda_obuf (.I (1'b0), .E (drive_sda), .O (sda_io));
) g; H( q0 x- u' |# W, bparameter i2c_address = 7'b0110101; // 6A write, 6B read* Z& d* ]+ i5 y. \& {
7 T+ |/ Z: b' _2 `// Equations1 Q/ F+ Z& m' [
// Debounce, then delay debounced signals for edge detection1 N/ P. T2 _% k9 @
always @ (posedge clk_in or posedge clr_in): C4 Y/ t2 h- c9 `; U
if (clr_in)3 w/ h% l4 s) n
begin3 M1 S1 O4 c" H. c0 V4 s7 d9 g$ d. y
sda_sr <= 4'b1111; // Start up assuming quiescent state of inputs
8 S8 q6 {, D- k! y sda <= 1;
* Y. ]9 L' ?# [/ ` a was_sda <= 0;# J* [, V- q8 t9 o
scl_sr <= 4'b1111; // Start up assuming quiescent state of inputs
1 ^: f- o) E8 S3 v9 f5 [. d% c scl <= 1;
, H) U' S% C& g! W0 D9 J was_scl <= 0;
) }5 u2 c# x9 s2 A' Q' w end5 U, |6 J1 `& J) ~ z5 @8 u
else+ d. ~' @# y7 g) Q$ l* ~3 Z
begin$ ^% \, {* U- V* q+ M3 C* C
sda_sr <= {sda_sr[2:0], sda_in};$ U2 t z* y5 U
if (sda_sr == 4'b0000) sda <= 0;
* ~- Z$ L, ~# ]9 b$ o4 j! _9 P else if (sda_sr == 4'b1111) sda <= 1;& G% ]6 s6 q' f. P. j
was_sda <= sda;" q( _5 N' i' R5 y7 w( ~
scl_sr <= {scl_sr[2:0], scl_in};
1 M) |0 {: ]; j4 n* C if (scl_sr == 4'b0000) scl <= 0;* C* z3 v# s: ?7 U) k# u) R& G2 M
else if (scl_sr == 4'b1111) scl <= 1;
( y. d5 H% I* B/ H was_scl <= scl;& l; v% f O" S7 P7 @
end6 [8 A( J, H+ n: D7 I
// Detect start and stop conditions on I2C bus:
# X4 O( @ m9 A, ^) t7 s talways @ (posedge clk_in or posedge clr_in)
4 O+ o! j! C ]; K6 L# p6 Z0 b- k" U if (clr_in)% K3 L; @( \) ~* E; |
begin
' q+ b \5 j8 X: w# h i2c_start <= 0;+ C: T7 D2 J0 {" h
i2c_stop <= 0;
3 } Y7 K. i; |; e% ?( ] end
0 T! `9 R! A0 s) K* ~ else5 w2 x% h/ M( D- Y
begin
" I3 N2 D% j2 _: t: S7 C; a+ l" O# T if (scl & was_scl & !sda & was_sda) i2c_start <= 1; // Falling edge of SDA with SCL high
& o! X4 y0 O- _ else if (!scl & !was_scl) i2c_start <= 0; // Hold until SCL has fallen- e& m3 H/ ~3 s% M4 x
i2c_stop <= scl & was_scl & sda & !was_sda ; // Rising edge of SDA with SCL high
$ C' b+ j; `; K e" Y9 M // i2c_stop is only on for one clock cycle. x% z. t) Q6 r) u: r/ M
end, r6 z% z# j( ~4 W
// Increment bit counter on falling edges of the
+ C# s9 c5 L2 c% N! x" y! w' y// SCL signal after the first in a packet.
9 i" b' s2 B/ k1 ^, n/ N8 x0 V" }, a// Count bit position within bytes:
- }! e* O; M2 u( {always @ (posedge clk_in or posedge i2c_start)
2 x7 Z$ D8 \2 q% }* i- i if (i2c_start)
6 v: |# L* k3 }3 @/ i; Q begin
0 G h* N: s: o" P' c5 Z5 x; V- g- Q ack_cyc <= 0;9 E; {, K6 A4 ~3 W. L0 g; l
byte_count <= 0;
! d4 {5 K2 W! O4 x/ t# l! [4 i end
; I. o" X5 ^# Q' B# S else if (!scl & was_scl & !i2c_start)
5 H. S0 c7 q6 q$ e: w begin8 }4 M/ _8 o( b2 X8 I w
// ack_cyc is really bit 3 of byte_count, counting from 0 to 85 w4 S( z% Z9 O& e9 Z- {
{ack_cyc,byte_count} <= ack_cyc ? 0 : {ack_cyc,byte_count} + 1;' f7 K4 ^" V1 W, P' X
end9 O9 c/ _' T4 v
// For edge detection of ack cycles:
, w7 n1 [: R0 {; M9 [ k; _always @ (posedge clk_in or posedge clr_in)5 a) b. y: N, p8 D2 S# x9 \
if (clr_in)
! I2 h3 L7 w! I z( V begin' Z: i: T! a& L4 A7 `
was_ack <= 0;& P) j1 U$ {2 G, k) x1 k
end
( y8 K: F( I/ C: `* A else( ]% _+ f( q* \
begin$ \5 s, ], S: |( J* ]+ T
was_ack <= ack_cyc;% b/ V, @. A( A; m
end
9 e8 h. J7 [ Y0 |/ I1 kalways @ (posedge clk_in or posedge clr_in)
+ G) M$ b! e$ c U if (clr_in)
4 x0 f& k0 R( J& Y2 C begin
3 Q$ ]& p$ o/ H0 h addr_byte <= 0;. E/ a3 L* p2 L/ ]" Q) i
addr_ack <= 0;
- X4 S0 O! m; t- m subad_byte <= 0;# F# Z8 m" ]- I v
subad_ack <= 0;: b) v! V3 E, C, L% m1 M1 a
wr_pulse_out <= 0;
& ~4 v. T; n4 O+ ]2 a5 z+ S rd_pulse_out <= 0;
& R+ J( W0 ], n4 S4 N2 p# q7 t end' W. U% `% `5 n! C% a/ h2 E9 n
else
; [( `& J& g: M: @7 C8 C begin
$ P- \+ ?( A/ T* n$ Z9 {: ` // addr_byte is on during the first byte transmitted after
; x8 u- W- a" t4 I; W% {2 m8 ? // a START condition.
+ W* R$ f7 e' k$ T4 A; n) K" u# Y: m if (i2c_start) addr_byte <= 1;2 v; S$ {8 e9 @( K7 Z
else if (ack_cyc) addr_byte <= 0;
* {8 \4 T A/ `5 ~ d1 D // addr_ack is on during acknowledge cycle of the address
* F9 v& K; c7 ~- {0 P5 e // byte.
" L8 t6 \* q! K if (addr_byte & ack_cyc) addr_ack <= 1;0 c1 {) e3 J, L* ?& X9 e, E5 }
else if (!ack_cyc) addr_ack <= 0;
6 ?: M0 `9 X7 t7 x: S // subad_byte is on for the second byte of my write cycle.' r: x2 H- A2 X
if (addr_ack & !ack_cyc & !rd_wr_out & my_cyc) subad_byte <= 1;
2 D% ^3 R4 G2 P# U* Z8 \ else if (ack_cyc) subad_byte <= 0;, m5 B7 F$ t f& G1 R
// subad_ack is on during the acknowledge cycle of the
6 P8 D) ?) f% d0 n& I // subaddress byte.7 u9 n. d( S$ K- h7 [6 ^1 R
if (subad_byte & ack_cyc) subad_ack <= 1;
t: ]0 `4 I9 n+ K else if (!ack_cyc) subad_ack <= 0;
! _$ h/ M5 O7 T4 n/ J* N // data_byte is on for my read or write data cycles. This is
1 Q, {+ K8 n4 a // any read cycle after the address, or write cycles after
( [" A/ j# c4 W: a( V0 J // the subaddress. It remains on until the I2C STOP event or3 Y: _5 \) ]" W0 q! n1 h
// any NACK.
# S8 n! v, s R; ^4 G0 L$ I if (addr_ack & !ack_cyc & rd_wr_out & my_cyc | subad_ack & !ack_cyc) data_byte <= 1;! J! n w0 i. G' X- r
else if (i2c_stop | ack_cyc & scl & sda) data_byte <= 0;
! j" e) d+ P/ \5 v // wr_pulse_out is on for one clock cycle while the data
0 ^' C+ m( R" J" ^0 M4 B // on the output bus is valid.
: X. k% I. C. t q wr_pulse_out <= data_byte & !ack_cyc & was_ack & !rd_wr_out;) W( J! A+ b9 ^
// rd_pulse_out is on for one clock cycle when external
" ?4 {* W1 \7 d, ]% J- p // read data is transfered into the output shift register0 m4 b$ j, m( {5 u. E3 D" u
// for transmission to the I2C bus.
, }& R4 Z4 ^ [& _# u- x rd_pulse_out <= addr_ack & !ack_cyc & rd_wr_out & my_cyc // First read cycle1 D4 R( G" d/ l7 S# s- v% G) o
| data_byte & !ack_cyc & was_ack & rd_wr_out ; // Subsequent read cycles
! h! }3 n- s# t) { end
, y, o& Y' D$ J8 b9 X% r8 P3 W' |6 ?! W// wr_bus_7_0_out is loaded from the I2C input S/R at the6 l! A) p3 y8 d. B# }* c3 f
// end of each write data cycle.
' I/ r$ w" i; m0 y* E: q% \always @ (posedge clk_in or posedge clr_in)
6 c9 T3 O2 R" Q, \$ Z3 `# u if (clr_in); F1 n4 D) h/ h: u, v: u
begin
' ]' M3 z- s$ A: l* o9 `9 ^ wr_bus_7_0_out <= 0;
$ h) a. v$ Y0 ~6 {. i end
6 }7 T" f" [$ Q. y else if (data_byte & ack_cyc & !was_ack & !rd_wr_out)
* ?& k: w }& N: n- L& Z: R begin4 d. T2 x% W7 I$ J* D) b
wr_bus_7_0_out <= in_sr;
; z g" ]& e( O9 R' }. f end
& ^% y7 C/ _& b0 P: X$ N, I// out_sr shifts data out to the I2C bus during read
s; E |6 S7 _3 S6 w1 \( u// data cycles. Transitions occur after the falling
, H) D3 W% ^+ c8 L( F) J, ~// edge of SCL. Fills with 1's from right.
7 w2 o% L1 a# K$ ^+ n+ j% M5 xalways @ (posedge clk_in or posedge clr_in)4 ]4 l; y( ^$ G- l8 Y' l
if (clr_in)' |6 R" I, ^: }) b
begin
3 o5 p: y8 z& Y/ U out_sr <= 8'b11111111;$ E6 V' H% e1 H* a1 G
end
# s# m8 F. B& E else- S( | f: M# Q* u
begin. d. M3 @6 U: J: G
if (rd_pulse_out) out_sr <= rd_bus_7_0_in;' o* c/ i- Y H1 u% y" s
else if (!scl & was_scl) out_sr <= {out_sr[6:0],1'b1};8 G1 ]0 o' F& V, h" w3 l+ ?
end
+ I1 d/ d: C: J// Delayed pulses for incrementing subaddress:
. g9 y+ m; p' T& h$ e! B* Palways @ (posedge clk_in or posedge clr_in)" f* z. t& f+ C0 f( U
if (clr_in)
! `2 x% v B! `' j" Z! L5 X2 [4 ]9 B begin5 u v L3 Q2 J6 f# \+ d
wr_pls_dly <= 0;
; I/ Z& a- m" S, f$ V( x# A# t# g rd_pls_dly <= 0;
. t s6 X* A k end
; ]- s5 y' \9 e: r! G( d else! ?5 Z; g: P/ a
begin
- n$ M& I4 w1 a! C wr_pls_dly <= wr_pulse_out;/ T2 Q, V& b& }. v t
rd_pls_dly <= rd_pulse_out;# b3 R1 Z H4 ?* Z
end
/ v; B6 U2 x$ b8 U" @// subaddr_7_0_out is loaded after the second byte of a write
% ?# T8 |7 d. @' z- x8 f1 H% y/ a// cycle has fully shifted in. It increments after each
* f& f; ` [/ o// read or write access.
* Q3 }! D9 z- L0 y- |+ r* Nalways @ (posedge clk_in or posedge clr_in)
, t9 @( i& u9 g# d; ]& n if (clr_in)
+ ^% _2 e) v% p/ {: g2 B/ K/ S begin
0 @5 F# o6 t* J8 g( m7 R& v9 ? subaddr_7_0_out <= 0;5 j- _3 e, ` a/ |$ {$ e- q2 O
end- Z) n6 g: F( R6 X# c
else
@9 V2 ]# l& z5 H8 S begin* l; d/ B. }# k* t$ n9 d5 y9 J0 H
if (subad_byte & ack_cyc) subaddr_7_0_out <= in_sr;9 p4 O2 d1 u7 C# S
// Leave Out this else clause for simple single register version- J5 d. {( |& o8 D) E: ?4 z0 A; ]
// In this case subaddr_7_0_out becomes the register output and should be1 ~- _" O3 M( ~
// wrapped back to rd_bus_7_0_in externally
, v. T0 U7 z1 \! a# z else if (wr_pls_dly | rd_pls_dly) subaddr_7_0_out <= subaddr_7_0_out + 1;
2 ^- Q3 V7 {5 @2 N1 R/ _ end! W( X; q& ^* W
// Shift I2C data in after rising edge of SCL.: d, v* w/ X2 I; Y$ g
always @ (posedge clk_in or posedge clr_in), t) o" _- w8 r/ r; T3 i* M, y
if (clr_in)
2 m/ U0 g$ N; f8 K* P: N' k( ]/ m begin
( e6 E# k3 J1 I+ k" S' [+ \ in_sr <= 0;
, m$ ~. I. n( Z5 r3 v3 x0 K end# d& G7 T+ |, p$ r0 V
else if (scl & !was_scl). z: [3 }! K3 z% x4 f$ u7 n* |
begin
# ?; t5 u' q9 o% e' s" ~ in_sr <= {in_sr[6:0],sda};0 e/ `9 p- K" `- k8 o r, b
end
6 F: c+ ?; w' N" B& X// Read / not Write. For external bus drivers if necessary.
4 c9 o: T* |1 D4 }% k$ V# D% o. }) B// Latch the Read bit of the address cycle.1 g2 U+ i. N S) O9 I9 l
always @ (posedge clk_in or posedge clr_in)
& d) h/ r& _5 E* z0 c if (clr_in) a( b6 V% q: w; B- J
begin
! d r$ e6 u. [. j$ D1 G rd_wr_out <= 0;( R1 k6 G* H Q
end/ A1 D; a; l) G8 D' |% n
else if (addr_byte & ack_cyc)
9 G% A& W v# ~- n begin$ K* f2 P! O1 x- {
rd_wr_out <= in_sr[0];, ^# i( K& [; l) K! u8 n
end( r q3 }4 U; i. q q' U
// Decode address. My cycle if address upper 7 bits
- Q- X9 X( c0 d1 J// match with i2c_address defined above.
4 \( \2 I6 H2 l& {- p9 m$ c1 ?9 Walways @ (posedge clk_in or posedge i2c_start)
/ p* x4 h9 z- q0 j% @ if (i2c_start)
+ b+ L: ]4 k% x" ~$ X, A: ~ begin
) y2 o9 c& x4 g8 n, ]7 D end% S1 n$ [) g) E, I2 I3 B
else if (addr_byte & ack_cyc)
& p0 `. e& W0 J begin4 q% [6 q8 n6 d
my_cyc <= (in_sr[7:1] == i2c_address);
) i* z5 @! Y7 L g) |; W3 A, P end. F) T) s* W" y* t5 a/ s
// I2C data output drive low signal (1 = drive SDA low)1 v- J. _9 z1 T0 x- t" e* {/ `
// Invert this signal for T input of OBUFT or IOBUF5 ^. T8 ~. g- `- M, y; P
// or use it directly for OBUFE.
4 s4 r. j" p! P" p" Ialways @ (posedge clk_in or posedge clr_in)# j. N9 p* z2 t" ~, d
if (clr_in)
2 a! {* I# y$ l5 B6 D begin
: v7 E' ^, w/ j2 x: L1 j drive_sda <= 0;
) D4 k- r- F; _1 f0 D end r, x2 ]+ E7 c a( h5 R1 S/ k. f% I
else1 Q& J; M% k' z# [0 C$ u. _
begin
+ `- p% ^2 W1 p drive_sda <= my_cyc & addr_ack // Address acknowledge% R5 |* b+ \8 N9 A* J7 p! l- \
| my_cyc & !rd_wr_out & ack_cyc // Write byte acknowledge
5 s5 m% [ A1 a0 l* }: ^' W | data_byte & rd_wr_out & !ack_cyc & !out_sr[7] ; // Read Data
/ \% [" M N1 `8 l/ G end; P6 X$ j; q5 {" X- H! b
endmodule // I2Cslave |
|