2
\$\begingroup\$

enter image description here

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
toolic
10.8k11 gold badges31 silver badges35 bronze badges
asked Aug 20, 2023 at 9:21
\$\endgroup\$
1
  • \$\begingroup\$ We have no idea what hardware -or software- OP is talking about. And I somehow missed the verilog tag. Whoops. Note that in classic I²C both I/Os should be used in open drain mode. \$\endgroup\$ Commented Aug 20, 2023 at 9:49

1 Answer 1

2
\$\begingroup\$

You set the slave address to 7'b1101010 (7'h6a) in the design, but your design received 8'b01010100 in address[7:0] according to your waveforms. This means address[7:1] is 7'b0101010, which is 7'h2a. The received address7'h2a does not match the expected address 7'h6a in the design. This is why the state machine goes to the HOLD state unexpectedly.

The problem is that you have a simulation race condition because SDA and SCL change at the same time. You should change the testbench so that they are changing at different times. Refer to an I2C timing diagram. Here is one way to code the testbench to demonstrate the signals changing at different times:

module tb;
reg sda_tb, scl_tb;
parameter PERIOD = 20;
initial begin
 sda_tb = 1;
 #(PERIOD/4) sda_tb = 0;
 set_address(7'h6a);
 #(PERIOD) $finish;
end
initial begin
 scl_tb = 1;
 forever #(PERIOD/2) scl_tb = ~scl_tb;
end
task set_address (input [6:0] addr);
 integer i;
 for (i=6; i>=0; i=i-1) begin
 #(PERIOD) sda_tb <= addr[i];
 end
endtask
endmodule

waves

answered Aug 21, 2023 at 16:04
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.