How can I read variable length message w/ I2C?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How can I read variable length message w/ I2C?

722 Views
kevinlfw
Contributor III

I'm using a K22, which is acting as a slave, on a single master bus, and the K22 is the only slave device on the bus.  I'm using IAR EWARM w/ KSDK v1.3 and MQX.  I'm using the non-blocking I2C Send/Receive methods.

 

The requirement I have is that my K22 should be able to talk to 2 different devices, and should have knowledge of what device its talking to.  To do that, the first step is reading the system information from the devices and taking appropriate action based on which device was detected.  Here is the catch: ProductA's system information message is 5 bytes long, ProductB's system information message is 12 bytes long.

 

So what I do is, attempt to read 12 bytes and implement my own timeout of 2 seconds.  If I get 12 bytes back, great, we know its ProductB.  However, if the receive happens to timeout after 2 seconds, then I check to see if 5 bytes were read (7 bytes remaining left to be read), and if so, we know its ProductA.

 

Here's pseudocode to give a rough idea of what I'm doing:

bool ReadSysInfo(uint8_t rxBuff, uint32_t * numBytesRemaining)
{
    bool result = true;
    I2C_Slave_SendData(txBuff) //Send data to the master, who then parses this data and responds with the system status information
    timeout = OSA_TimeGetMsec() + I2C_RX_TX_TIMEOUT;
    I2C_Slave_ReceiveData(rxBuffer, 12) //Receive 12 bytes
    do
    {
        currentTime = OSA_TimeGetMsec();;
        status = I2C_DRV_SlaveGetReceiveStatus(I2C_RTOS_SLAVE_INSTANCE, numBytesRemaining);  
    } while(status != kStatus_I2C_Success && timeout > currTimeMs);

    if(timeout <= currTimeMs)
    {
        result = false;
    }

    return result;
}

uint8_t rxBuff[12];
uint32_t nbr = 0; //number of remaining bytes left to be read
ProductType product;
bool result = ReadSysInfo(rxBuff, &nbr);
if(result)
{
    product = ProductB;
}
else if(nbr == 7) //If we still have 7 bytes left to receive, then that means we read 5 bytes, which is the number of bytes ProductA will respond with
{
    product = ProductA;
}

 

The issue is that, if I follow this method, and I'm talking to ProductA type, because I don't receive 12 bytes (and I only receive 5), the busy flag is held high and all following I2C communications fail because the I2C lines are pulled low.  If I change the call to read 5 bytes instead of 12, the busy bit is cleared after the STOP signal is received and everything works as expected.

 

My question is how should I properly handle this kind of issue?  Is there something in the SDK I can call that will force the I2C module to stop pulling the line low?  Any suggestion is appreciated.

Labels (1)
Tags (4)
0 Kudos
1 Reply

481 Views
kevinlfw
Contributor III

So far the best solution I've found is de-initializing the slave and then initializing it again.  This seems kind of wonky, but I'll be more than happy to try other solutions.

0 Kudos