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.

MSPM0G3507: I2C controller mode handling NACK

Part Number: MSPM0G3507


Hi,

After updating form the mspm0_sdk_1_20_00_05 to the mspm0_sdk_1_30_00_03 I started to have some problems with my I2C Bus.

The Bus has a i2c eeprom, a display driver and a i2c button controller peripheral. The button controller has a defined behavior where it will always return a NACK upon first communication as it wakes up from sleep mode. It can return to sleep mode if no communications happen within a defined time frame.

What i found is that at the startup, where I am writing/reading the eeprom, communicating with display and perform the initial configuration of the bus controller, the NACK coming from the Button controller is somehow corrupting the eeprom data. i can confirm this by probing the bus, which starts to transfer non-sense data and message sizes. If no button controller communication is performed, the system works ok with eeprom and display simultaneously.

I looked for implementation suggestion related with the NACK interrupt handling but no relevant information was found.

my initialization configuration is as follows:

        uint16_t uiI2CClk;
        uint16_t uiI2CFreq;
        uint8_t ucI2CPeriod;
        int16_t siI2CPeriod;

        DL_I2C_ClockConfig strI2CClockConfig;

        DL_I2C_reset(ptraI2CBus[enumI2CBus_p]);
        DL_I2C_enablePower(ptraI2CBus[enumI2CBus_p]);

        delay_cycles(16);

        straI2CData[enumI2CBus_p].enumI2CMode = enumI2CMode_p;
        straI2CData[enumI2CBus_p].ulMyI2CAddress = ulMyAddress_p;

        strI2CClockConfig.clockSel = DL_I2C_CLOCK_BUSCLK;
        strI2CClockConfig.divideRatio = DL_I2C_CLOCK_DIVIDE_1;

        DL_I2C_setClockConfig(ptraI2CBus[enumI2CBus_p], &strI2CClockConfig);

        DL_I2C_setAnalogGlitchFilterPulseWidth(ptraI2CBus[enumI2CBus_p], DL_I2C_ANALOG_GLITCH_FILTER_WIDTH_50NS);
        DL_I2C_enableAnalogGlitchFilter(ptraI2CBus[enumI2CBus_p]);

        if (enumI2CMode_p == I2C_CONTROLLER_e)
        {
            uiI2CClk = (uint16_t)(DEV_getSystemClock()/10000);
            uiI2CFreq = (uint32_t)enumSpeed_p;
            uiI2CFreq *= 10;

            siI2CPeriod = (uint8_t)((uiI2CClk / uiI2CFreq) - 1);

            if (siI2CPeriod <= 0)
            {
                ucI2CPeriod = 1; // limit to the maximum possible speed
            }
            else
            {
                ucI2CPeriod = (uint8_t)siI2CPeriod;
            }

            DL_I2C_resetControllerTransfer(ptraI2CBus[enumI2CBus_p]);
            DL_I2C_setTimerPeriod(ptraI2CBus[enumI2CBus_p], ucI2CPeriod);
            DL_I2C_setControllerTXFIFOThreshold(ptraI2CBus[enumI2CBus_p], DL_I2C_TX_FIFO_LEVEL_EMPTY);
            DL_I2C_setControllerRXFIFOThreshold(ptraI2CBus[enumI2CBus_p], DL_I2C_RX_FIFO_LEVEL_BYTES_1);
            DL_I2C_enableInterrupt(ptraI2CBus[enumI2CBus_p],
                DL_I2C_INTERRUPT_CONTROLLER_ARBITRATION_LOST |
                DL_I2C_INTERRUPT_CONTROLLER_NACK |
                DL_I2C_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER |
                DL_I2C_INTERRUPT_CONTROLLER_RX_DONE |
                DL_I2C_INTERRUPT_CONTROLLER_TX_DONE);
            DL_I2C_enableControllerClockStretching(ptraI2CBus[enumI2CBus_p]);

            DL_I2C_enableControllerReadOnTXEmpty(ptraI2CBus[enumI2CBus_p]);

            DL_I2C_enableController(ptraI2CBus[enumI2CBus_p]);
        }

