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?