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.
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?
Hi,
Please refer to this thread:(3) LP-MSPM0G3507: I2C manual NACK causes Bus Hang low - Arm-based microcontrollers forum - Arm-based microcontrollers - TI E2E support forums.
Zoey
Hi, I checked that thread. my problem is in the controller mode, not as a target. Anyway, a complete bus reset would not be the best way to handle the NACk as it can happen in real operation conditions and other functionalities supported by i2c should not be disturbed
Hi,
Maybe you can disable NACK interrupt, and check whether the NACK is received after sending the button's address command.
Hi zoey,
DId you manage to replicate the problem on your side? We are handling i2c via interrups and would be a bad architetcure decision to just be polling for the status of the i2c events... there is no proper way to handle these errors via interrupt?
Hi
Sorry, we don't have test environment to replicate this situation. But I have one question: As the address is to E2PROM or display, not to button, why you can receive NACK from button?
To solve that, How about disable interrupt while writing/reading the eeprom, after it is finish then enable that.
B.R.
Zoey