the write method is defined as:

    uint8_t I2C_sendDataToMemory(EI2CBus enumI2CBus_p, uint8_t ucTargetAddress_p, uint16_t uiMemoryAddress_p, uint8_t ucMemorySize_p, uint8_t* pucTxData_p, uint16_t uiDataSize_p)
    {
        straI2CData[enumI2CBus_p].ucTargetAddress = ucTargetAddress_p;
        straI2CData[enumI2CBus_p].pucTxData = pucTxData_p;
        straI2CData[enumI2CBus_p].uiSizeOfDataToSend =  uiDataSize_p + (uint16_t)ucMemorySize_p;
        straI2CData[enumI2CBus_p].ucMemoryAddressSize = ucMemorySize_p;

        if (ucMemorySize_p == 1)
        {
            straI2CData[enumI2CBus_p].uiaMemoryAddress[0] = (uint8_t)(uiMemoryAddress_p & 0x00FF);
        }
        else
        {
            straI2CData[enumI2CBus_p].uiaMemoryAddress[1] = (uint8_t)(uiMemoryAddress_p & 0x00FF);
            straI2CData[enumI2CBus_p].uiaMemoryAddress[0] = (uint8_t)(uiMemoryAddress_p >> 8);
        }

        /*
         * Fill the FIFO with the address
         * The FIFO is 8-bytes deep, and this function will return number
         * of bytes written to FIFO */
        straI2CData[enumI2CBus_p].ucTransmitionStart = TRUE;
        straI2CData[enumI2CBus_p].ucDummyWrite = FALSE;

        if (ucMemorySize_p == 0)
        {
            straI2CData[enumI2CBus_p].uiDataSentCounter = DL_I2C_fillControllerTXFIFO(ptraI2CBus[enumI2CBus_p],
                                                            straI2CData[enumI2CBus_p].pucTxData,
                                                            straI2CData[enumI2CBus_p].uiSizeOfDataToSend);
        }
        else
        {
            straI2CData[enumI2CBus_p].uiDataSentCounter = DL_I2C_fillControllerTXFIFO(ptraI2CBus[enumI2CBus_p],
                                                              straI2CData[enumI2CBus_p].uiaMemoryAddress,
                                                              straI2CData[enumI2CBus_p].ucMemoryAddressSize);

            straI2CData[enumI2CBus_p].uiDataSentCounter +=
                    DL_I2C_fillControllerTXFIFO(ptraI2CBus[enumI2CBus_p],
                                                straI2CData[enumI2CBus_p].pucTxData,
                                                straI2CData[enumI2CBus_p].uiSizeOfDataToSend - straI2CData[enumI2CBus_p].uiDataSentCounter);
        }

        DL_I2C_enableInterrupt(ptraI2CBus[enumI2CBus_p], DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);

        /*
         * Send the packet to the controller.
         * This function will send Start + Stop automatically.
         */
        while (!(DL_I2C_getControllerStatus(ptraI2CBus[enumI2CBus_p]) & DL_I2C_CONTROLLER_STATUS_IDLE))
        {
            /* wait */
        }

        DL_I2C_startControllerTransfer(ptraI2CBus[enumI2CBus_p],
                                       (uint32_t)straI2CData[enumI2CBus_p].ucTargetAddress,
                                       DL_I2C_CONTROLLER_DIRECTION_TX,
                                       straI2CData[enumI2CBus_p].uiSizeOfDataToSend);

        return(TRUE);
    }

The NACK handling is defined as 

            case DL_I2C_IIDX_CONTROLLER_NACK:
                if (straI2CData[enumI2CBus_p].ucTransmitionStart)
                {
                    if (straI2CCallbacks[enumI2CBus_p].ErrorCallback != NULL)
                    {
                        straI2CCallbacks[enumI2CBus_p].ErrorCallback(straI2CCallbacks[enumI2CBus_p].ucTargetBus);
                    }
                }

                DL_I2C_resetControllerTransfer(ptraI2CBus[enumI2CBus_p]);
                break;

The DL_I2C_resetControllerTransfer resets i2c->MASTER.MCTR which has to be reconfigured as the flags set by "DL_I2C_enableControllerReadOnTXEmpty(ptraI2CBus[enumI2CBus_p]);"  will be cleared.

What should be the right way to handle the NACK events?