Adrian Verity

I2C issue in i2cm_8xx

Discussion created by Adrian Verity on Sep 8, 2016
Latest reply on Sep 20, 2016 by Adrian Verity

Hello All,

 

Just to share my findings, there are a couple of issues with the LPCOpen I2CM_8xx example code.

 

1. In the SetupXferRecAndExecute function, the i2c is setup and then there is a wiat for transfer to complete followed by the disabling of the Interrupts.  This only works if the interrupts get turned off before within about 15us of the last none-idle interrupt.  (This is the case if there isn't much else going on, but if you have other ISR for other things then if they run just after the i2c final ISR this may well occur).  If the Interrrupt is not turned off in time, the ISR continuously executes and the main code will never get chance to run.  The Data sheet says for the MSTPENDING flag "If the master is in the idle state, and no communication is needed, mask this interrupt."  The masking of this interrupt must therefore be done in the ISR itself to ensure it gets turned off..

 

void I2C_IRQHandler(void)
{
    /* Call I2CM ISR function with the I2C device and transfer rec */
    if (Chip_I2CM_XferHandler(LPC_I2C, &i2cmXferRec) != 0)
    {
        if(Chip_I2CM_GetMasterState(LPC_I2C) == I2C_STAT_MSTCODE_IDLE)
        {
            /* Clear all Interrupts */
            Chip_I2C_ClearInt(LPC_I2C, I2C_INTENSET_MSTPENDING | I2C_INTENSET_MSTRARBLOSS | I2C_INTENSET_MSTSTSTPERR);
        }
    }
}

 

I imagine this is the way the interrupt should be disabled for the ROM version, and that this is probably applicable to other device families too.

 

2.  If optomisation is turned on (for size -Os), the WaitForI2cXferComplete loop check for busy is optomised out, and it becomes a while(1); forever loop.  In order to fix this the xferRecPtr->status should be made volatile (to tell the compiler this variable may change external to the loop) but this means changing the LPCOpen code. 

 

The WaitForI2cXferComplete function can also me modified (i.e. so the LPCOpen code doesn't need changing):

 

/* Function to wait for I2CM transfer completion */
static void WaitForI2cXferComplete(I2CM_XFER_T *xferRecPtr)
{
    volatile uint16_t *status;
    status = (volatile uint16_t *)&xferRecPtr->status;
    /* Test for still transferring data */
    while (*status == I2CM_STATUS_BUSY)
    {
        /* Sleep until next interrupt */
        __WFI();
    }
}

 

I hope someone else finds these useful, or even NXP implment these findings....

 

Sincerely,

Adrian

Outcomes