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_INT_STOP_Condition 和 2C_INT_NO_ACK 中断的 I2C 代码。
在中断处理程序中、当我获取 2C_INT_NO_ACK 时、我 会调用 I2C_sendStopCondition、以便接下来获取 I2C_INT_STOP_Condition 中断。
我这样做是为了在单点(停止条件)处理消息的每一端并启动新的传输。
现在、 NACKed 消息后下一次传输失败的时间大约有一半。
为了解决这个问题、我尝试 在中断处理程序中添加一个 while 循环、在它启动新的(有时失败)消息之前轮询 I2C_getStopConditionStatus。
这解决了问题、但是、对于其他 I2C 器件、有时这种 while 循环会卡住、因为 I2C_getStopConditionStatus 在某些情况下似乎总是返回 true。
什么会导致 I2C_getStopConditionStatus 从不返回 FALSE?
您好、Kustaa、
根据参考手册对 I2CMDR 寄存器的说明(这是 I2C_getStopConditionStatus 函数使用的内容):
您能告诉我您的 I2C 配置吗? F28004x I2C 是设置为控制器还是目标? 是接收还是传输? 它使用哪种串行格式模式?
此致、
阿米尔·奥马尔
您好!
以下是初始化 I2C 控制器的方式:
void init_i2ca() { Interrupt_disable(INT_I2CA); Interrupt_disable(INT_I2CA_FIFO); I2C_disableInterrupt(I2CA_BASE, I2C_INT_NO_ACK); I2C_disableInterrupt(I2CA_BASE, I2C_INT_STOP_CONDITION); g_i2cbus_endp.m_trnx_idx = 0; g_i2cbus_endp.m_receive = false; I2C_disableModule(I2CA_BASE); I2C_initMaster(I2CA_BASE, DEVICE_SYSCLK_FREQ, 100000, I2C_DUTYCYCLE_50); I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE); I2C_setDataCount(I2CA_BASE, 0); I2C_setBitCount(I2CA_BASE, I2C_BITCOUNT_8); I2C_disableFIFO(I2CA_BASE); I2C_enableFIFO(I2CA_BASE); I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXFULL, I2C_FIFO_RXFULL); I2C_enableModule(I2CA_BASE); Interrupt_register(INT_I2CA_FIFO, &i2c_FIFO_ISR); Interrupt_register(INT_I2CA, &i2c_ISR); Interrupt_enable(INT_I2CA); I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_NO_ACK | I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST); I2C_enableInterrupt(I2CA_BASE, I2C_INT_NO_ACK | I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST); i2c_start_next_transfer(); }
这是我的中断处理程序:
__interrupt void i2c_ISR(void) { uint32_t istat = I2C_getInterruptStatus(I2CA_BASE); if (istat & I2C_INT_STOP_CONDITION) { GPIO_togglePin(39); I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_STOP_CONDITION); i2c_handle_received_data(); i2c_start_next_transfer(); GPIO_togglePin(39); } if (istat & I2C_INT_NO_ACK) { GPIO_togglePin(39); I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_NO_ACK); I2C_clearStatus(I2CA_BASE, I2C_STS_NO_ACK); I2C_disableFIFO(I2CA_BASE); I2C_enableFIFO(I2CA_BASE); I2C_sendStopCondition(I2CA_BASE); GPIO_togglePin(39); } if (istat & I2C_INT_ARB_LOST) { I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_ARB_LOST); } Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8); }
这用于处理在获取停止条件中断时接收/接收新消息:
void i2c_start_next_transfer() { I2C_Trxn_t *trxn = get_next_transfer(&g_i2cbus_endp); if (trxn) { while(I2C_getStopConditionStatus(I2CA_BASE)) GPIO_togglePin(39); //g_debug_x = trxn->m_debug; I2C_disableFIFO(I2CA_BASE); I2C_enableFIFO(I2CA_BASE); if (trxn->m_send) { I2C_setSlaveAddress(I2CA_BASE, trxn->m_addr); I2C_setConfig(I2CA_BASE, I2C_MASTER_SEND_MODE); I2C_setDataCount(I2CA_BASE, trxn->m_data_len); uint16_t i; for (i = 0; i < trxn->m_data_len; i++) { I2C_putData(I2CA_BASE, trxn->m_data[i]); } //I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXEMPTY, I2C_FIFO_RXFULL); } else { I2C_setSlaveAddress(I2CA_BASE, trxn->m_addr); I2C_setConfig(I2CA_BASE, I2C_MASTER_RECEIVE_MODE); I2C_setDataCount(I2CA_BASE, trxn->m_data_len); //I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TXFULL, (I2C_RxFIFOLevel) trxn->m_data_len); } I2C_sendStartCondition(I2CA_BASE); I2C_sendStopCondition(I2CA_BASE); } else { I2C_disableInterrupt(I2CA_BASE, I2C_INT_NO_ACK); I2C_disableInterrupt(I2CA_BASE, I2C_INT_STOP_CONDITION); } }
它是在上面的 int
while (I2C_getStopConditionStatus (I2CA_BASE))
代码有时会卡住。
您好、Kustaa、
它是在上面的 int
while (I2C_getStopConditionStatus (I2CA_BASE))
[/报价]
代码有时会卡住。根据寄存器描述、STP 位在停止条件生成后自动清零。 我不确定为什么 在您的设备上有时不会清除它。 就从器件发送的有效传输而言、您是否在示波器上验证了这一点? 发送完成后应立即产生停止条件(见下文):
也要确保 I2C 外设未处于复位状态(我不确定这里是否会发生这种情况、但这 会阻止 I2C 外设检测启动/停止条件)。
此致、
阿米尔·奥马尔
您说停止条件的一部分取决于我要通信的总线上的器件?
因此、在中断服务例程中、像我这样的(可能)无限循环是不可接受的?
我的思维模型是停止条件由 I2C 控制器单独生成、因此始终会发生、环路将会退出。
除了实现超时之外、是否有办法检查总线是否处于"不良"状态、以及是否应终止循环?
您好、Kustaa、
为了有一个停止条件、SDA 和 SCL 线路的控制器需要将它们升高到高电平(如之前的图像所示)。 如果 您指定数据和时钟线路的范围、但没有发生这种情况、则将不会获得停止条件、并且 STP 位也不会被清除。
除了实现超时之外,是否有其他方法可以检查总线是否处于"坏"状态以及是否应终止循环?
[/报价]您可以向 while 循环添加一些逻辑来确定此情况、例如、如果需要、通过运行带有 CPU 计时器的计数器来创建某种超时。 我不认为有这样的硬件、因此您需要进行软件实施。
此致、
阿米尔·奥马尔