AnsweredAssumed Answered

I2C slave transmitter problem

Question asked by David Rojas on Mar 2, 2012
Latest reply on Mar 6, 2012 by David Rojas
Hello. I'm trying to connect two stm32f4discovery boards through I2C. One will be the master receiver, and will ask for 4 bytes of data to the other (slave receiver). I found an example for the master receiver, and it seems is working. Everything is correctly wired and configured, here is the function in the master receiver (uses polling) that reads the data:

/*re-enable ACK bit incase it was disabled last call*/
     I2C_AcknowledgeConfig(I2C1, ENABLE);
     /* Test on BUSY Flag */
     while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
     I2C_GenerateSTART(I2C1, ENABLE);
     /* Test on start flag */
     while (!I2C_GetFlagStatus(I2C1,I2C_FLAG_SB));
     /* Send address for read */
     I2C_Send7bitAddress(I2C1, Address, I2C_Direction_Receiver);
     /* Test Receive mode Flag */
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
     /* load in all 4 registers */
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
     CapValueH = I2C_ReceiveData(I2C1);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
     CapValueL = I2C_ReceiveData(I2C1);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
     TempValueH = I2C_ReceiveData(I2C1);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
     TempValueL = I2C_ReceiveData(I2C1);
     /*enable NACK bit */
     I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current); // Indicates that the current byte is the last received byte
     I2C_AcknowledgeConfig(I2C1, DISABLE);

     /* Send STOP Condition */
     I2C_GenerateSTOP(I2C1, ENABLE);
     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF));

I've omitted some debugging stuf (led flashing to see what's happening). I've also omitted the configuration part (GPIO, clocks, i2c parameters), since it's pretty standard and no problem there.
And here, the slave transmitter, that uses interrupts. This is the interrupt EV routine:

void I2C1_EV_IRQHandler(void)
{
switch (I2C_GetLastEvent(I2C1))
{
//Slave Events
case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: // EV1
{
     //I2C_StretchClockCmd(I2C1, ENABLE);
     I2C_SendData(I2C1, 1);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_BYTE_TRANSMITTED));
     I2C_SendData(I2C1, 0);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_BYTE_TRANSMITTED));
     I2C_SendData(I2C1, 1);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_BYTE_TRANSMITTED));
     I2C_SendData(I2C1, 3);
     while (!I2C_CheckEvent(I2C1, I2C_EVENT_SLAVE_BYTE_TRANSMITTED));
     //I2C_StretchClockCmd(I2C1, DISABLE);
break;
}

case I2C_EVENT_SLAVE_BYTE_RECEIVED: //EV2
{

break;
}
case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //EV3
{

break;
}
case I2C_EVENT_SLAVE_ACK_FAILURE: // EV3-1
{

break;
}
case I2C_EVENT_SLAVE_STOP_DETECTED: // EV4
{

break;
}


default:
{

break;
}
}
}

I use again some led flashing for debug that I've omitted, and the data I send is just random numbers to test.
If I try it like this, the master performs all the correct functions, receives the data, generates the stop and finish his function. The 4 bytes received are correct, but when it finishes the slave holds down the clock, so I cannot make more requests unless I reset the slave board. Now If I remove the clock stretching commented commands in the interrupt, and also disable clock stretching when I configure the slave i2c, everything seems to work fine, I receive the data and the slave releases the clock, so I can make another request, but the data received is always 0x03 in any new request (in the 4 bytes the same value).
I've been banging my head against this for several days and tested a lot of things. Unfortunately I don't have a logic analyzer at hand now.

Outcomes