|
找到一个I2C Slave的代码,可惜Verlog看不懂,发上来给大家参考2 ? v% ]0 K i( n/ H
' }5 z) F" X V6 ^
//////////////////////////////////////////////////////////////////////////////// w- ]) h: r8 o/ p u6 D# @5 i
//7 Z. ^3 g: [) G7 [1 ]
// Alacron Inc. - Confidential: All Rights Reserved
9 h4 J* F9 O Z' o// Copyright (C) 2003' A4 D! b4 M! A; n0 n9 a
// D0 `9 O m1 q* o1 i1 E. n% R* N
// Title : I2C Slave Control Logic
% Z$ J$ g* {4 B+ p5 r1 o& X// File : I2CSLAVE.v; z' X& K0 B) r; ^% w* h1 z
// Author : Gabor Szakacs
* b* D' C, P' d P2 }// Created : 25-May-2004 - Adapted from I2CSLAVE.abl
, O: m% g5 v! X4 R5 F//
! r/ A3 n1 n- x9 q//
" S' ?) r) C' q! }+ d///////////////////////////////////////////////////////////////////////////////* s6 h/ J- V- [" D+ w V
//5 r" C1 ~$ ?0 U; r: n! T3 I4 i( b
// Description :4 s9 H7 G3 n- J5 ^
// This code implements an I2C slave-only controller.
. T0 j2 W. F3 {1 |// Access to internal registers uses the sub-address7 E. P0 f/ a0 Y
// protocol like a serial EEPROM. No registers are; c i& M5 u8 o. j
// implemented in this module, however the module
' @! g+ q2 c1 F3 l5 w% g// provides a simple bus interface to external registers." Z9 o. c) M3 \
// GLS - 12/13/00
/ F% C2 ^" {& Q& c4 E// I2C inputs are oversampled by clk_in, which should run3 Q! {3 h2 S8 f; ?( x
// at a minimum of 5 MHz for a 100 KHz I2C bus. The
/ J* r. P* ^) [6 X8 s! B' W7 t// debouncing on the inputs has been tested at up to 80 MHz.' c2 I$ r2 K% u; J, a) |3 n1 B. X
// The I2C 7-bit device address is set by i2c_address. Address- U8 P3 D0 c s! E& G- w, T; h
// 0x6A was selected for FastImage because it doesn't% p/ `. `/ \; k0 C; X6 k
// conflict with other devices on board.
; j+ L% N* B! X2 c* `% |// Because of limitations in Xilinx Abel, the I/O buffers% @7 c/ e. g- W1 t7 a
// for the I2C SDA and SCL signals were external to this( B$ a7 Y9 R& v
// macro.( j' C( J9 k3 P" T
// Three 8-bit buses are implemented for read data, write
8 d2 ~1 f1 V9 |// data and subaddress. For a simple implementation where% Z2 I) J8 O. }$ `
// only one 8-bit register is required, the subaddress may) u0 d8 h; o D: Y, R& r3 y. [) K+ v% ~
// be used as the register output using simple write and
* W" H+ q$ x' q- V: y5 L// read protocol on the I2C bus. In this case looping the8 x) {6 z# t# [$ V. O
// subaddress output to the read data bus allows register
+ v# d- p2 C/ X' X4 s" T* d// read-back.
! J) }; Z- e+ k+ y* n# j// For use with multiple internal registers, the subaddress
& d' u9 P5 @: M( c// provides the register address. The rd_wr_out output indicates
1 f8 C: s; i# o! Z" D; @// the direction of the current I2C bus transaction and may
( k1 O. a, L) N// be used to enable read data onto an externally combined
/ Y, D, E/ ?4 L, ]1 c// read/write data bus. The wr_pulse_out signal can be used as
& ]6 G( t0 z3 h( U// an active-high latch enable or clock enable for the8 `2 J5 u4 w6 r! w m; F
// external registers. It comes on for one period of clk_in8 P2 _! c4 x+ \9 z
// and the subaddress and data are valid for at least one4 }) M3 I2 K6 @" x3 P( Y. ~& @, t& A. w
// clk_in period before and after wr_pulse_out." P3 C- N9 m0 ~) b% U* Z. {
// A rd_pulse_out output goes high for one clk_in period at the
8 f# p! @" h1 j5 s// beginning of each data byte read. This indicates the
4 n) @. e3 o" Q. O0 E// time when external data is latched from the read data' {1 O, Y: h$ v& l
// bus. It may be used to create side-effects on read3 V5 Y; C) C: Q
// such as clearing sticky status bits.) z% d! E8 Q' ^
//4 Z& ~3 B& t0 Z5 t$ @
///////////////////////////////////////////////////////////////////////////////
- d- Z4 b* V' `/ Y& N- @//
1 ]3 L1 @0 r7 u) N$ Q// Modules Instantiated: none
8 m' a, O( l; k( F: G! U) G//: u3 p4 S; S, G- _/ Q
//////////////////////////////////////////////////////////////////////////////// ]5 K$ V$ h9 d4 S0 W& v
//
- E* w9 w" T% t7 U// Modification History:, v* ^0 _ k& [( q0 t5 t
//2 ^0 ~" y% ~) h1 M F- q
// Added clock enable to slow down state logic with fast input clock
# Z$ ^" F- i; E9 T2 f// 6/9/05 - GLS.
F2 p' X7 j% R+ O/// h( l( }+ i3 K1 c# @8 I! o* t. e0 M
//, h0 D+ o& Y! x; i9 ~% V: I
///////////////////////////////////////////////////////////////////////////////8 s) s8 E' Z* k& Q. o
///////////////////////////////////////////////////////////////////////////////* G. b/ _* p! M: Y
///////////////////////////////////////////////////////////////////////////////2 W1 |1 T% Q7 o+ J
`timescale 1 ns / 100 ps
. c# K9 ~9 @, l7 Vmodule I2Cslave
9 _/ n$ b ~/ H5 F# F9 F(
% Y: m/ Z( E l: Q sda_io,1 A2 m! W7 C9 Q7 c( T8 J4 k, N0 R
scl_in,
$ C, x' {3 S; \/ A" h" C rd_bus_7_0_in,
& r% t9 S M2 j* L6 G clk_in,
% H4 v. S' m* X9 o3 G% E clr_in,' u, w1 G8 v: k3 f
subaddr_7_0_out,
9 a1 ~1 V5 O8 l, S7 L, {- X wr_bus_7_0_out,3 ?, p5 g0 ~5 W2 f
wr_pulse_out,; K Z. C5 L% m4 I# e
rd_pulse_out,3 u) R) W, B3 I! k' B
rd_wr_out5 h( u& O+ W' U+ \
);
- x, D9 o2 N3 q( q// Inputs:
; x$ ^1 k# C' S- I9 n* a// I2C inputs (SDA is I/O externally)
8 \& _# p- O- [; U" v& Ninout sda_io;, N, k, ^- c3 _- s
input scl_in;
4 ?- Q7 r% C. K) o// 8-bit bus for reading registers* B( D/ A- B) z& R* x% |+ l
input [7:0] rd_bus_7_0_in;
. j; v) t& m: j/ {// High-speed clock for state machine logic
/ Y" C3 p5 i1 [7 ~$ y7 ?2 H% K7 ?9 iinput clk_in;
& j. h' J7 k o5 w. s. r2 q/ c// Asynchronous reset can be grounded for synthesis Q7 g& E% _# f
input clr_in;3 ?% V0 O9 x. o
// Outputs:
* [ I8 n( W& ]( x' v// 8-bit subaddress for register selection
6 o; q& i( k2 ?' t. x; l5 q noutput [7:0] subaddr_7_0_out;
. m/ |' Q3 \' _1 i1 o4 [reg [7:0] subaddr_7_0_out;
/ T' P4 ^, B% L- |/ B; I& k' o// 8-bit bus for writing registers
6 B9 X6 P+ q& @: U! [ Zoutput [7:0] wr_bus_7_0_out;3 ]( m; h9 [" X' z
reg [7:0] wr_bus_7_0_out;2 a; B/ d0 Y& x+ e) G0 ^" F
// I2C data output drive low signal (1 = drive SDA low)
5 T4 \+ R! }3 T- z# Q+ D/ Y2 ereg drive_sda;3 t3 ]+ j( i& c- w+ C* T
// Register write pulse. On for one clk_in cycle.8 C7 ^ n4 g1 C/ Y# @
output wr_pulse_out;
* E$ X! o. F! Creg wr_pulse_out;
: d: W# [7 l% A( P. d& P" V# n( l// Register read pulse. On for one clk_in cycle.
c9 s5 j+ }5 l9 y/ x8 J& K6 Eoutput rd_pulse_out;
7 L; ?; R% U/ E- f) d# `9 ]5 Areg rd_pulse_out;
! f- G2 h, i; d4 h6 \$ Y+ r// Read / not Write. For external bus drivers if necessary.
6 ~" g6 `! c2 t" \$ n1 Q. ^output rd_wr_out;
7 Y+ G; @6 _, x0 a& [. R+ F) x# b1 wreg rd_wr_out;- g2 q% I" i* _1 C" e
// Internal Nodes:' p: f* F* U: A; W. ?
// I2C input debounced nodes:4 v1 F2 o7 n# z: f& n& A2 R
reg [3:0] sda_sr, scl_sr;
( K& g/ n2 _! S* i' Oreg sda, scl;/ M, w# }) {) k5 `5 V4 m6 W1 p% `
// I2C edge detection nodes:0 H o3 q* [$ v2 b
reg was_sda, was_scl;
5 ^' i. ~, d; C2 j- Z+ ]5 v// Delayed pulses for address increment:
3 W4 y5 W1 Q9 ?; xreg rd_pls_dly, wr_pls_dly;
( Y, t5 |2 C7 ^) p// I2C protocol state nodes:
) e- D- _# T9 P. ]reg i2c_start, i2c_stop;
0 i( \8 Y) ~2 k) x1 h$ r6 ?reg [2:0] byte_count;
$ x! z j. [1 R3 Mreg ack_cyc;4 O1 `6 f8 A6 P
reg addr_byte, addr_ack, subad_byte, subad_ack, data_byte;9 Z* t' y! R8 O; `. z
// Edge detection:/ c3 `' h, h4 [! J9 F: z
reg was_ack;% m1 J3 N' b) k8 e& G
reg my_cyc;, }) M" n- p0 S9 |4 a
// Input data shift register! N9 \- Y* z+ B% d
reg [7:0] in_sr;
) y/ M" U# R8 U0 a; d// Output data shift register
0 v0 `# q% B/ o3 {reg [7:0] out_sr;8 D" m# s; u) o+ Y, e
// internal node for bidirectional SDA line:- m9 Q& K' P" W f% o! I' a# v+ [ ~
wire sda_in;& C0 b. A8 ~" ~9 l* @ ~
IBUF sda_ibuf (.I (sda_io), .O (sda_in));
% H; X% j3 T. o: Q) K: [2 tOBUFE sda_obuf (.I (1'b0), .E (drive_sda), .O (sda_io));
( }& {- z. L0 u' oparameter i2c_address = 7'b0110101; // 6A write, 6B read! ~0 ~3 F& y+ J/ C
5 I* M+ ~. Q- d% d
// Equations
, [8 W! Z" p( z- L8 l* q' p// Debounce, then delay debounced signals for edge detection
7 X* f" X+ d8 ]always @ (posedge clk_in or posedge clr_in)
1 ?! |5 d6 }2 U7 g if (clr_in)2 D& x1 i; T3 L; b
begin* H+ G1 W' g9 M v2 v2 D
sda_sr <= 4'b1111; // Start up assuming quiescent state of inputs
5 f4 B% v8 K9 A/ L5 b sda <= 1;2 C% z9 `- C2 l
was_sda <= 0;
0 Z8 r& g# d7 O8 e scl_sr <= 4'b1111; // Start up assuming quiescent state of inputs
, ~% {, |& Y" b+ N3 I# K4 M scl <= 1;
% I7 E. J+ Q1 T: ]* u4 g3 @ was_scl <= 0;
% @* C+ i7 H% }: A4 z, J) u end1 p% M+ `& j% f q% v
else
# h9 i e% t6 J& x, ^ begin5 n) p T0 l0 c' n( V
sda_sr <= {sda_sr[2:0], sda_in};
8 ` u' e6 _1 ~. x if (sda_sr == 4'b0000) sda <= 0;- n& q2 ?# a# ?; E
else if (sda_sr == 4'b1111) sda <= 1;: [+ L! i$ R' E( I- v% T- y
was_sda <= sda;" k: k5 X8 Y) O, _9 a2 k- v
scl_sr <= {scl_sr[2:0], scl_in};3 J, T3 I2 A3 ~1 W" Z& ^8 z- ]
if (scl_sr == 4'b0000) scl <= 0;) s/ a# o+ z! C( a
else if (scl_sr == 4'b1111) scl <= 1;
) Y9 M9 q o; a/ k% Y6 E was_scl <= scl;
9 Q( \+ X( U6 z end' c# U) x8 [6 D' I+ U
// Detect start and stop conditions on I2C bus:
w( z. W1 \+ p5 Falways @ (posedge clk_in or posedge clr_in): d1 z, l0 E/ M
if (clr_in)
# D3 E9 y( X% C. V7 n) Y begin
# r/ \& j3 C4 i1 g, a i2c_start <= 0;
# {' b9 h. l$ O% G4 k q, R i2c_stop <= 0;" C9 L" n7 L1 {3 E
end
/ w1 D2 i! I2 T% l/ i: Y else
5 g: t# a% ~9 K begin
- h. f+ Q, N% ?4 T6 Q6 { if (scl & was_scl & !sda & was_sda) i2c_start <= 1; // Falling edge of SDA with SCL high! S) B) F, ^9 b9 I
else if (!scl & !was_scl) i2c_start <= 0; // Hold until SCL has fallen+ L1 z0 A& ~( p
i2c_stop <= scl & was_scl & sda & !was_sda ; // Rising edge of SDA with SCL high
+ R+ h( h+ I ?( E( x! X& ~ f6 u& S // i2c_stop is only on for one clock cycle* ^2 @& `6 H1 \, @+ L2 b0 m
end( s' Q; u; {( k/ w; ?
// Increment bit counter on falling edges of the$ N% Z" n) ~2 w+ P4 {- d$ j- [0 f
// SCL signal after the first in a packet.
% `( c A: Y4 v/ H// Count bit position within bytes:. E4 `/ z' S. e# U' U+ y X+ N
always @ (posedge clk_in or posedge i2c_start); Y. W3 K, n/ Z( P
if (i2c_start)
p9 h: W+ g; L$ a; u' b begin
+ S1 S9 E: p9 z& y2 V ack_cyc <= 0;2 i2 G; |" a( H* U `& } B8 y
byte_count <= 0;, ]4 u' I$ r! \% D# j0 p0 q6 z+ J
end' p$ C% t3 ~2 {, c# Q6 I) }
else if (!scl & was_scl & !i2c_start)
( I: y D- j0 b begin
0 }3 G l+ A5 Y: n3 k0 T // ack_cyc is really bit 3 of byte_count, counting from 0 to 8
) A7 y$ Q* Z4 m4 R' N; _ {ack_cyc,byte_count} <= ack_cyc ? 0 : {ack_cyc,byte_count} + 1;3 C2 X- ~/ r% t5 h
end" Y8 t, e7 J$ u7 T
// For edge detection of ack cycles:
7 e1 \5 _+ R" P* x# X5 m2 {always @ (posedge clk_in or posedge clr_in)2 b# i1 T: K" X3 D$ i5 b
if (clr_in)
' P h) ~8 _# j) Q! ] begin% y- S2 ]1 y7 R5 y4 O, ]
was_ack <= 0;* ^: p1 q4 V7 k4 f8 G
end4 h) x0 h" a! |4 x
else5 p: d; r0 F; ~3 G- e; M- I: q
begin
; ~ `# [/ Z( r( P was_ack <= ack_cyc;& a: r4 K# j# f5 |
end0 M, X# i' W4 `8 b1 P) M& r2 D( i: z
always @ (posedge clk_in or posedge clr_in)/ ^# C# ]9 _3 U) g7 c
if (clr_in); A+ }2 M% I5 H( c5 |& {
begin$ U, n7 P y0 R4 F
addr_byte <= 0;
/ y8 C5 D2 W2 Y# s) S addr_ack <= 0;
* c# J. I }! x. D4 w: | subad_byte <= 0;
4 I; N% w! u7 t( Z- H subad_ack <= 0;' Z+ h3 b, T, ~( x& R
wr_pulse_out <= 0;; }) u( T0 m# M* Y& Q* R
rd_pulse_out <= 0;. N5 n' ]0 P7 p+ f
end5 ]- ~8 K6 d3 }1 T6 j" K
else0 \( [# S# ]% [7 O9 S
begin" Q) A0 L2 E. h- P$ O2 ?5 ~
// addr_byte is on during the first byte transmitted after
4 H* H" |9 `! x6 \) ^& w9 [ // a START condition.
! i p6 t8 f* D if (i2c_start) addr_byte <= 1;
& M: f) q+ q: k! d else if (ack_cyc) addr_byte <= 0;
$ D! l4 T8 C3 g8 C! i: P // addr_ack is on during acknowledge cycle of the address& N: P8 ^" M" n4 p! t: ^. b/ W7 Q
// byte.
$ Y1 R5 M5 i; r3 J/ Z if (addr_byte & ack_cyc) addr_ack <= 1;
3 T/ e% e6 R$ ~6 U3 O8 H, x+ U else if (!ack_cyc) addr_ack <= 0;% y# [/ \! ^ B
// subad_byte is on for the second byte of my write cycle.
; K1 k+ k+ F$ q. U9 S5 }: t if (addr_ack & !ack_cyc & !rd_wr_out & my_cyc) subad_byte <= 1;
7 g6 M8 G! }0 S3 T$ o" |7 e( d* o else if (ack_cyc) subad_byte <= 0;, Y( [! ], S6 M2 x; i$ X
// subad_ack is on during the acknowledge cycle of the2 L+ @6 |( a3 X! v6 r$ F
// subaddress byte.6 w* Y$ t9 b/ E9 j* I( C
if (subad_byte & ack_cyc) subad_ack <= 1;* t2 Y$ B9 i3 n$ p( \
else if (!ack_cyc) subad_ack <= 0;6 x( J1 F& y/ t; W" `9 g
// data_byte is on for my read or write data cycles. This is1 }' K/ G0 ]; }% k- ~
// any read cycle after the address, or write cycles after
: l& C1 ` C" ]" |/ z1 m7 P) m // the subaddress. It remains on until the I2C STOP event or3 y' ]% ?" c& ^$ f
// any NACK.
5 {5 q$ K) z( n& \5 _ if (addr_ack & !ack_cyc & rd_wr_out & my_cyc | subad_ack & !ack_cyc) data_byte <= 1;
$ n- W( M0 }7 U8 m; c# c! ? else if (i2c_stop | ack_cyc & scl & sda) data_byte <= 0;
+ M1 o5 M0 v; A* d6 t // wr_pulse_out is on for one clock cycle while the data' p- t. f2 U' }/ {" e
// on the output bus is valid.8 q. y$ r" K; F" N
wr_pulse_out <= data_byte & !ack_cyc & was_ack & !rd_wr_out;
4 B5 I1 [6 M' N // rd_pulse_out is on for one clock cycle when external7 F; z: G; `* ? } a* W- o9 B6 [
// read data is transfered into the output shift register1 m( J3 F/ x4 G7 U/ I x o9 r( |
// for transmission to the I2C bus.5 E8 _- o& \% R2 a# |8 A0 o
rd_pulse_out <= addr_ack & !ack_cyc & rd_wr_out & my_cyc // First read cycle
5 G( U4 s+ ], y- p; a0 m | data_byte & !ack_cyc & was_ack & rd_wr_out ; // Subsequent read cycles7 m8 K2 x+ X" n% r6 L# I
end
! c8 ]7 A5 i5 y& X5 [3 W0 l// wr_bus_7_0_out is loaded from the I2C input S/R at the
4 S; ~+ j- w' D7 ]! z% W4 t// end of each write data cycle.
6 u! x7 N4 Z4 X$ _: D0 ]6 |. }always @ (posedge clk_in or posedge clr_in); H! m9 s3 C8 g8 {# l: n K8 W
if (clr_in)7 w' C" y/ j ^8 B
begin
! ?! Z6 x, g% p wr_bus_7_0_out <= 0;
2 Z' T: r8 d! R end
+ c' W- l8 E4 F9 h- s else if (data_byte & ack_cyc & !was_ack & !rd_wr_out)4 V8 B0 U7 P p4 l8 t
begin- m6 u6 j. R, `# G# A+ [4 O4 R
wr_bus_7_0_out <= in_sr;
4 S4 G" d- Y4 _6 y& o3 |7 U( S end/ P' u, |! P; C$ d
// out_sr shifts data out to the I2C bus during read
" \& h) R8 H) X" J' `2 C3 b) B// data cycles. Transitions occur after the falling
( _+ h L/ X/ m4 y4 ^+ v$ O// edge of SCL. Fills with 1's from right.6 ^0 w% Y: r" G9 k6 B" I' b, r
always @ (posedge clk_in or posedge clr_in)
- R4 G/ n* i# d$ ]8 _7 ]: L if (clr_in)' ^; Z2 { `1 ~+ |# U
begin0 p0 w0 x/ `6 J! o/ t7 c4 m
out_sr <= 8'b11111111;5 d5 U1 ~) Q9 \% J3 ]9 ~0 C
end/ w9 ^3 j+ Z* l% M9 [: I6 y% m D
else* x7 T9 e }3 W6 y
begin' X$ O8 w7 `% U9 X( b8 w
if (rd_pulse_out) out_sr <= rd_bus_7_0_in;$ L9 `) Q( W9 g
else if (!scl & was_scl) out_sr <= {out_sr[6:0],1'b1};' g" W. O0 l1 |- [
end
/ @! M& y; p0 f1 `0 [& x* w. J// Delayed pulses for incrementing subaddress:
9 F2 O5 W& V" {4 B8 Z0 l% Valways @ (posedge clk_in or posedge clr_in)
$ \3 t7 c9 X$ X+ V0 p3 j if (clr_in)
, O; ?% w4 j$ e/ Z! `8 [2 S8 E+ i begin) Q6 j7 u, R7 g- }; M* g
wr_pls_dly <= 0;
' @' o7 q2 \( {9 C J7 N rd_pls_dly <= 0;2 g! v% T1 F" N
end0 f& @$ T$ S' G0 i6 v
else) H4 d `: ~: ]
begin
# y2 H8 P& Q. D; } wr_pls_dly <= wr_pulse_out;# v6 @4 ]$ O w3 c. ]
rd_pls_dly <= rd_pulse_out;
- L6 N/ E6 v/ n9 M' r; t end K' q) i& C) m, P1 u! W
// subaddr_7_0_out is loaded after the second byte of a write! G; ?/ S2 ^1 \
// cycle has fully shifted in. It increments after each& g5 ]+ D3 @4 M8 H; t& p5 Q- s' D
// read or write access.. o; v0 d6 f- O( a
always @ (posedge clk_in or posedge clr_in); c7 f3 ?/ G) Q; o% H# c0 n
if (clr_in)7 o$ l* {2 d& q; i9 w
begin
3 N/ N; i- Q, ^, I& P subaddr_7_0_out <= 0;
0 a+ i) D" _1 d: R9 l% K; u. D end* M3 U1 j2 M& Q5 k* a9 m9 |6 L
else
- C! V- S# q5 S& c# w9 G begin
2 P1 C9 W5 L5 I3 D+ Q' q if (subad_byte & ack_cyc) subaddr_7_0_out <= in_sr;
6 z; `2 I) K; o3 B4 `; a // Leave Out this else clause for simple single register version* A8 H o% c% u) n2 O0 D3 F" z
// In this case subaddr_7_0_out becomes the register output and should be( A* |; x5 ^% m
// wrapped back to rd_bus_7_0_in externally
$ W& s2 U$ k: J, H. O/ d* E; R else if (wr_pls_dly | rd_pls_dly) subaddr_7_0_out <= subaddr_7_0_out + 1;
! \8 ?! W% |$ E end! y: V+ ~- I9 t4 K
// Shift I2C data in after rising edge of SCL." s+ k; P9 a" D; @
always @ (posedge clk_in or posedge clr_in)
% t' G3 c) W7 _$ p4 G0 f$ E if (clr_in)
1 W: E6 b. E* g' q7 P" \$ g begin
1 z+ J% F7 U: J; `3 L in_sr <= 0;
5 t; a' ~# [0 Z! n3 n1 B end. p& S7 s1 @0 _9 N7 Z
else if (scl & !was_scl)
) X) X. S. c l! S( K- g begin7 U7 t" F& c U# n
in_sr <= {in_sr[6:0],sda};
6 W/ ?( t4 c# q end
2 S& a* z& E. ?% w! W$ G4 ^" ]" y// Read / not Write. For external bus drivers if necessary.1 k( k0 c+ w/ A) u1 p+ W
// Latch the Read bit of the address cycle.$ k0 a% A. `( @
always @ (posedge clk_in or posedge clr_in)8 T! ~5 _+ ?3 W2 T- b1 C3 A# t
if (clr_in)
" U8 k3 Y: @( o( Z begin
: s" g: |% l% p/ d0 R rd_wr_out <= 0;
0 r ]' v; I$ E end
0 v7 ]! z) }3 ^ else if (addr_byte & ack_cyc)
, M, Y) l0 g3 j' ~% V begin2 K$ Q8 M4 r* c$ j9 a' Y
rd_wr_out <= in_sr[0];
" H; e( x; V' a* F/ u2 ^ end
& t& c# [9 a7 R) p; z// Decode address. My cycle if address upper 7 bits
" l u n% j0 |* O7 @2 b// match with i2c_address defined above.
+ r8 s. G2 G- K) X. \* T* Ralways @ (posedge clk_in or posedge i2c_start)# z o/ s3 ~9 Z9 g3 k
if (i2c_start)
1 m, v" ~6 C) O4 I$ G9 D, S# M begin6 H" Z8 @5 C1 X0 S; N& a
end7 I) H$ G* `! r" e. T- l! v
else if (addr_byte & ack_cyc)
% V5 r( ]5 c. K' P" b begin0 q# u' t* i5 u8 j8 H
my_cyc <= (in_sr[7:1] == i2c_address); R4 n2 }9 [4 I/ X# L5 O
end
5 @; p) f) @( C2 C1 N// I2C data output drive low signal (1 = drive SDA low)
# z: p# d: W6 Y% Z" Z# X// Invert this signal for T input of OBUFT or IOBUF
! w/ f; H7 J9 k. q! c// or use it directly for OBUFE.
3 a t& u2 K( @/ J$ u( Lalways @ (posedge clk_in or posedge clr_in)
# @: a# N+ R! }% y4 q7 Q) k z2 }3 F if (clr_in)* \/ f9 D' M) j3 o
begin K2 q) u7 \9 l7 t3 c
drive_sda <= 0;
, p+ R# w# t6 q# u0 v end
0 {! r% Z8 |# p9 J4 B. T- ~$ s else
' }, W; H9 Q& w1 e# p4 w7 Y begin
, B- U* n5 {# b; v drive_sda <= my_cyc & addr_ack // Address acknowledge4 P3 L% N; a- U- h! @' r& t# L
| my_cyc & !rd_wr_out & ack_cyc // Write byte acknowledge3 x0 B$ l4 _% `- T3 s1 ~
| data_byte & rd_wr_out & !ack_cyc & !out_sr[7] ; // Read Data( ^' @1 J2 m+ e/ a
end
* h5 [; B! ]/ |$ S0 s7 `' x0 M+ cendmodule // I2Cslave |
|