i2c passthru bridge from rpi to tuner
authorDobrica Pavlinusic <dpavlin@rot13.org>
Thu, 30 Dec 2021 16:24:49 +0000 (17:24 +0100)
committerDobrica Pavlinusic <dpavlin@rot13.org>
Thu, 30 Dec 2021 16:24:49 +0000 (17:24 +0100)
i2c.v [new file with mode: 0644]
i2c_bridge.v [new file with mode: 0644]

diff --git a/i2c.v b/i2c.v
new file mode 100644 (file)
index 0000000..079b4e3
--- /dev/null
+++ b/i2c.v
@@ -0,0 +1,58 @@
+`include "i2c_bridge.v"
+
+module top(
+       input clk,
+
+       inout rtc_sda,
+       inout rtc_scl,
+
+       inout tuner_sda,
+       inout tuner_scl,
+
+       output green_led_d7,
+       output orange_led_d8,
+       output red_led_d5,
+       output yellow_led_d6
+);
+
+       assign green_led_d7  = 1;
+       assign orange_led_d8 = 1;
+       assign red_led_d5    = 1;
+       assign yellow_led_d6 = 1;
+
+  localparam bridge_clk_div = 3; // div = 1+2^n, 24/(1+2^2)=4 MHz
+  reg [bridge_clk_div:0] bridge_cnt;
+  always @(posedge clk) // 24 MHz
+  begin
+    if(bridge_cnt[bridge_clk_div])
+      bridge_cnt <= 0;
+    else
+      bridge_cnt <= bridge_cnt + 1;
+  end
+  wire clk_bridge_en = bridge_cnt[bridge_clk_div];
+
+  wire [1:0] i2c_sda_i = {rtc_sda, tuner_sda};
+  wire [1:0] i2c_sda_t;
+  i2c_bridge i2c_sda_bridge_i
+  (
+    .clk(clk),
+    .clk_en(clk_bridge_en),
+    .i(i2c_sda_i),
+    .t(i2c_sda_t)
+  );
+  assign rtc_sda = i2c_sda_t[1] ? 1'bz : 1'b0;
+  assign tuner_sda = i2c_sda_t[0] ? 1'bz : 1'b0;
+
+  wire [1:0] i2c_scl_i = {rtc_scl, tuner_scl};
+  wire [1:0] i2c_scl_t;
+  i2c_bridge i2c_scl_bridge_i
+  (
+    .clk(clk),
+    .clk_en(clk_bridge_en),
+    .i(i2c_scl_i),
+    .t(i2c_scl_t)
+  );
+  assign rtc_scl = i2c_scl_t[1] ? 1'bz : 1'b0;
+  assign tuner_scl = i2c_scl_t[0] ? 1'bz : 1'b0;
+
+endmodule
diff --git a/i2c_bridge.v b/i2c_bridge.v
new file mode 100644 (file)
index 0000000..643bce9
--- /dev/null
@@ -0,0 +1,44 @@
+`default_nettype none
+module i2c_bridge
+(
+    input  wire       clk,    // any
+    input  wire       clk_en, // 1-clk pulse, repeats 1.5-6 MHz
+    input  wire [1:0] i,      // inputs
+    output wire [1:0] t       // tristate 0->0 1->Z
+);
+  reg [1:0] state, next_state;
+
+  always @(posedge clk)
+    case(state)
+      2'd0: begin
+        if(i[0])
+          next_state <= 3;
+        else
+          next_state <= 0;
+      end
+
+      2'd1: begin
+        if(i[1])
+          next_state <= 3;
+        else
+          next_state <= 1;
+      end
+
+      default: begin
+        if(i[0]==0 && i[1]==1)
+          next_state <= 0;
+        else if(i[1]==0 && i[0]==1)
+          next_state <= 1;
+        else
+          next_state <= 3;
+      end
+    endcase
+
+  always @(posedge clk)
+    if(clk_en)
+      state <= next_state;
+
+  assign t[1] = state == 2'd0 ? 0:1;
+  assign t[0] = state == 2'd1 ? 0:1;
+
+endmodule