This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

I2C INT1A interrupt only works once

Hi all,

I've written I2C handler to use the FIFOs and INT1A; however the interrupt only works once, but works every time if I set a hardware breakpoint inside the interrupt. I've been digging into all the interrupt registers and they all look OK, but believe this must be a configuration problem.

Has anyone seen this behaviour before or can give me any pointers?

Thanks in advance,


David.

Here is the code that initiates an I2C read:

ESysError i2cReadDevice(SDevData_t *pDev)
{
   ESysError retval;
   Uint16    size;
   Uint16    cnt;
   Uint16    i2cMode;

   /* Wait until the device is ready to receive. */
   if ((i2cState == I2C_WRITE_BUSY) ||
      (i2cState == I2C_READ_BUSY))
   {
      retval = SERR_RESOURCE_BUSY;
      return (retval);
   }
   else
   {
      retval = SERR_NO_ERROR;
   }

   /* Set defaults */
   i2cMode = (I2CMDR_FREE_OPTION | I2CMDR_MST | I2CMDR_STT | I2CMDR_IRS);
   I2caRegs.I2CMDR.all = I2CMDR_IRS;
   I2caRegs.I2CSAR = pDev->i2cAddr;

   if (i2cState != I2C_CONTINUE_READ)
   {
      /* Initialise/reset the pointers used by the interrupt routine. */
      bufferIndex = 0;
      pDevice = pDev;
   }
   else
   {
      /* Intentionally left blank. */
   }

   /* Determine the transfer type and configure it. */
   if ((i2cState != I2C_CONTINUE_READ) && (pDev->devAddrSz != 0))
   {
      /* Write device address.
       * The device we are accessing requires the writing of address bytes
       * before we can initiate a read. This code assumes the address size
       * is never greater than the FIFO size.
       */
      i2cState = I2C_WRITE_BUSY;
      i2cMode |= I2CMDR_TRX;
      size = pDev->devAddrSz;

      /* Setup the number of bytes to transmit & load FIFO */
      I2caRegs.I2CCNT = size;
      for (cnt = 0; cnt < size; cnt++)
      {
         I2caRegs.I2CDXR = pDev->pAddr[cnt];
      }
   }
   else
   {
      /*
       * Straight read from device.
       */
      i2cState = I2C_READ_BUSY;

      /* We're using the FIFO ensure we don't overrun it. */
      size  = pDevice->dataSz;
      size -= bufferIndex;
      if (size > I2C_FIFO_SIZE)
      {
         size = I2C_FIFO_SIZE;
      }
      else
      {
         i2cMode |= I2CMDR_STP;  /* Generate a Stop condition. */
      }

      /*
       * Configure the I2C Module and RX FIFO for the transfer.
       */
      I2caRegs.I2CCNT = size;    /* Setup how many bytes to expect */
   }

   /* Setup the I2C Module for the transfer. */
   I2caRegs.I2CMDR.all = i2cMode;

   return (retval);
} /* i2cReadDevice() */

  • Fixed.

    Realised the problem after I had written the above; the solution is as below.
    I needed to check for the STOP bit and Busy Bit in the correct places for read and write operations.

    ESysError i2cReadDevice(SDevData_t *pDev)
    {
       ESysError retval;
       Uint16    size;
       Uint16    cnt;
       Uint16    i2cMode;

       /* Wait until the device is ready to receive. */
       if ((I2caRegs.I2CMDR.bit.STP == 1) ||
          (i2cState == I2C_WRITE_BUSY) ||
          (i2cState == I2C_READ_BUSY))
       {
          retval = SERR_RESOURCE_BUSY;
          return (retval);
       }
       else
       {
          retval = SERR_NO_ERROR;
       }

       /* Set defaults */
       i2cMode = (I2CMDR_FREE_OPTION | I2CMDR_MST | I2CMDR_STT | I2CMDR_IRS);

       if (i2cState != I2C_CONTINUE_READ)
       {
          /* Initialise/reset the pointers used by the interrupt routine. */
          bufferIndex = 0;
          pDevice = pDev;
       }
       else
       {
          /* Intentionally left blank. */
       }

       /* Determine the transfer type and configure it. */
       if ((i2cState != I2C_CONTINUE_READ) && (pDev->devAddrSz != 0))
       {
          if (I2caRegs.I2CSTR.bit.BB == 1)
          {
             retval = SERR_RESOURCE_BUSY;
             return (retval);
          }
          else
          {
          }
          /* Write device address.
           * The device we are accessing requires the writing of address bytes
           * before we can initiate a read. This code assumes the address size
           * is never greater than the FIFO size.
           */
          i2cState = I2C_WRITE_BUSY;
          i2cMode |= I2CMDR_TRX;
          size = pDev->devAddrSz;

          /* Setup the number of bytes to transmit & load FIFO */
          I2caRegs.I2CCNT = size;
          for (cnt = 0; cnt < size; cnt++)
          {
             I2caRegs.I2CDXR = pDev->pAddr[cnt];
          }
       }
       else
       {
          /*
           * Straight read from device.
           */
          i2cState = I2C_READ_BUSY;

          /* We're using the FIFO ensure we don't overrun it. */
          size  = pDevice->dataSz;
          size -= bufferIndex;
          if (size > I2C_FIFO_SIZE)
          {
             size = I2C_FIFO_SIZE;
          }
          else
          {
             i2cMode |= I2CMDR_STP;  /* Generate a Stop condition. */
          }

          /*
           * Configure the I2C Module and RX FIFO for the transfer.
           */
          I2caRegs.I2CCNT = size;    /* Setup how many bytes to expect */
       }

       /* Setup the I2C Module for the transfer. */
       I2caRegs.I2CSAR = pDev->i2cAddr;
       I2caRegs.I2CMDR.all = i2cMode;

       return (retval);
    } /* i2cReadDevice() */