Norm May

51JM128 Freescale I2C two interrupt problems

Discussion created by Norm May on Apr 8, 2013

I've found two issues with our interrupt driven I2C communication to an accelerometer on a DEMOJM board.  The problems appear to be in the Freescale processor bean for the I2C interface.  I have made code changes to the generated code which gets my project running, but would like to hear confirmation that these are sound changes and possibly get Freescale to fix their code if it is a general purpose problem.


I had the I2C interface to the accelerometer working with the polling method.  It broke when I started using the interrupt driven methods.


1) After the first transfer to the I2C device, the bus becomes busy (IIC1S_BUSY is asserted.)  When this is true, the SendBlock, RecvBlock, and SendChar just return with ERR_BUSOFF.  The Coldfire documentation indicates this will be true when the I2C bus sees a start but not a stop condition.  The logic analyzer viewing the transaction indicates the transfer was good with a valid start and stop.  So the processor for some reason is not seeing the stop condition.  I tried to clear the bus while the processor was suspended by the debugger and togging various CPU registers (enable/disable I2C, generating a stop condition...) but was unable to clear the bus.  However, when I removed the test for the IIC1S_BUSY bit, then the next transactions could be done.  So it appears that the bus really wasn't busy since further transactions worked.  Here is the SendBlock routine with the BUSY test commented out.


byte AccelCom_SendBlock(const void * Ptr,word Siz,word *Snt)


  if (!Siz) {                          /* Test variable Size on zero */

    *Snt = 0U;

    return ERR_OK;                     /* If zero then OK */


  //if((IIC1S_BUSY) || (InpLenM) || (AccelCom_SerFlag & (CHAR_IN_TX|WAIT_RX_CHAR|IN_PROGRES))) { /* Is the bus busy */

  if((InpLenM) || (AccelCom_SerFlag & (CHAR_IN_TX|WAIT_RX_CHAR|IN_PROGRES))) { /* Is the bus busy */

    return ERR_BUSOFF;                 /* If yes then error */


  EnterCritical();                     /* Enter the critical section */

  AccelCom_SerFlag |= IN_PROGRES;      /* Set flag "busy" */

  OutLenM = Siz;                       /* Set lenght of data */

  OutPtrM = (byte *)Ptr;               /* Save pointer to data for transmitting */

  IIC1C1_TX = 1U;                      /* Set TX mode */



  if(IIC1C1_MST) {                     /* Is device in master mode? */

    IIC1C1_RSTA = 1U;                  /* If yes then repeat start cycle generated */


  else {

    IIC1C1_MST = 1U;                   /* If no then start signal generated */


  IIC1D = 0x3AU;                       /* Send slave address */

  ExitCritical();                      /* Exit the critical section */

  *Snt = Siz;                          /* Dummy number of really sent chars */

  return ERR_OK;                       /* OK */



2) The second problem found might be related to #1.  The 2nd transfer was never completed unless there was a delay after IIC1C1_TX = 1U; /* Set TX mode */ and before the test if(IIC1C1_MST) { /* Is device in master mode? */.  Or more correctly, the delay was needed after setting TX mode and in my case, setting the start signal generated.  (IIC1C1_MST = 1U;)


The code change is the addition of the Cpu_Delay100US() from the CPU processor expert.


Without the delay, on the last byte of the 2nd transfer, the ISR does not detect that the device is in master mode.  So the OnTransmitData() function is never called to trigger the continuation of the next byte to send.  With the delay, the ISR does detect that the device is in master mode, it calls the OnTransmitData() and the flow of data continues.


I've seen some other mentions in these forums about similar problems.  I read a posting where the BUSY bit was removed from the test.  I've never seen delays suggested to fix the other problem though.  While it might work, I don't have any rational for if this is a good fix and what the processor is doing.  Comments are welcome.



Original Attachment has been moved to: