主题中讨论的其他器件: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