| ////////////////////////////////////////////////////////////////////////////// |
| // SPDX-FileCopyrightText: 2021 , Dinesh Annayya |
| // |
| // 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. |
| // SPDX-License-Identifier: Apache-2.0 |
| // SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org> |
| // |
| |
| ////////////////////////////////////////////////////////////////////// |
| //// //// |
| //// OMS8051 I2C Master byte-controller Module //// |
| //// WISHBONE rev.B2 compliant I2C Master byte-controller //// |
| //// //// |
| //// This file is part of the OMS 8051 cores project //// |
| //// http://www.opencores.org/cores/oms8051mini/ //// |
| //// //// |
| //// Description //// |
| //// OMS 8051 definitions. //// |
| //// //// |
| //// To Do: //// |
| //// nothing //// |
| //// //// |
| //// Author(s): //// |
| //// -Richard Herveille , richard@asics.ws, www.asics.ws //// |
| //// -Dinesh Annayya, dinesha@opencores.org //// |
| //// //// |
| //// Revision : Jan 6, 2017 //// |
| //// //// |
| ////////////////////////////////////////////////////////////////////// |
| //// v0.0 - Dinesh A, 6th Jan 2017 |
| //// 1. Initail version picked from |
| //// http://www.opencores.org/projects/i2c/ |
| //// 2. renaming of reset signal to aresetn and sresetn |
| //// v0.1 - Dinesh.A, 19th Jan 2017 |
| //// 1. Lint Error fixes |
| ////////////////////////////////////////////////////////////////////// |
| //// //// |
| //// Copyright (C) 2000 Authors and OPENCORES.ORG //// |
| //// //// |
| //// This source file may be used and distributed without //// |
| //// restriction provided that this copyright statement is not //// |
| //// removed from the file and that any derivative work contains //// |
| //// the original copyright notice and the associated disclaimer. //// |
| //// //// |
| //// This source file is free software; you can redistribute it //// |
| //// and/or modify it under the terms of the GNU Lesser General //// |
| //// Public License as published by the Free Software Foundation; //// |
| //// either version 2.1 of the License, or (at your option) any //// |
| //// later version. //// |
| //// //// |
| //// This source is distributed in the hope that it will be //// |
| //// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
| //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
| //// PURPOSE. See the GNU Lesser General Public License for more //// |
| //// details. //// |
| //// //// |
| //// You should have received a copy of the GNU Lesser General //// |
| //// Public License along with this source; if not, download it //// |
| //// from http://www.opencores.org/lgpl.shtml //// |
| //// //// |
| ////////////////////////////////////////////////////////////////////// |
| |
| `include "i2cm_defines.v" |
| |
| module i2cm_byte_ctrl ( |
| // |
| // inputs & outputs |
| // |
| input clk, // master clock |
| input sresetn, // synchronous active high reset |
| input aresetn, // asynchronous active low reset |
| input ena, // core enable signal |
| |
| input [15:0] clk_cnt, // 4x SCL |
| |
| // control inputs |
| input start, |
| input stop, |
| input read, |
| input write, |
| input ack_in, |
| input [7:0] din, |
| |
| // status outputs |
| output reg cmd_ack, |
| output reg ack_out, |
| output i2c_busy, |
| output i2c_fsm_busy, |
| output i2c_al, |
| output [7:0] dout, |
| |
| // I2C signals |
| input scl_i, |
| output scl_o, |
| output scl_oen, |
| input sda_i, |
| output sda_o, |
| output sda_oen |
| |
| ); |
| |
| |
| |
| // |
| // Variable declarations |
| // |
| |
| // statemachine |
| parameter [4:0] ST_IDLE = 5'b0_0000; |
| parameter [4:0] ST_START = 5'b0_0001; |
| parameter [4:0] ST_READ = 5'b0_0010; |
| parameter [4:0] ST_WRITE = 5'b0_0100; |
| parameter [4:0] ST_ACK = 5'b0_1000; |
| parameter [4:0] ST_STOP = 5'b1_0000; |
| |
| // signals for bit_controller |
| reg [3:0] core_cmd; |
| reg core_txd; |
| wire core_ack, core_rxd; |
| |
| // signals for shift register |
| reg [7:0] sr; //8bit shift register |
| reg shift, ld; |
| |
| // signals for state machine |
| wire go; |
| reg [2:0] dcnt; |
| wire cnt_done; |
| |
| // |
| // Module body |
| // |
| |
| // hookup bit_controller |
| i2cm_bit_ctrl u_bit_ctrl ( |
| .clk ( clk ), |
| .sresetn ( sresetn ), |
| .aresetn ( aresetn ), |
| .ena ( ena ), |
| .clk_cnt ( clk_cnt ), |
| .cmd ( core_cmd ), |
| .cmd_ack ( core_ack ), |
| .busy ( i2c_busy ), |
| .al ( i2c_al ), |
| .din ( core_txd ), |
| .dout ( core_rxd ), |
| .scl_i ( scl_i ), |
| .scl_o ( scl_o ), |
| .scl_oen ( scl_oen ), |
| .sda_i ( sda_i ), |
| .sda_o ( sda_o ), |
| .sda_oen ( sda_oen ) |
| ); |
| |
| // Generate I2C FSM Busy |
| assign i2c_fsm_busy = (c_state !=0); |
| |
| // generate go-signal |
| assign go = (read | write | stop) & ~cmd_ack; |
| |
| // assign dout output to shift-register |
| assign dout = sr; |
| |
| // generate shift register |
| always @(posedge clk or negedge aresetn) |
| if (!aresetn) |
| sr <= 8'h0; |
| else if (!sresetn) |
| sr <= 8'h0; |
| else if (ld) |
| sr <= din; |
| else if (shift) |
| sr <= {sr[6:0], core_rxd}; |
| |
| // generate counter |
| always @(posedge clk or negedge aresetn) |
| if (!aresetn) |
| dcnt <= 3'h0; |
| else if (!sresetn) |
| dcnt <= 3'h0; |
| else if (ld) |
| dcnt <= 3'h7; |
| else if (shift) |
| dcnt <= dcnt - 3'h1; |
| |
| assign cnt_done = ~(|dcnt); |
| |
| // |
| // state machine |
| // |
| reg [4:0] c_state; // synopsys enum_state |
| |
| always @(posedge clk or negedge aresetn) |
| if (!aresetn) |
| begin |
| core_cmd <= `I2C_CMD_NOP; |
| core_txd <= 1'b0; |
| shift <= 1'b0; |
| ld <= 1'b0; |
| cmd_ack <= 1'b0; |
| c_state <= ST_IDLE; |
| ack_out <= 1'b0; |
| end |
| else if (!sresetn | i2c_al) |
| begin |
| core_cmd <= `I2C_CMD_NOP; |
| core_txd <= 1'b0; |
| shift <= 1'b0; |
| ld <= 1'b0; |
| cmd_ack <= 1'b0; |
| c_state <= ST_IDLE; |
| ack_out <= 1'b0; |
| end |
| else |
| begin |
| // initially reset all signals |
| core_txd <= sr[7]; |
| shift <= 1'b0; |
| ld <= 1'b0; |
| cmd_ack <= 1'b0; |
| |
| case (c_state) // synopsys full_case parallel_case |
| ST_IDLE: |
| if (go) |
| begin |
| if (start) |
| begin |
| c_state <= ST_START; |
| core_cmd <= `I2C_CMD_START; |
| end |
| else if (read) |
| begin |
| c_state <= ST_READ; |
| core_cmd <= `I2C_CMD_READ; |
| end |
| else if (write) |
| begin |
| c_state <= ST_WRITE; |
| core_cmd <= `I2C_CMD_WRITE; |
| end |
| else // stop |
| begin |
| c_state <= ST_STOP; |
| core_cmd <= `I2C_CMD_STOP; |
| end |
| |
| ld <= 1'b1; |
| end |
| |
| ST_START: |
| if (core_ack) |
| begin |
| if (read) |
| begin |
| c_state <= ST_READ; |
| core_cmd <= `I2C_CMD_READ; |
| end |
| else |
| begin |
| c_state <= ST_WRITE; |
| core_cmd <= `I2C_CMD_WRITE; |
| end |
| |
| ld <= 1'b1; |
| end |
| |
| ST_WRITE: |
| if (core_ack) |
| if (cnt_done) |
| begin |
| c_state <= ST_ACK; |
| core_cmd <= `I2C_CMD_READ; |
| end |
| else |
| begin |
| c_state <= ST_WRITE; // stay in same state |
| core_cmd <= `I2C_CMD_WRITE; // write next bit |
| shift <= 1'b1; |
| end |
| |
| ST_READ: |
| if (core_ack) |
| begin |
| if (cnt_done) |
| begin |
| c_state <= ST_ACK; |
| core_cmd <= `I2C_CMD_WRITE; |
| end |
| else |
| begin |
| c_state <= ST_READ; // stay in same state |
| core_cmd <= `I2C_CMD_READ; // read next bit |
| end |
| |
| shift <= 1'b1; |
| core_txd <= ack_in; |
| end |
| |
| ST_ACK: |
| if (core_ack) |
| begin |
| if (stop) |
| begin |
| c_state <= ST_STOP; |
| core_cmd <= `I2C_CMD_STOP; |
| end |
| else |
| begin |
| c_state <= ST_IDLE; |
| core_cmd <= `I2C_CMD_NOP; |
| |
| // generate command acknowledge signal |
| cmd_ack <= 1'b1; |
| end |
| |
| // assign ack_out output to bit_controller_rxd (contains last received bit) |
| ack_out <= core_rxd; |
| |
| core_txd <= 1'b1; |
| end |
| else |
| core_txd <= ack_in; |
| |
| ST_STOP: |
| if (core_ack) |
| begin |
| c_state <= ST_IDLE; |
| core_cmd <= `I2C_CMD_NOP; |
| |
| // generate command acknowledge signal |
| cmd_ack <= 1'b1; |
| end |
| default: c_state <= ST_IDLE; |
| |
| endcase |
| end |
| endmodule |