|
@@ -5,17 +5,24 @@
|
|
|
// 0 - write data/command
|
|
|
// [15:8] - data bits (must be 1 for read)
|
|
|
// [7] - ACK bit (must be 1 for write)
|
|
|
-// [2] - follow with P condition
|
|
|
-// [1] - follow with Sr condition
|
|
|
+// [2:1] - 00 = normal byte (S if needed, no following Sr/P)
|
|
|
+// 01 = follow with Sr (S if needed)
|
|
|
+// 10 = follow with P (S if needed)
|
|
|
+// 11 = dummy clocks (no S, for synchronization)
|
|
|
//
|
|
|
// 1 - read data/status
|
|
|
// [15:8] - data bits
|
|
|
// [7] - ack bit
|
|
|
-// [1] - bus idle (after P condition)
|
|
|
+// [6] - SDA
|
|
|
+// [5] - SCL
|
|
|
+// [4] - "started" (no S will be issued before next byte)
|
|
|
+// [2:1] - bits [2:1] from last command
|
|
|
// [0] - busy
|
|
|
//
|
|
|
// 2 - baud rate divisor (f = clk/(4*(divisor+1)))
|
|
|
//
|
|
|
+// 3 - bit [0] - send dummy clocks on SCL when idle
|
|
|
+//
|
|
|
// This unit handles S(r) and P conditions by considering two classes of
|
|
|
// symbols: "normal", when SCL is asserted at the end of the
|
|
|
|
|
@@ -46,7 +53,6 @@ module i2c (
|
|
|
reg busy; // Data received, running
|
|
|
reg end_s, end_p; // Trailing S(r) or P
|
|
|
reg started; // S sent, but not P
|
|
|
- reg is_sr; // Sending an S(r)
|
|
|
|
|
|
reg [1:0] outsymb; // Output symbol [abnormal, data]
|
|
|
|
|
@@ -68,6 +74,8 @@ module i2c (
|
|
|
sda_out <= 1'b1;
|
|
|
phase <= 2'b00;
|
|
|
do_read <= 1'b0;
|
|
|
+ end_s <= 1'bx;
|
|
|
+ end_p <= 1'bx;
|
|
|
started <= 1'b0;
|
|
|
end
|
|
|
else
|
|
@@ -128,9 +136,9 @@ module i2c (
|
|
|
do_read <= 1'b1;
|
|
|
if (bitctr[3])
|
|
|
begin
|
|
|
- bitctr <= end_p ? 4'd12 :
|
|
|
- end_s ? 4'd14 : 4'd0;
|
|
|
- busy <= end_p;
|
|
|
+ bitctr <= end_s ? 4'd14 :
|
|
|
+ end_p ? 4'd12 : 4'b0;
|
|
|
+ busy <= end_p & ~end_s;
|
|
|
// If we are to be followed by
|
|
|
// an S(r) condition, we are not
|
|
|
// really "started".
|
|
@@ -152,13 +160,13 @@ module i2c (
|
|
|
|
|
|
// Start condition
|
|
|
4'd14: begin
|
|
|
- started <= 1'b1;
|
|
|
+ started <= ~(end_s & end_p);
|
|
|
outsymb <= 2'b11; // A1
|
|
|
end
|
|
|
|
|
|
4'd15: begin
|
|
|
- started <= 1'b1;
|
|
|
- outsymb <= 2'b00; // N0
|
|
|
+ // N0, unless dummy in which case N1
|
|
|
+ outsymb <= { 1'b0, ~started };
|
|
|
end
|
|
|
|
|
|
default: begin
|
|
@@ -202,14 +210,16 @@ module i2c (
|
|
|
//
|
|
|
always_comb
|
|
|
case (addr)
|
|
|
- 2'b00: rdata = { 16'b0, wreg, 4'b0, end_p, end_s, busy | do_read };
|
|
|
- 2'b01: rdata = { 16'b0, rreg, 4'b0, end_p, end_s, busy | do_read };
|
|
|
+ 2'b00: rdata = { 16'b0, wreg, i2c_sda, i2c_scl, started, 1'b0,
|
|
|
+ end_p, end_s, busy | do_read };
|
|
|
+ 2'b01: rdata = { 16'b0, rreg, i2c_sda, i2c_scl, started, 1'b0,
|
|
|
+ end_p, end_s, busy | do_read };
|
|
|
2'b10: rdata = { 24'b0, divisor };
|
|
|
- default: rdata = 32'b0;
|
|
|
+ default: rdata = 32'bx;
|
|
|
endcase // casez (addr)
|
|
|
|
|
|
//
|
|
|
- // IRQ (edge) when unit idle
|
|
|
+ // IRQ (level) when unit idle
|
|
|
//
|
|
|
assign irq = ~(busy | do_read);
|
|
|
|