Part Number: TMS320F280049
Have experimented with various GPIO configs:
Original (from examples):
GPIO_setPinConfig(DEVICE_GPIO_CFG_SDAA);
GPIO_setPadConfig(DEVICE_GPIO_PIN_SDAA, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(DEVICE_GPIO_PIN_SDAA, GPIO_QUAL_ASYNC);
GPIO_setPinConfig(DEVICE_GPIO_CFG_SCLA);
GPIO_setPadConfig(DEVICE_GPIO_PIN_SCLA, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(DEVICE_GPIO_PIN_SCLA, GPIO_QUAL_ASYNC);
Modified:
GPIO_setPinConfig(DEVICE_GPIO_CFG_SCLA);
GPIO_setPadConfig(DEVICE_GPIO_PIN_SCLA, GPIO_PIN_TYPE_OD);
GPIO_setQualificationMode(DEVICE_GPIO_PIN_SCLA, GPIO_QUAL_6SAMPLE);
GPIO_setPinConfig(DEVICE_GPIO_CFG_SDAA);
GPIO_setPadConfig(DEVICE_GPIO_PIN_SDAA, GPIO_PIN_TYPE_OD);
GPIO_setQualificationMode(DEVICE_GPIO_PIN_SDAA, GPIO_QUAL_6SAMPLE);
The original setup yields NAK rate: 0.6%, arbitration lost rate: 0.014%, corrupted messages rate: ?
The modified setup performs considerably better - NAK rate: 0.0015%, arbitration lost rate: 0.011%, corrupted messages rate: 0.014%
The slaves never experience NAKs when trying to send to the master.
Does it make sense that the modified GPIO configs should perform better? Is there a better combination of configs to use? Anything else I should consider (software-wise) to improve performance? If a hardware filter is applied to SDA and SCL, would the expected performance be significantly better than indicated above?
FWIW my code is as follows:
I2C Initialization:
GPIO_setPinConfig(DEVICE_GPIO_CFG_SCLA);
GPIO_setPadConfig(DEVICE_GPIO_PIN_SCLA, GPIO_PIN_TYPE_OD);
GPIO_setQualificationMode(DEVICE_GPIO_PIN_SCLA, GPIO_QUAL_6SAMPLE);
GPIO_setPinConfig(DEVICE_GPIO_CFG_SDAA);
GPIO_setPadConfig(DEVICE_GPIO_PIN_SDAA, GPIO_PIN_TYPE_OD);
GPIO_setQualificationMode(DEVICE_GPIO_PIN_SDAA, GPIO_QUAL_6SAMPLE);
I2C_disableModule(I2CA_BASE);
#ifdef I2C_MASTER
I2C_initMaster(I2CA_BASE, DEVICE_SYSCLK_FREQ, 400000, I2C_DUTYCYCLE_50);
#endif
I2C_setAddressMode(I2CA_BASE, I2C_ADDR_MODE_7BITS);
I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8);
I2C_disableLoopback(I2CA_BASE);
#ifdef I2C_SLAVE
I2C_setOwnSlaveAddress(I2CA_BASE, I2C_ADDRESS);
#endif
I2C_setEmulationMode(I2CA_BASE, I2C_EMULATION_STOP_SCL_LOW); // When debugger hits a breakpoint, SCL will be held low (indefinitely) to pause I2C activity.
// Interrupt when the Tx FIFO has 4 bytes (or less) left to transmit, OR...
// when the Rx FIFO has at least 1 byte of received data.
I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TX4, I2C_FIFO_RX1);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
Interrupt_register(INT_I2CA, &i2cAISR);
Interrupt_enable(INT_I2CA);
Interrupt_register(INT_I2CA_FIFO, &i2cAFIFOISR);
Interrupt_enable(INT_I2CA_FIFO);
Message Transmission:
Master & Slave, Tx & Rx:
I2C_disableModule(I2CA_BASE);
I2C_disableFIFO(I2CA_BASE);
I2C_enableFIFO(I2CA_BASE);
I2C_disableInterrupt(I2CA_BASE, (I2C_INT_RXFF | I2C_INT_TXFF | I2C_INT_STOP_CONDITION |
I2C_INT_ARB_LOST | I2C_INT_NO_ACK | I2C_INT_REG_ACCESS_RDY |
I2C_INT_RX_DATA_RDY | I2C_INT_TX_DATA_RDY | I2C_INT_ADDR_SLAVE));
I2C_clearInterruptStatus(I2CA_BASE, (I2C_INT_RXFF | I2C_INT_TXFF | I2C_INT_STOP_CONDITION |
I2C_INT_ARB_LOST | I2C_INT_NO_ACK | I2C_INT_REG_ACCESS_RDY |
I2C_INT_RX_DATA_RDY | I2C_INT_TX_DATA_RDY | I2C_INT_ADDR_SLAVE));
Master Tx:
I2C_enableInterrupt(I2CA_BASE, (I2C_INT_TXFF | I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK));
I2C_setSlaveAddress(I2CA_BASE, i2cControl.slaveAddress);
I2C_setDataCount(I2CA_BASE, i2cControl.nBytesToTx);
I2C_setConfig(I2CA_BASE, (I2C_MASTER_SEND_MODE | I2C_START_BYTE_MODE));
I2C_enableModule(I2CA_BASE);
I2C_sendStartCondition(I2CA_BASE);
I2C_sendStopCondition(I2CA_BASE);
Master Rx:
I2C_enableInterrupt(I2CA_BASE, (I2C_INT_RXFF | I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK));
I2C_setSlaveAddress(I2CA_BASE, i2cControl.slaveAddress);
I2C_setDataCount(I2CA_BASE, i2cControl.nBytesToRx);
I2C_setConfig(I2CA_BASE, (I2C_MASTER_RECEIVE_MODE | I2C_START_BYTE_MODE));
I2C_enableModule(I2CA_BASE);
I2C_sendStartCondition(I2CA_BASE);
I2C_sendStopCondition(I2CA_BASE);
Slave Tx:
I2C_enableInterrupt(I2CA_BASE, (I2C_INT_TXFF | I2C_INT_STOP_CONDITION | I2C_INT_NO_ACK));
I2C_setConfig(I2CA_BASE, I2C_SLAVE_SEND_MODE);
I2C_enableModule(I2CA_BASE);
Slave Rx:
I2C_enableInterrupt(I2CA_BASE, (I2C_INT_RXFF | I2C_INT_STOP_CONDITION | I2C_INT_NO_ACK));
I2C_setConfig(I2CA_BASE, I2C_SLAVE_RECEIVE_MODE);
I2C_enableModule(I2CA_BASE);
Basic Interrrupt Service Routine:
__interrupt void i2cAISR(void)
{
I2C_InterruptSource i2cInterruptSource;
i2cInterruptSource = I2C_getInterruptSource(I2CA_BASE);
if (i2cInterruptSource == I2C_INTSRC_STOP_CONDITION)
{
i2cControl.bStopRxd = true;
if (i2cControl.bTxInProgress && (i2cControl.nTxdBytes == i2cControl.nBytesToTx))
{
i2cControl.bTxInProgress = false;
}
else if (i2cControl.bRxInProgress && (i2cControl.nRxdBytes == i2cControl.nBytesToRx))
{
i2cControl.bRxInProgress = false;
}
}
else if (i2cInterruptSource == I2C_INTSRC_NO_ACK)
{
Comms.nI2cNaks++; // (DEBUG)
}
#ifdef I2C_MASTER
else if (i2cInterruptSource == I2C_INTSRC_ARB_LOST)
{
Comms.nI2cArbitrationLosts++; // (DEBUG)
}
#endif
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
}
FIFO Interrrupt Service Routine:
__interrupt void i2cAFIFOISR(void)
{
uint32_t i2cInterruptStatus;
i2cInterruptStatus = I2C_getInterruptStatus(I2CA_BASE);
if ((i2cInterruptStatus & I2C_INT_RXFF) != 0)
{
if (i2cControl.bRxInProgress)
{
if (i2cControl.nRxdBytes < i2cControl.nBytesToRx)
{
I2C_RxFIFOLevel i2cRxFIFOLevel = I2C_getRxFIFOStatus(I2CA_BASE);
uint16_t nAddlRxdBytes = mapRxFIFOLevelToCount(i2cRxFIFOLevel);
while (nAddlRxdBytes && (i2cControl.nRxdBytes < i2cControl.nBytesToRx))
{
uint16_t newByte = I2C_getData(I2CA_BASE);
i2cControl.RxBuffer[i2cControl.nRxdBytes] = newByte;
i2cControl.nRxdBytes++;
nAddlRxdBytes--;
}
if (i2cControl.bStopRxd && (i2cControl.nRxdBytes == i2cControl.nBytesToRx))
{
i2cControl.bRxInProgress = false;
}
}
I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF);
}
}
if ((i2cInterruptStatus & I2C_INT_TXFF) != 0)
{
if (i2cControl.bTxInProgress)
{
if (i2cControl.nTxdBytes < i2cControl.nBytesToTx)
{
I2C_TxFIFOLevel i2cTxFIFOLevel = I2C_getTxFIFOStatus(I2CA_BASE);
uint16_t nBytesAvailableFIFOCapacity = I2C_FIFO_SIZE - mapTxFIFOLevelToCount(i2cTxFIFOLevel);
uint16_t nRemainingBytes = i2cControl.nBytesToTx - i2cControl.nTxdBytes;
uint16_t nAddlTxBytes;
if (nRemainingBytes > nBytesAvailableFIFOCapacity)
{
nAddlTxBytes = nBytesAvailableFIFOCapacity;
}
else
{
nAddlTxBytes = nRemainingBytes;
}
while (nAddlTxBytes)
{
I2C_putData(I2CA_BASE, i2cControl.TxBuffer[i2cControl.nTxdBytes]);
i2cControl.nTxdBytes++;
nAddlTxBytes--;
}
I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_TXFF);
}
// If there are NOT more bytes to Tx...
else
{
if (i2cControl.bStopRxd)
{
i2cControl.bTxInProgress = false;
}
}
}
}
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
}