blob: ff85e948c5e6b9597da23765b8a91dee893b310b [file] [log] [blame]
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
//
// 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
//
// https://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.
`timescale 1ns/1ns
module i2c_ctrl2202(
input i_start,
input i_cclk,
input i_read,
input i_stop,
input i_sda,
input [7:1] i_address,
input [8:1] i_txdata,
output [8:1] i_rxdata,
output o_scl,
output reg o_busy,
output reg o_sda
);
reg a_ack;
reg d_ack;
reg stop_bit;
reg [2:0] a_cycle;
reg [3:0] x_cycle;
reg [8:1] r_txdata;
reg [8:1] r_rxdata;
reg [7:1] r_i_address;
reg [2:0] state;
parameter IDLE = 3'b000,
ADDR = 3'b001,
MODR = 3'b010,
AACK = 3'b011,
READ = 3'b100,
WRTE = 3'b101,
FINL = 3'b110;
initial begin
o_sda <= 1'b0;
o_busy <= 1'b0;
a_ack <= 1'b0;
d_ack <= 'b0;
stop_bit <= 'b0;
a_cycle <= 3'b111;
x_cycle <= 'd8;
r_txdata <= 8'd0;
r_rxdata <= 8'd0;
r_i_address <= 7'b0;
state <= 3'b0;
end
// State Machine
//==============
always @(posedge i_cclk)
case(state)
// IDLE: Idle
3'b000:
begin
if(!i_start & !i_stop) begin
o_sda <= 1'b0;
state <= ADDR;
a_cycle <= 3'b111;
r_i_address <= i_address;
o_busy <= 1'b0;
end
else begin
o_sda <= 1'b1;
state <= IDLE;
o_busy <= 1'b0;
end
end
// ADDR: Addressing
3'b001:
begin
if(a_cycle >= 3'b001) begin
o_sda <= r_i_address[a_cycle];
a_cycle <= a_cycle - 1'b1;
state <= ADDR;
o_busy <= 1'b1;
end
else begin
state <= MODR;
o_busy <= 1'b0;
end
end
// MODR: Select between Read and Write
3'b010:
begin
state <= AACK;
o_sda <= i_read;
end
// AACK: Address Acknowledgement
3'b011:
begin
if(i_sda) begin
a_cycle <= 3'b111;
state <= ADDR;
o_busy <= 1'b0;
o_sda <= 1'b1;
end
else if(!i_sda) begin
if(!i_read) begin
state <= WRTE;
x_cycle <= 4'd8;
o_sda <= 1'b0;
o_busy <= 1'b0;
r_txdata <= i_txdata;
end
else begin
state <= READ;
x_cycle <= 4'd8;
o_sda <= 1'b0;
o_busy <= 1'b0;
end
end
end
// READ: Read Operation
3'b100:
begin
if(x_cycle >= 1) begin
r_rxdata[x_cycle] <= i_sda;
x_cycle <= x_cycle - 1'b1;
o_busy <= 1'b1;
state <= READ;
end
else begin
state <= FINL;
o_busy <= 1'b0;
x_cycle <= 4'd8;
end
end
// WRTE: Write Operation
3'b101:
begin
if(x_cycle > 0) begin
o_sda <= i_txdata[x_cycle];
x_cycle <= x_cycle - 1'b1;
o_busy <= 1'b1;
state <= WRTE;
end
else begin
state <= FINL;
o_busy <= 1'b0;
x_cycle <= 4'd8;
end
end
// FINL: Data Acknowledgement and Stop
3'b110:
begin
if(i_sda) begin
state <= MODR;
end
else begin
o_sda <= 1'b1;
state <= IDLE;
end
end
default: state <= IDLE;
endcase
// Controller clock
assign o_scl = i_cclk;
assign i_rxdata = r_rxdata;
endmodule