主题中讨论的其他器件:DAC7578、 TCA9555、 C2000WARE
大家好、我正在为我的系统处理 I2C 事务、我注意到为了让我的事务安全完成、我在每个事务之间需要大约75uS 的延迟、以便所有事务都能在停止条件下正常完成。 在大约60us 或更短的延迟时间内、我开始失去总线稳定性、之前事务中的字节出现在下一个事务中、错过了停止条件和/或最终完全锁定总线。 是否有人可能对可能发生的原因有任何见解? 在延迟情况下、一切运行顺利、但如果可能、我想减少这一延迟量。
谢谢!
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.
大家好、我正在为我的系统处理 I2C 事务、我注意到为了让我的事务安全完成、我在每个事务之间需要大约75uS 的延迟、以便所有事务都能在停止条件下正常完成。 在大约60us 或更短的延迟时间内、我开始失去总线稳定性、之前事务中的字节出现在下一个事务中、错过了停止条件和/或最终完全锁定总线。 是否有人可能对可能发生的原因有任何见解? 在延迟情况下、一切运行顺利、但如果可能、我想减少这一延迟量。
谢谢!
感谢您的回答! 以下是您需要的信息:
/*-------------------*/
/* I2C API Functions */
/*-------------------*/
/*-----------*/
/* Variables */
/*-----------*/
volatile I2C_MESSAGE_STRUCT writeDAC =
{
.messageState = TRANSMITTING,
.messageStatus = NO_ERROR,
.slaveChipAddress = DAC1_SLAVE_ADDRESS,
.dataByteCount = 2,
.commandByte = WRITE_DAC,
.dataByteBuffer = { 0x00U, 0x00U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};
volatile I2C_MESSAGE_STRUCT readDAC =
{
.messageState = RECEIVING,
.messageStatus = NO_ERROR,
.slaveChipAddress = DAC1_SLAVE_ADDRESS,
.dataByteCount = 2,
.commandByte = READ_DAC,
.dataByteBuffer = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
};
volatile I2C_MESSAGE_STRUCT rtcGetTimeMsg =
{
.messageState = RECEIVING,
.messageStatus = NO_ERROR,
.slaveChipAddress = RTC_SLAVE_ADDRESS,
.dataByteCount = 7,
.commandByte = RTC_SECONDS_INDEX,
.dataByteBuffer = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
// Read the Weekday Register to Get the Oscillator Status
volatile I2C_MESSAGE_STRUCT rtcGetOscStatusMsg =
{
.messageState = RECEIVING,
.messageStatus = NO_ERROR,
.slaveChipAddress = RTC_SLAVE_ADDRESS,
.dataByteCount = 1,
.commandByte = RTC_WEEKDAY_INDEX,
.dataByteBuffer = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
volatile I2C_MESSAGE_STRUCT writeIOX =
{
.messageState = TRANSMITTING,
.messageStatus = NO_ERROR,
.slaveChipAddress = IO_EXPANDER_A_SLAVE_ADDRESS,
.dataByteCount = 1,
.commandByte = IOX_WRITE_PIN,
.dataByteBuffer = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
volatile I2C_MESSAGE_STRUCT readIOX =
{
.messageState = RECEIVING,
.messageStatus = NO_ERROR,
.slaveChipAddress = IO_EXPANDER_A_SLAVE_ADDRESS,
.dataByteCount = 1,
.commandByte = IOX_READ_PIN,
.dataByteBuffer = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
/*---------------*/
/* I2C Functions */
/*---------------*/
/*---------------------------------------------------------------------------*/
/** @brief Public I2C Read function
* Posts the I2C Read Transaction to the I2C Manager's Mailbox
*
* @param [I2C_MESSAGE_STRUCT* msg] pointer to I2C message struct
* @param [const I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*
* @returns transaction status - success (true) or failure (false)
*//*------------------------------------------------------------------------*/
static bool_dtc I2C_read(const I2C_SETTINGS_STRUCT* settings, volatile I2C_MESSAGE_STRUCT *msg, I2C_DEVICE_ID deviceID)
{
bool_dtc transactionStatus = true;
i2cRead(settings, msg);
DEVICE_DELAY_US(I2C_BUS_DELAY);
if(NO_ERROR != msg->messageStatus)
{
if(WARNING_SPURIOUS_INTERRUPT == msg->messageStatus)
{
++i2cStatistics[deviceID].statsSpuriuousInterrupts;
}
else
{
++i2cStatistics[deviceID].statsReadsFailure;
}
transactionStatus = false;
}
else
{
++i2cStatistics[deviceID].statsReadsSuccess;
}
return transactionStatus;
}
/*---------------------------------------------------------------------------*/
/** @brief Public I2C Write function
* Posts the I2C Write Transaction to the I2C Manager's Mailbox
*
* @param [I2C_MESSAGE_STRUCT* msg] pointer to I2C message struct
* @param [const I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*
* @returns transaction status - success (true) or failure (false)
*//*------------------------------------------------------------------------*/
static bool_dtc I2C_write(const I2C_SETTINGS_STRUCT* settings, volatile I2C_MESSAGE_STRUCT* msg, I2C_DEVICE_ID deviceID)
{
bool_dtc transactionStatus = true;
i2cWrite(settings, msg);
DEVICE_DELAY_US(I2C_BUS_DELAY);
if(NO_ERROR != msg->messageStatus)
{
if(WARNING_SPURIOUS_INTERRUPT == msg->messageStatus)
{
++i2cStatistics[deviceID].statsSpuriuousInterrupts;
}
else
{
++i2cStatistics[deviceID].statsWriteFailure;
}
transactionStatus = false;
}
else
{
++i2cStatistics[deviceID].statsWriteSuccess;
}
return transactionStatus;
}
/*---------------*/
/* DAC Functions */
/*---------------*/
/*---------------------------------------------------------------------------*/
/** @brief Write DAC
*
* Public DAC Write Function to start an I2C Write Transaction
*
* @param [dac] pointer to an instance of DAC_STRUCT
* @param [deviceID] The I2C Device ID
*
* @returns true/false based on transaction success status
*//*------------------------------------------------------------------------*/
bool_dtc DAC_write(DAC_STRUCT *dac, I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionSuccessful = false;
DAC_PN partNumber = -1;
switch(deviceID)
{
case DAC1:
writeDAC.slaveChipAddress = DAC1_SLAVE_ADDRESS;
partNumber = DAC_TI_DAC7578;
break;
case DAC2:
writeDAC.slaveChipAddress = DAC2_SLAVE_ADDRESS;
break;
default:
break; //Device Not Found
}
i2cTransactionSuccessful = dac_translateToI2C(dac, &writeDAC, partNumber);
if(i2cTransactionSuccessful)
{
writeDAC.commandByte = WRITE_DAC | dac->channel;
i2cTransactionSuccessful = I2C_write(&i2cASettings, &writeDAC, deviceID);
}
return i2cTransactionSuccessful;
}
/*---------------------------------------------------------------------------*/
/** @brief Read DAC
*
* Public DAC Read Function to start an I2C Read Transaction
*
* @param [dac] pointer to an instance of DAC_STRUCT
* @param [deviceID] The I2C Device ID
*
* @returns true/false based on transaction success status
*//*------------------------------------------------------------------------*/
bool_dtc DAC_read(DAC_STRUCT *dac, I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionSuccessful = false;
DAC_PN partNumber = -1;
switch(deviceID)
{
case DAC1:
readDAC.slaveChipAddress = DAC1_SLAVE_ADDRESS;
partNumber = DAC_TI_DAC7578;
break;
case DAC2:
readDAC.slaveChipAddress = DAC2_SLAVE_ADDRESS;
break;
default:
break; //Device Not Found
}
readDAC.commandByte = READ_DAC | dac->channel;
i2cTransactionSuccessful = I2C_read(&i2cASettings, &readDAC, deviceID);
if(i2cTransactionSuccessful)
{
i2cTransactionSuccessful = dac_translateFromI2C(dac, &readDAC, partNumber);
}
return i2cTransactionSuccessful;
}
/*---------------*/
/* RTC Functions */
/*---------------*/
/*---------------------------------------------------------------------------*/
/** @brief Initializes the RTC
* @param [deviceID] The I2C Device ID
*//*------------------------------------------------------------------------*/
bool_dtc RTC_init(I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionStatus = false;
RTCTimeFormat defaultDate =
{
.year = 0x21,
.month = 0x04,
.date = 0x25,
.weekday = 0x01,
.hours = 0x10,
.minutes = 0x30,
.seconds = 0x30
};
i2cTransactionStatus = I2C_read(&i2cASettings, &rtcGetOscStatusMsg, deviceID);
//If the I2C Read was successful and the Oscillator is NOT running
if(i2cTransactionStatus
&& (RTC_OSCRUN_STATUS != (rtcGetOscStatusMsg.dataByteBuffer[0] & RTC_OSCRUN_STATUS)))
{
i2cTransactionStatus = RTC_setTime(&defaultDate, deviceID);
}
return i2cTransactionStatus;
}
/*---------------------------------------------------------------------------*/
/** @brief read time from RTC device
*
* Sends the get date command to device, then converts the BCD digits to
* integers populated into the out pointer structure.
*
* @param [timeStruct] pointer to an instance of RTCTimeFormat structure
* @param [deviceID] The I2C Device ID
*
* @returns true/false based on transaction success status
*//*------------------------------------------------------------------------*/
bool_dtc RTC_getTime(RTCTimeFormat* timeStruct, I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionSuccessful = false;
i2cTransactionSuccessful = I2C_read(&i2cASettings, &rtcGetTimeMsg, deviceID);
if(i2cTransactionSuccessful)
{
i2cTransactionSuccessful = rtc_translateFromI2C(timeStruct, &rtcGetTimeMsg);
}
return i2cTransactionSuccessful;
}
/*---------------------------------------------------------------------------*/
/** @brief set time on RTC device
*
* Converts the time/date data from decimal to BCD and builds it into the I2C message.
* Then sends the message to RTC to set the new time/date.
*
* @param [timeStruct] pointer to an instance of RTCTimeFormat structure
* @param [deviceID] The I2C Device ID
*
* @returns true/false based on transaction success status
*//*------------------------------------------------------------------------*/
bool_dtc RTC_setTime(RTCTimeFormat* timeStruct, I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionSuccessful = false;
i2cTransactionSuccessful = rtc_translateToI2C(timeStruct, &rtcSetTimeMsg);
if(i2cTransactionSuccessful)
{
// Disable the RTC oscillator
i2cTransactionSuccessful = I2C_write(&i2cASettings, &rtcStopOscillatorMsg, deviceID);
// Transmit the time structure to the RTC
if(i2cTransactionSuccessful)
{
i2cTransactionSuccessful = I2C_write(&i2cASettings, &rtcSetTimeMsg, deviceID);
Board_deviceDelayUs(I2C_BUS_DELAY); //Extra Delay Required for RTC Set Time
}
if(i2cTransactionSuccessful)
{
// Enable the RTC oscillator
rtcStartOscillatorMsg.dataByteBuffer[RTC_SECONDS_INDEX] |= rtcSetTimeMsg.dataByteBuffer[RTC_SECONDS_INDEX];
i2cTransactionSuccessful = I2C_write(&i2cASettings, &rtcStartOscillatorMsg, deviceID);
}
}
return i2cTransactionSuccessful;
}
/*---------------------------------------------------------------------------*/
/** @brief Writes to an IO Expander on the I2C Bus
*
* Writes the Pin Status to the Selected Pins in the IOX_STRUCT
*
* @param [*iox] pointer to an instance of IOX_STRUCT
* @param [deviceID] I2C Device ID
*
* @returns true/false based on transaction success status
*//*------------------------------------------------------------------------*/
bool_dtc IOX_write(IOX_STRUCT *iox, I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionSuccessful = false;
switch(deviceID)
{
case IOXA:
writeIOX.slaveChipAddress = IO_EXPANDER_A_SLAVE_ADDRESS;
break;
case IOXB:
writeIOX.slaveChipAddress = IO_EXPANDER_B_SLAVE_ADDRESS;
break;
default:
break; //Device Not Found
}
writeIOX.commandByte = IOX_WRITE_PIN;
i2cTransactionSuccessful = iox_translateToI2C(iox, &writeIOX, currentPinStatusIOX);
if(i2cTransactionSuccessful)
{
i2cTransactionSuccessful = I2C_write(&i2cASettings, &writeIOX, deviceID);
}
return i2cTransactionSuccessful;
}
/*---------------------------------------------------------------------------*/
/** @brief Reads from an IO Expander on the I2C Bus
*
* Reads the Pin Status from the Selected Pins in the IOX_STRUCT
*
* @param [*iox] pointer to an instance of IOX_STRUCT
* @param [deviceID] I2C Device ID
*
* @returns true/false based on transaction success status
*//*------------------------------------------------------------------------*/
bool_dtc IOX_read(IOX_STRUCT *iox, I2C_DEVICE_ID deviceID)
{
bool_dtc i2cTransactionSuccessful = false;
iox->pinStatus = IOX_PIN_DONT_CARE;
switch(deviceID)
{
case IOXA:
readIOX.slaveChipAddress = IO_EXPANDER_A_SLAVE_ADDRESS;
break;
case IOXB:
readIOX.slaveChipAddress = IO_EXPANDER_B_SLAVE_ADDRESS;
break;
default:
break; //Device Not Found
}
readIOX.commandByte = IOX_READ_PIN;
i2cTransactionSuccessful = iox_translateToI2C(iox, &readIOX, currentPinStatusIOX);
if(i2cTransactionSuccessful)
{
i2cTransactionSuccessful = I2C_read(&i2cASettings, &readIOX, deviceID);
}
if(i2cTransactionSuccessful)
{
i2cTransactionSuccessful = iox_translateFromI2C(iox, &readIOX);
}
return i2cTransactionSuccessful;
}/*-------------------*/
/* I2C HAL Functions */
/*-------------------*/
/*-----------------------------------------------------------------------------
* Types (typedefs, structs, class declarations)
*---------------------------------------------------------------------------*/
/**
* Dummy message struct to ensure currTxMsgPtr always
* points to a valid memory location
*/
volatile static I2C_MESSAGE_STRUCT dummyMsg =
{
.messageState = INACTIVE,
.messageStatus = NO_ERROR,
.slaveChipAddress = 1,
.dataByteCount = 16,
.commandByte = 0x00U,
.dataByteBuffer = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
/*-----------------------------------------------------------------------------
* Static "private" (file scope) variables
*---------------------------------------------------------------------------*/
/**
* Current message pointers are used by the ISR to track which operation
* is being executed on the I2C bus.
* I point both the Tx and Rx Message Pointers to the dummyMsg at initialization
* so that the pointers aren't pointing to random memory locations.
*/
static volatile I2C_MESSAGE_STRUCT *currTxMsgPtr = &dummyMsg;
static volatile I2C_MESSAGE_STRUCT *currRxMsgPtr = &dummyMsg;
/*-----------------------------------------------------------------------------
* Implementations of static "private" (file scope) functions
*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/** @brief Reset the indicated I2C FIFO
*
* This function resets the indicated I2C FIFO
* @param [uint32_dtc base] base address of the I2C module
* @param [I2C_FIFO_TYPE fifoType] The type of FIFO to reset, either TX or RX
*//*------------------------------------------------------------------------*/
static void I2C_resetFIFO(uint32_dtc base)
{
I2C_disableFIFO(base);
I2C_enableFIFO(base);
}
/*---------------------------------------------------------------------------*/
/** @brief Function called by the FIFO Interrupts
*
* This function handles what to do with the information in the FIFOs
* @param [I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*//*------------------------------------------------------------------------*/
void i2cFIFOInterruptHandler(const I2C_SETTINGS_STRUCT *settings)
{
uint32_dtc base = settings->i2cBaseAddr;
uint32_dtc intStatus = I2C_getInterruptStatus(base);
//Interrupt is from the Receive FIFO
if(I2C_INT_RXFF == (intStatus & I2C_INT_RXFF))
{
I2C_sendStopCondition(base);
uint32_dtc byteWaitCounter = 0;
while((byteWaitCounter < I2C_RX_TIMEOUT)
&& ((I2C_RxFIFOLevel)currRxMsgPtr->dataByteCount != I2C_getRxFIFOStatus(base)))
{
++byteWaitCounter;
}
if(byteWaitCounter != I2C_RX_TIMEOUT)
{
for(int16_dtc i = 0; i < currRxMsgPtr->dataByteCount; ++i)
{
currRxMsgPtr->dataByteBuffer[i] = I2C_getData(base);
}
}
else
{
currRxMsgPtr->messageStatus = ERROR_RX_TIMEOUT;
}
I2C_resetFIFO(base);
currRxMsgPtr = &dummyMsg;
}
else //Interrupt is from the Transmit FIFO
{
currTxMsgPtr = &dummyMsg;
}
I2C_clearInterruptStatus(base, (uint32_dtc)(I2C_INT_TXFF | I2C_INT_RXFF));
I2C_setFIFOInterruptLevel(base, I2C_FIFO_TXEMPTY, I2C_FIFO_RXFULL);
I2C_disableFIFO(base);
}
/*------------------------------------------------------------------------------*/
/** @brief Helper Function called by the I2C Interrupt Handler for NACKs
*
* This function handles the NACK interrupt from the I2C Module
* @param [I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*//*------------------------------------------------------------------------*/
static void i2cInterrputHandler_NACK(const I2C_SETTINGS_STRUCT *settings)
{
uint32_dtc base = settings->i2cBaseAddr;
//Reset the TX FIFO to clear any data inside of it
I2C_resetFIFO(base);
I2C_clearInterruptStatus(base, (uint32_dtc)I2C_INT_TXFF);
//Clear NACK Status and Interrupt
I2C_clearStatus(base, I2C_STS_NO_ACK);
I2C_clearInterruptStatus(base, I2C_INT_NO_ACK);
//Report that the Message was Nacked
if(INACTIVE != currTxMsgPtr->messageState)
{
currTxMsgPtr->messageStatus = ERROR_NACKED_SETUP;
currTxMsgPtr = &dummyMsg;
}
else //(INACTIVE == currTxMsgPtr->messageState) thus this is an Rx NACK
{
currRxMsgPtr->messageStatus = ERROR_NACKED_SETUP;
currRxMsgPtr = &dummyMsg;
}
I2C_sendStopCondition(base);
}
/*---------------------------------------------------------------------------------*/
/** @brief Helper Function called by the I2C Interrupt Handler for REG_ACCESS_RDY
*
* This function handles the REG_ACCESS_RDY Interrupt from the I2C Module
* @param [I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*//*------------------------------------------------------------------------------*/
static void i2cInterruptHandler_RegAccesRdy(const I2C_SETTINGS_STRUCT *settings)
{
if(INACTIVE != currRxMsgPtr->messageState)
{
uint32_dtc base = settings->i2cBaseAddr;
I2C_clearInterruptStatus(base, I2C_INT_REG_ACCESS_RDY);
I2C_disableFIFO(base);
I2C_enableFIFO(base);
I2C_disableInterrupt(base, (uint32_dtc)(I2C_INT_TXFF | I2C_INT_RXFF));
I2C_clearInterruptStatus(base, (uint32_dtc)(I2C_INT_TXFF | I2C_INT_RXFF));
I2C_setConfig(base, (uint16_dtc)I2C_MASTER_RECEIVE_MODE);
I2C_setDataCount(base, currRxMsgPtr->dataByteCount);
I2C_enableInterrupt(base, (uint32_dtc)I2C_INT_RXFF);
I2C_setFIFOInterruptLevel(base, I2C_FIFO_TXEMPTY, (I2C_RxFIFOLevel)(currRxMsgPtr->dataByteCount - 1));
I2C_sendStartCondition(base);
}
}
/*------------------------------------------------------------------------------------*/
/** @brief Helper Function called by the I2C Interrupt Handler for Spurious Interrupts
*
* This function handles Spurious Interrupts from the I2C Module
* @param [I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*//*--------------------------------------------------------------------------------*/
static void i2cInterrputHandler_SpuriousInt(const I2C_SETTINGS_STRUCT *settings)
{
//Report that the Message was Nacked
if(INACTIVE != currTxMsgPtr->messageState)
{
currTxMsgPtr->messageStatus = WARNING_SPURIOUS_INTERRUPT;
currTxMsgPtr = &dummyMsg;
}
else //(INACTIVE != currRxMsgPtr->messageState)
{
currRxMsgPtr->messageStatus = WARNING_SPURIOUS_INTERRUPT;
currRxMsgPtr = &dummyMsg;
}
I2C_clearInterruptStatus(settings->i2cBaseAddr, I2C_STR_INTMASK);
}
/*-----------------------------------------------------------------------------
* Implementations of "public" API
*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/** @brief Function called by the I2C ISR
* This function handles the interrupts on the I2C Bus
*
* @param [I2C_SETTINGS_STRUCT *setting] - a pointer to the I2C settings
* for the module that generated the interrupt
*//*------------------------------------------------------------------------*/
void i2cInterruptHandler(const I2C_SETTINGS_STRUCT *settings)
{
uint32_t base = settings->i2cBaseAddr;
I2C_InterruptSource intSource = I2C_getInterruptSource(base);
switch (intSource)
{
case I2C_INTSRC_NONE:
case I2C_INTSRC_RX_DATA_RDY:
case I2C_INTSRC_TX_DATA_RDY:
break;
case I2C_INTSRC_NO_ACK:
i2cInterrputHandler_NACK(settings);
break;
case I2C_INTSRC_REG_ACCESS_RDY:
i2cInterruptHandler_RegAccesRdy(settings);
break;
case I2C_INTSRC_STOP_CONDITION:
I2C_disableInterrupt(base, (uint32_dtc)(I2C_INT_TXFF | I2C_INT_RXFF));
I2C_clearInterruptStatus(base, (uint32_dtc)(I2C_INT_TXFF | I2C_INT_RXFF));
break;
default:
i2cInterrputHandler_SpuriousInt(settings);
}
}
/*---------------------------------------------------------------------------*/
/** @brief Send a write message on the I2C bus.
*
* Sets slave address and puts address and data bytes on to transmit
* register.
* messageStatus field of the struct should be set to MSGSTAT_SEND_WITHSTOP
*
* @pre configure I2C_MESSAGE_STRUCT object
* ***ENSURE THAT MESSAGE STRUCTURE REMAINS IN SCOPE UNTIL WRITE COMPLETES
* @post check error code
*
* @param [I2C_MESSAGE_STRUCT* msg] pointer to I2C message struct
*
* @returns transaction status - success (true) or failure (false)
*//*------------------------------------------------------------------------*/
void i2cWrite(const I2C_SETTINGS_STRUCT* settings, volatile I2C_MESSAGE_STRUCT* msg)
{
uint32_dtc base = settings->i2cBaseAddr;
//Save current message state
currTxMsgPtr = msg;
I2C_disableFIFO(base);
I2C_setConfig(base, (uint16_dtc)I2C_MASTER_SEND_MODE);
// Setup slave address
I2C_setSlaveAddress(base, currTxMsgPtr->slaveChipAddress);
I2C_enableFIFO(base);
//Set expected byte count on the FIFO
I2C_setDataCount(base, (currTxMsgPtr->dataByteCount + 1));
//write address buffer one byte at a time onto output FIFO
I2C_putData(base, currTxMsgPtr->commandByte);
//write data buffer one byte at a time onto output FIFO
for (int32_dtc i = 0; i < currTxMsgPtr->dataByteCount; ++i)
{
I2C_putData(base, currTxMsgPtr->dataByteBuffer[i]);
}
I2C_sendStartCondition(base);
I2C_sendStopCondition(base);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets up I2C Module to perform a read
*
* Sets slave address and writes registers to be read
* Changes status of I2C_MESSAGE_STRUCT pointer to indicate address setup
* complete
*
* @pre configure I2C_MESSAGE_STRUCT object
* ***ENSURE THAT MESSAGE STRUCTURE REMAINS IN SCOPE UNTIL READ COMPLETES
* @post check error code. Should fire ISR after address setup completes
*
* @param [I2C_MESSAGE_STRUCT* msg] pointer to I2C message struct
*
* @returns transaction status - success (true) or failure (false)
*//*------------------------------------------------------------------------*/
void i2cRead(const I2C_SETTINGS_STRUCT* settings, volatile I2C_MESSAGE_STRUCT *msg)
{
uint32_dtc base = settings->i2cBaseAddr;
//Save current message state
currRxMsgPtr = msg;
I2C_disableFIFO(base);
I2C_setConfig(base, (uint16_dtc)I2C_MASTER_SEND_MODE);
// Setup slave address
I2C_setSlaveAddress(base, currRxMsgPtr->slaveChipAddress);
I2C_enableFIFO(base);
//First, the module must setup the register addresses to be read by issuing a write to the slave on the bus
//Set the number of address registers to be read
I2C_setDataCount(base, 1);
//Put the addresses onto the transmit FIFO
I2C_putData(base, currRxMsgPtr->commandByte);
I2C_sendStartCondition(base);
}/*----------*/
/* I2C Main */
/*----------*/
//Running in a Loop going at 1kHz
void I2CM_i2cTest(void)
{
++dacCount;
if(150 == dacCount)
{
dacCount = 0;
for(int32_dtc i = 1; i <= 8; ++i)
{
testDAC.percent = 0.125F * i;
DAC_write(&testDAC, DAC1);
DAC_read(&testDAC, DAC1);
}
for(int32_dtc i = 7; i >= 0; --i)
{
testDAC.percent = 0.125F * i;
DAC_write(&testDAC, DAC1);
DAC_read(&testDAC, DAC1);
}
if(ledsOn)
{
ledsOn = false;
testIOX0.pinStatus = (IOX_PIN_STATUS)PIN_LOW;
IOX_write(&testIOX0, IOXA);
testIOX0.pinStatus = IOX_PIN_DONT_CARE;
IOX_read(&testIOX0, IOXA);
testIOX1.pinStatus = (IOX_PIN_STATUS)PIN_LOW;
IOX_write(&testIOX1, IOXA);
testIOX1.pinStatus = IOX_PIN_DONT_CARE;
IOX_read(&testIOX1, IOXA);
}
else
{
ledsOn = true;
testIOX0.pinStatus = (IOX_PIN_STATUS)PIN_HIGH;
IOX_write(&testIOX0, IOXA);
testIOX0.pinStatus = IOX_PIN_DONT_CARE;
IOX_read(&testIOX0, IOXA);
testIOX1.pinStatus = (IOX_PIN_STATUS)PIN_HIGH;
IOX_write(&testIOX1, IOXA);
testIOX1.pinStatus = IOX_PIN_DONT_CARE;
IOX_read(&testIOX1, IOXA);
}
}
++rtcCount;
if(500 == rtcCount)
{
rtcCount = 0;
RTC_init(RTC);
RTC_getTime(&defaultDate, RTC);
}
}再次感谢您!
尊敬的罗纳尔杜斯、您好!
我将回顾您分享的内容、如果我发现了一些内容、请告知您。
[引用 userid="480852" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1019094/tms320f28374s-i2c-transactions-requiring-a-relatively-long-delay-in-order-to-safely-complete-transactions/3767286 #3767286">时钟速度为200MHz。这是器件时钟速度。 请求 I2C (SCL)时钟速度。 通常在软件中配置为100KHz (标准)或400KHz (快速模式)。 您也可以共享 I2C init 函数吗?
最棒的
Kevin
很抱歉。 I2C 模块在快速模式@ 400kHz 下运行。 我附加了下面的 init 函数。 谢谢!
/*-----------------------------------------------------------------------------
* Implementations of "public" API
*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/** @brief Initializes I2C Module
* CPU core 1 is set as the I2C master.
*
* Set up module as I2C master.
* Set up SDA and SCL and enable their pullups
* Enable FIFO modes and interrupts
* Enable module
*//*------------------------------------------------------------------------*/
void I2C_initializeI2C(I2C_SETTINGS_STRUCT* settings)
{
if (false == settings->isInitialized)
{
//Disable HWIs
Hwi_disablePIEIER(I2C_PIE_INTERRUPT_GROUP, I2CA_INTERRUPT_MASK | I2CA_FIFO_INTERRUPT_MASK);
//Have currTxMsgPtr point to the dummy message struct
currTxMsgPtr = &dummyMsg;
currRxMsgPtr = &dummyMsg;
//Disable the module at outset
I2C_disableModule(settings->i2cBaseAddr);
//Configure the SDAA and SCLA GPIO pins.
GPIO_setMasterCore(settings->i2cSDAPin, GPIO_CORE_CPU1);
GPIO_setPinConfig(settings->i2cSDAConfig);
GPIO_setPadConfig(settings->i2cSDAPin, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(settings->i2cSDAPin, GPIO_QUAL_ASYNC);
GPIO_setMasterCore(settings->i2cSCLPin, GPIO_CORE_CPU1);
GPIO_setPinConfig(settings->i2cSCLConfig);
GPIO_setPadConfig(settings->i2cSCLPin, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(settings->i2cSCLPin, GPIO_QUAL_ASYNC);
//Initialize module I2CA as I2C Master
//Set clock frequency to 400 kHz and duty cycle to 33 percent
I2C_initMaster(settings->i2cBaseAddr, (uint32_dtc)DEVICE_SYSCLK_FREQ,
settings->i2cClockFrequency, settings->i2cClockDutyCycle);
//Set addressing mode
I2C_setAddressMode(settings->i2cBaseAddr, settings->i2cAddressingMode);
//Set Emulation mode to free-run. SCL will run according to transmission even if emulation is suspended
I2C_setEmulationMode(settings->i2cBaseAddr, I2C_EMULATION_FREE_RUN);
//Set bits per data byte transmitted over the I2C bus.
//For all transactions, this should be set to 8 to utilize the full data byte
I2C_setBitCount(settings->i2cBaseAddr, I2C_BITCOUNT_8);
//Enable FIFO mode operation and clear all possible I2C device interrupts
I2C_enableFIFO(settings->i2cBaseAddr);
I2C_setFIFOInterruptLevel(settings->i2cBaseAddr, I2C_FIFO_TXEMPTY, I2C_FIFO_RXFULL);
I2C_clearInterruptStatus(settings->i2cBaseAddr, (uint32_dtc)(I2C_STR_INTMASK | I2C_INT_TXFF | I2C_INT_RXFF));
//Enable I2C Module Interrupts upon Access-Ready and Stop Condition Detect
I2C_enableInterrupt(settings->i2cBaseAddr, (I2C_INT_STOP_CONDITION | I2C_INT_REG_ACCESS_RDY | I2C_INT_NO_ACK));
//Enable module
I2C_enableModule(settings->i2cBaseAddr);
//Enable PIE Interrupts for PIE group 8 for I2C
DINT;
if(I2CA_BASE == settings->i2cBaseAddr)
{
Hwi_enablePIEIER(I2C_PIE_INTERRUPT_GROUP, I2CA_INTERRUPT_MASK | I2CA_FIFO_INTERRUPT_MASK);
}
else
{
Hwi_enablePIEIER(I2C_PIE_INTERRUPT_GROUP, I2CB_INTERRUPT_MASK | I2CB_FIFO_INTERRUPT_MASK);
}
EINT;
//Set isInitialized to true to ensure initialization happens only once
settings->isInitialized = true;
}
}尊敬的罗纳尔杜斯、您好!
我相信您会遇到一些问题、因为您列出的大多数通信长度都超过60us、即使在400KHz 时也是如此。
[引用 userid="480852" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1019094/tms320f28374s-i2c-transactions-requiring-a-relatively-long-delay-in-order-to-safely-complete-transactions/3767286 #3767286"]DAC对于上面的示例、您正在写入从器件地址+ 3个数据字节。 在400KHz 时、从开始到停止条件的通信需要~90us、并且包含 Nack/ACK 位。 在开始新的通信序列之前、您应该添加一个用于检查总线状态的函数、如下所示:
uint16_t checkBusStatus(uint32_t base)
{
if(I2C_isBusBusy(base))
{
return ERROR_BUS_BUSY;
}
if(I2C_getStopConditionStatus(base))
{
return ERROR_STOP_NOT_READY;
}
return SUCCESS;
}
我建议查看我们在 C2000WARE 中发布的一些较新的 I2C 示例、以进一步了解如何编写 I2C 代码。 请参阅以下目录:
最棒的
Kevin
大家好、Kevin、
感谢您提供的信息! 当我执行 I2C_write()事务时,在 while 循环中执行类似的检查对我有效,但在 I2C_read()事务上不起作用。 这是我做的、我是否错过了什么?
/*---------------------------------------------------------------------------*/
/** @brief Check Bus Status
* Checks to See if an I2C Transaction is still in progress
*
* @param [const I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*
* @returns isBusFree - Bus is Free (true) / Bus is Not Free (false)
*//*------------------------------------------------------------------------*/
static bool_dtc isBusFree(const I2C_SETTINGS_STRUCT *settings)
{
uint32_dtc base = settings->i2cBaseAddr;
bool_dtc isBusFree = true;
if(I2C_isBusBusy(base))
{
isBusFree = false;
}
if(I2C_getStopConditionStatus(base))
{
isBusFree = false;
}
return isBusFree;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Read function
* Posts the I2C Read Transaction to the I2C Manager's Mailbox
*
* @param [I2C_MESSAGE_STRUCT* msg] pointer to I2C message struct
* @param [const I2C_SETTINGS_STRUCT* settings] pointer to I2C settings struct
*
* @returns transaction status - success (true) or failure (false)
*//*------------------------------------------------------------------------*/
static bool_dtc I2C_read(const I2C_SETTINGS_STRUCT* settings, volatile I2C_MESSAGE_STRUCT *msg, I2C_DEVICE_ID deviceID)
{
bool_dtc transactionStatus = true;
i2cRead(settings, msg);
while(!isBusFree(settings))
{
//Wait for Transaction to Finish
}
if(NO_ERROR != msg->messageStatus)
{
if(WARNING_SPURIOUS_INTERRUPT == msg->messageStatus)
{
++i2cStatistics[deviceID].statsSpuriuousInterrupts;
}
else
{
++i2cStatistics[deviceID].statsReadsFailure;
}
transactionStatus = false;
}
else
{
++i2cStatistics[deviceID].statsReadsSuccess;
}
return transactionStatus;
}
再次感谢您的帮助!
大家好、Kevin、
感谢您的回复! 因此、看起来发生的情况是、在读取事务上、循环在总线空闲之前或在达到停止条件之前结束。 很抱歉、我没有提到我有一个查看总线的逻辑分析仪、我可以向您展示所发生的情况:
在该图中、我将写入 DAC、然后从中读取。 我有读取事务延迟、事务按预期完成。 这种通用的读/写模式继续存在。
在该图中、我正在执行相同的写入/读取模式、但我使用了 while Loop 方法、您会看到我提供了在 DAC 上执行读取事务的命令、但我跳过了下一次写入事务。
就好像 REG_ACCESS_RDY HWI 会触发从发送切换到接收 while 循环中断一样。 我是否做了错误的事情?
再次感谢 Kevin、您给予了很多帮助!
尊敬的罗纳尔杜斯、您好!
这些波形的唯一区别是、您将'I2C_READ'函数中的'while (!isBusFree (settings))'循环更改为延迟? 或者、您是否不仅仅改变了这种情况?
我不太清楚'bool_DTC I2C_read'函数和状态机是如何工作的。 在下面的代码中、您只向 DAC 器件发送命令字节、之后当随后的读取请求发生(即起始地址+从地址+读取位设置)时、该字节不会被清除。
i2cRead(settings, msg);
while(!isBusFree(settings))
{
//Wait for Transaction to Finish
}
我想这是在 ISR 中处理的。 您能否在 ISR 顶部设置断点并检查触发的中断源。
最棒的
Kevin
尊敬的 Kevin:
再次感谢您的回答! 没有、我唯一切换掉的代码是我 用 while 循环替换了'device_delay_US (I2C_bus_delay)'。 这是我处理 I2C 读取事务的当前流程。

当我在 I2C HAL 层内完成'i2cRead ()'调用后有延迟时、接收到的中断源为'I2C_INTSRC_REG_ACCESS_RDY'。 问题是、当我使用 while 环路版本时、我没有获得该中断
尊敬的罗纳尔杜斯、您好!
[引用 userid="480852" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1019094/tms320f28374s-i2c-transactions-requiring-a-relatively-long-delay-in-order-to-safely-complete-transactions/3779677 #3779677"]I2C HAL 层内的"i2cRead ()"调用结束后、我在延迟后收到的中断源是"I2C_INTSRC_REG_ACCESS_RDY。" 问题是、当我使用 while 循环版本时、我没有获得该中断您是否获得了不同的中断? 还是根本没有中断? 似乎正在输入写入序列、触发写入序列代码的是什么?
我不知道为什么您会看到 while 循环的不同行为。 它应该保持在 while 环路中、直到生成停止条件并且可以开始新的通信。
最棒的
Kevin