As you can see in the waveforms and the code after the start (busy line goes high) condition occurs, I start sending the slave address bit by bit in the testbench through the SDA
line, and this needs to get stored in the address
register. And in the Addr Ackn state, it checks whether the address
matches, and depending on the last bit of the address, it goes into read or write state as written in the code.
But, here for reasons unknown, the address
register isn't able to capture the address from the SDA
line accurately and hence the FSM is going to a HOLD
state.
Can anyone provide suggestions on the issue?
And this is the relevant code snippet.
module I2C_SLAVE #(parameter SLAVE_ADDR = 7'b1101010) // Slave Address for this module is 0x6A
(
input Reset_L, // (WIRE) Active Low Reset to clear the data within slave and reset the registers
input SCL, // (WIRE) Serial Clock
inout SDA // (WIRE) Serial Data
);
// STATES OF STATE MACHINE BETWEEN START AND STOP CONDITION
localparam ADDRESS = 3'b000; // Address from the master is read and checked with slave address
localparam ADDR_ACKN = 3'b001; // Acknowledgement from slave to master is sent from if address matches
localparam RECEIVE = 3'b010; // If Address last bit is 0 then data is received from master to slave (WRITE OPERATION)
localparam RX_ACKN = 3'b011; // Sends an Acknowledgement to master after the data is received
localparam TRANSMIT = 3'b100; // If Address last bit is 1 then data is transmitted from slave to master (READ OPERATION)
localparam TX_ACKN = 3'b101; // Waits for Acknowledgement from master after the data is transmitted
localparam HOLD = 3'b110; // It is the rest state which implies slave is not active
// STATE MACHINE VARIABLE
reg [2:0] state_machine;
// REGISTERS FOR INTERNAL OPERATIONS
reg busy; // Used to activate and deactivate FSM (SLAVE)
reg [7:0] address; // Used to hold the input serial data
reg [2:0] bit_index; // Used in accessing each bit of address and data register
reg [7:0] slave_data; // Data held by the slave
// CONTROL REGISTERS TO ACTIVATE OUTPUT FUNCTION OF SDA
reg SDA_EN; // Controls when the SDA should act as output
reg SDA_OUT; // Holds the serial data to be transmitted from slave
// SDA INPUT AND OUTPUT TRANSITION
assign SDA = (SDA_EN) ? SDA_OUT : 'bz; // [SDA_EN == 1] => O/P pin and [SDA_EN == 0] => I/P pin
// START CONDITION
always @(negedge SDA) // If SDA goes low when SCL is high then start condition occurs
begin
if (SCL == 1) // If busy is already high then repeated start condition occurs
begin
address <= 8'b0; // Address reg is reset to store the new address transmitted from master
bit_index <= 3'b111; // Bit Index reg is preset as the first data transmitted will be MSB
state_machine <= ADDRESS; // SM variable is set to first state where address is obtained
if (busy == 0)
busy <= 1'b1; // Busy reg is made high indicating the slave FSM is active
end
end
// FSM for state operations
always @(posedge SCL)
begin
if (~Reset_L)
begin
SDA_EN <= 1'b0;
SDA_OUT <= 1'b0;
slave_data <= 8'b0;
end
if (busy == 1)
begin
case(state_machine)
ADDRESS:
begin
if (bit_index > 0)
begin
address[bit_index] <= SDA;
bit_index <= bit_index - 1; // Bit index reg is decremented until last bit is received
end
else
state_machine <= ADDR_ACKN;
end
ADDR_ACKN:
begin
if (address[7:1] == SLAVE_ADDR) // Compares the address transmitted by master with the slave's address
begin
// SDA_OUT <= 1'b1; // If address matched, based on operation to be performed the FSM moves to next state
bit_index <= 3'b111; // Presets the bit index reg
if(address[0] == 0) // If Address Bit[0] == 0 then slave becomes data receiver
state_machine <= RECEIVE; // WRITE OPERATION
else // If Address Bit[0] == 1 then slave becomes data transmitter
state_machine <= TRANSMIT; // READ OPERATION
end
else
state_machine <= HOLD; // If address does not match slave moves to HOLD state
end