summaryrefslogtreecommitdiffhomepage
path: root/source/i2c.v
diff options
context:
space:
mode:
authorPrivate Island Networks <opensource@privateisland.tech>2025-09-01 12:34:17 -0400
committerPrivate Island Networks <opensource@privateisland.tech>2025-09-01 12:34:17 -0400
commitc8b273c80abe98e53828f46079a187975938a56a (patch)
tree410577af8067ee001ba473dcf0c7bcae46d83de1 /source/i2c.v
parentac2bbbd2f816c223ef4dcfa2f8440d9c0c73bffe (diff)
rename source to src
Diffstat (limited to 'source/i2c.v')
-rw-r--r--source/i2c.v391
1 files changed, 0 insertions, 391 deletions
diff --git a/source/i2c.v b/source/i2c.v
deleted file mode 100644
index aca6452..0000000
--- a/source/i2c.v
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * i2c.v
- *
- * Copyright (C) 2018, 2019 Mind Chasers Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * function: I2C slave controller for communicating with internal controller
- *
- */
-
-
-`timescale 1ns /10ps
-
-
-module i2c(
- input rstn,
- input clk,
-
- // external I2C I/O
- input scl_i, // serial clock
- output scl_o, // serial clock out
- output scl_oe, // serial clock output enable
-
- input sda_i, // serial data in
- output reg sda_o, // serial data out
- output reg sda_oe, // serial data output enable
-
- // shared memory and controller data output
- output [7:0] mem_do,
-
- // dedicated memory interface
- output [10:0] mem_ad,
- output mem_ce,
- output reg mem_we,
- input [7:0] mem_di,
-
- // dedicated controller write interface
- output reg cont_we,
- output cont_done,
-
- // Controller->FIFO input interface
- input tx_fifo_empty, // use for control and pass as msbit of data
- input [6:0] fifo_di, // data from FIFO to transmit on I2C
- output reg fifo_re
-
-);
-
-localparam CONT_SEL = 7'h10,
- DPRAM_SEL = 7'h20,
- SCI_SEL = 7'h30;
-
-// slave-related signals
-
-reg scl_high, scl_low;
-reg [4:0] bit_cnt; // cnt the bits received
-reg start; // falling SDA while SCL is high
-reg stop; // rising SDA while SCL is high
-reg run; // assert while running and counting bits
-reg rwn; // follows address
-
-reg [6:0] dev_ad; // 7-bit device address
-reg [7:0] addr; // address
-reg [7:0] d; // data received from external i2c controller during an I2C write
-wire target_sel, dpram_sel, cont_sel;
-reg scl_i_m1, scl_i_m2, sda_i_m1; // delayed versions of the inputs
-reg ack;
-
-wire [7:0] i_di; // internal data in muxed from external sources (e.g., DPRAM and controller)
-
-assign i_di = dpram_sel ? mem_di : { tx_fifo_empty, fifo_di };
-
-// master-related signals
-//reg halt; // assert if we lose arbitration, detect a zero in place of a one
-
-assign scl_oe = 1'b0;
-
-// since it's open drain, never drive the outputs high
-assign scl_o = 1'b0;
-
-// slave interface
-
-/*
- debounce and capture the asynch inputs
- delayed signals, by default, they're 1 since they're open drain
-*/
-always @(posedge clk or negedge rstn)
- begin
- if (!rstn)
- begin
- scl_i_m1 <= 1'b1;
- scl_i_m2 <= 1'b1;
- sda_i_m1 <= 1'b1;
- end
- else
- begin
- scl_i_m1 <= scl_i;
- scl_i_m2 <= scl_i_m1;
- sda_i_m1 <= sda_i;
- end
- end
-
-/*
- create a one shot when scl is first stable high
- use this to register inputs
-*/
-always@(posedge clk or negedge rstn)
- begin
- if (!rstn)
- scl_high <= 1'b0;
- else if (scl_i && scl_i_m1 && ~scl_i_m2)
- scl_high <= 1'b1;
- else
- scl_high <= 1'b0;
- end
-
-/*
- create a one shot when scl is first stable low
- use this to register outputs
-*/
-always@(posedge clk or negedge rstn)
- begin
- if (!rstn)
- scl_low <= 1'b0;
- else if ( !scl_i && !scl_i_m1 && scl_i_m2)
- scl_low <= 1'b1;
- else
- scl_low <= 1'b0;
- end
-
-/*
- one shot start/restart bit, sda 1 to 0 anytime while scl is high
-*/
-always @(posedge clk or negedge rstn)
- begin
- if (!rstn)
- start <= 1'b0;
- else if ( scl_i == 1'b1 && scl_i_m1 == 1'b1 && sda_i == 1'b0 && sda_i_m1 == 1'b1 )
- start <= 1'b1;
- else
- start <= 1'b0;
- end
-
-/*
- one shot stop bit, sda 0 to 1 anytime while scl is high
-*/
-assign cont_done = stop & ~rwn;
-
-always @(posedge clk or negedge rstn)
- begin
- if (!rstn )
- stop <= 1'b0;
- else if ( scl_i == 1'b1 && scl_i_m1 == 1'b1 && sda_i == 1'b1 && sda_i_m1 == 1'b0 )
- stop <= 1'b1;
- else
- stop <= 1'b0;
- end
-
-/*
- This I2C block runs between start and stop while run == 1
-*/
-always @(posedge clk or negedge rstn)
- begin
- if (!rstn)
- run <= 1'b0;
- else if ( start )
- run <= 1'b1;
- else if ( stop )
- run <= 1'b0;
- end
-
-
-/*
- bit_cnt indicates the state of the i2c transfer:
- start/stop act as synchronous resets
- otherwise, bit_cnt can change when scl is low
-
- 31 (1F): reserved for first cycle after start / idle state
- 0:6: dev_ad
- 7: rwn, ACK is clocked out
- 8:
- 9:16: if rwn == 0 addr, else d, ACK is clocked out on 16
- 17: ( restart to 9 if read )
- 18:25: write data, ack write data is clocked out on 25
- 26: ( restart to 18 for write data )
-*/
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- bit_cnt <= 5'h1f;
- else if ( start || stop )
- bit_cnt <= 5'h1f;
- else if ( run && scl_low )
- begin
- if ( rwn && bit_cnt == 5'd17 )
- bit_cnt <= 5'd9;
- else if ( bit_cnt == 5'd26 )
- bit_cnt <= 5'd18;
- else
- bit_cnt <= bit_cnt + 1;
- end
- end
-
-/*
- shift device address (dev_ad) into the module from the i2c bus
-*/
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- dev_ad <= 7'h0;
- else if ( stop )
- dev_ad <= 7'h0;
- else if ( run && scl_high && bit_cnt <= 5'h6 )
- dev_ad <= { dev_ad[5:0], sda_i };
- end
-
-
-/*
- shift I2C memory addr into the module from the i2c bus during first cycle
- auto increment on subsequent byte reads during same I2C cycle
-*/
-always @(posedge clk or negedge rstn)
- begin
- if (!rstn)
- addr <= 8'h00;
- else if ( run && scl_high)
- begin
- if ( !rwn && bit_cnt >= 5'd9 && bit_cnt <= 5'd16 )
- addr <= { addr[6:0], sda_i };
- else if ( (rwn && bit_cnt == 5'd17) || (!rwn && bit_cnt == 5'd26) )
- addr <= addr + 1;
- end
- end
-
-
-/*
-* shift write data (d) into the module from the i2c bus.
-*/
-always @(posedge clk or negedge rstn)
- begin
- if (!rstn)
- d <= 8'ha5;
- else if ( run && scl_high && !rwn && !start && bit_cnt >= 5'd18 && bit_cnt < 5'd26 )
- d <= { d[6:0], sda_i };
- end
-
-
-
-assign dpram_sel = ( dev_ad == DPRAM_SEL ) ? 1 : 0;
-assign cont_sel = ( dev_ad == CONT_SEL ) ? 1 : 0;
-assign target_sel = cont_sel | dpram_sel;
-
-/*
- register ack during I2C reads when bit_cnt == 17
-*/
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- ack <= 1'b0;
- else if ( run && scl_high && rwn && bit_cnt == 5'd17 )
- ack <= ~sda_i;
- end
-
-/*
- register rwn bit
-*/
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- rwn <= 1'b1;
- else if ( stop )
- rwn <= 1'b1;
- else if ( run && scl_high && bit_cnt == 5'd7 )
- rwn <= sda_i;
- end
-
-/*
- sda_oe logic, note that the bit_cnt will be changing simultaneously, so it's one behind
-*/
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- begin
- sda_oe <= 1'b0;
- sda_o <= 1'b1;
- end
- else if ( stop )
- begin
- sda_oe <= 1'b0;
- sda_o <= 1'b1;
- end
- else if ( scl_low )
- begin
- // ack the first byte written by master if it's addressed to our I2C slave
- if ( target_sel && bit_cnt == 5'd7 )
- begin
- sda_oe <= 1'b1;
- sda_o <= 1'b0;
- end
- // ack write address
- else if ( target_sel && rwn == 1'b0 && bit_cnt == 5'd16 )
- begin
- sda_oe <= 1'b1;
- sda_o <= 1'b0;
- end
- // ack write data
- else if ( target_sel && rwn == 1'b0 && bit_cnt == 5'd25 )
- begin
- sda_oe <= 1'b1;
- sda_o <= 1'b0;
- end
- // drive read data
- else if ( target_sel && rwn == 1'b1 && bit_cnt >= 5'd8 && bit_cnt <=5'd15 ) // xmt data for read cycle
- begin
- sda_oe <= 1'b1;
- sda_o <= i_di[7-bit_cnt[2:0]];
- end
- // drive data for first bit of burst read cycle, multi-byte if we get an ack
- // if no ack, then the burst read or single read is done
- else if ( target_sel && rwn == 1'b1 && ack && bit_cnt == 5'd17 )
- begin
- sda_oe <= 1'b1;
- sda_o <= i_di[7];
- end
- else
- begin
- sda_oe <= 1'b0;
- sda_o <= 1'b1; // don't care
- end
- end
- end
-
-/* DPRAM Control */
-assign mem_ad = {3'b0, addr};
-assign mem_ce = 1'b1;
-
-/*
- driver: mem_do
- shared between both cont and dpram interfaces
- drive addr for first byte since this is the controller cmd
-*/
-assign mem_do = ( bit_cnt <= 5'd17 ) ? addr : d;
-
-// mem_we bit
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- mem_we <= 1'b0;
- else if ( run && scl_high && dpram_sel && !rwn && bit_cnt == 5'd26 )
- mem_we <= 1'b1;
- else
- mem_we <= 1'b0;
- end
-
-// cont_we bit is asserted at the end of both command and data bytes
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- cont_we <= 1'b0;
- else if ( run && scl_high && cont_sel && !rwn && (bit_cnt == 5'd26 || bit_cnt == 5'd17) )
- cont_we <= 1'b1;
- else
- cont_we <= 1'b0;
- end
-
-/*
-* drive: fifo_re
-* Stop asserting during a burst if we don't get an ACK (use sda_i for real-time ACK)
-*/
-always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- fifo_re <= 1'b0;
- else if ( run && scl_high && cont_sel && rwn && !tx_fifo_empty && ( bit_cnt == 5'd8 || ( bit_cnt == 5'd17 && !sda_i ) ) )
- fifo_re <= 1'b1;
- else
- fifo_re <= 1'b0;
- end
-
-
-endmodule

Highly Recommended Verilog Books