Friday, June 10, 2011

Notes on I2C and SSI bus implementation

A quick note:

When you implement I2C and/or SSI you must implement timeouts and anit-lockup code.
Both busses are driven with statements like

while(some flag)  wait forever.

And you can get locked up if there is a single clock glitch.


void I2CResetLoopTimer(int i2cDeviceIdx)
{
  xI2CConfigHandle h = I2CDevices[i2cDeviceIdx];
  h->loopTimer = xTaskGetTickCount();
}


int I2CHasError(int i2cDeviceIdx)
{
  xI2CConfigHandle h = I2CDevices[i2cDeviceIdx];
  portTickType dt = xTaskGetTickCount() - h->loopTimer;
 
  return dt > 200 ||
    I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_TIMEOUT) ||
      I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_PECERR) ||
        I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_AF) ||
          I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_ARLO) ||
            I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_BERR);
}


int I2CHasErrorAndClear(int i2cDeviceIdx)
{
  if(I2CHasError(i2cDeviceIdx))
  {
    I2CClearError(i2cDeviceIdx);
    return true;
  }
  return false;
}

And an example loop.

int WhileBusy(int i2cDeviceIdx)
{
  xI2CConfigHandle h = I2CDevices[i2cDeviceIdx];
  
  I2CResetLoopTimer(i2cDeviceIdx);
  while (I2C_GetFlagStatus(h->i2cDevice, I2C_FLAG_BUSY))
  {
    if(I2CHasErrorAndClear(i2cDeviceIdx))
    {
      return false;
    }
    
    portYIELD();
  }
  return true;
}

TF

No comments: