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 主机外设(不是无限的 while 循环)。
为此、我需要学习如何使用具有中断的 TI HalCoGen I2C API。
遗憾的是、我没有找到任何示例:
- TI e2e 搜索功能未显示任何讨论此主题的结果
-正式文件不包含使用 HalCoGen 生成代码的示例
- HalCoGen 示例文件夹 有0提到 i2cNotification
所以我现在转到这个论坛:^)
——
我主要寻找有关如何处理待机问题的
- 如何在 i2cNotification 中正确处理 STOP ?
- 如何正确处理 i2cNotification 中的错误?
- 如何适当地等待总线做好准备,然后再做其他事情?
下面是我的代码:
static volatile bool g_rx_done = false; static volatile bool g_tx_done = false; int i2c_transmit(i2cBASE_t *base, // uint8_t slave_address, size_t data_size, uint8_t const data[data_size]) { if (i2cIsMasterReady(base) != true) { return -1; //< Busy } g_tx_done = false; i2cSetSlaveAdd(base, slave_address); i2cSetDirection(base, I2C_TRANSMITTER); i2cSetMode(base, I2C_MASTER); i2cSetCount(base, data_size); i2cSetStop(base); i2cSetStart(base); i2cSend(base, data_size, data); return 0; } bool i2c_is_transmit_done(i2cBASE_t *base) { return i2cIsMasterReady(base) && g_tx_done; // } int i2c_start_receiving(i2cBASE_t *base, // uint8_t slave_address, size_t data_size, uint8_t data[data_size]) { if (i2cIsMasterReady(base) != true) { return -1; //< Busy } g_rx_done = false; i2cSetSlaveAdd(base, slave_address); i2cSetDirection(base, I2C_RECEIVER); i2cSetMode(base, I2C_MASTER); i2cSetCount(base, data_size); i2cSetStop(base); i2cSetStart(base); i2cReceive(base, data_size, data); return 0; } bool i2c_is_receive_done(i2cBASE_t *base) { return i2cIsMasterReady(base) && g_rx_done; // } void i2cNotification(i2cBASE_t *base, uint32 flags) { if (flags & I2C_SCD_INT) //< Stop condition detect { i2cClearSCD(base); } if (flags & I2C_TX_INT) //< Transmit data ready { g_tx_done = true; } if (flags & I2C_RX_INT) //< Receive data ready { g_rx_done = true; } if (flags & I2C_AL_INT) //< Arbitration lost (AL) { } if (flags & I2C_NACK_INT) //< No acknowledgement (NACK) { } if (flags & I2C_ARDY_INT) //< Register access ready (ARDY) { } if (flags & I2C_AAS_INT) //< Address as slave (AAS) { } }
欢迎提供任何建议。
此致、
加布里埃尔
尊敬的 Gabriel:
我同意您的看法、即在 i2c 中没有经过良好测试的中断示例。
我建议您参考以下两个可能在某种程度上对您有帮助的主题。
(+) TMS570LC4357:I2C 总线示例代码-基于 Arm 的微控制器论坛-基于 Arm 的微控制器- TI E2E 支持论坛
(+) CCS/TMS570LS1227:I2C -与中断通信-基于 Arm 的微控制器论坛-基于 Arm 的微控制器- TI E2E 支持论坛
- 如何在 i2cNotification 中正确处理 stop?
这取决于您的要求。
例如、如果我想向从机发送一些 n 个字节、并想发送 STOP 条件、那么我们可以在设置 count 个字节后、在调用 i2csend 函数之前、按照您所做的那样设置 STOP 条件。
i2cSetSlaveAdd(base, slave_address); i2cSetDirection(base, I2C_TRANSMITTER); i2cSetMode(base, I2C_MASTER); i2cSetCount(base, data_size); i2cSetStop(base); i2cSetStart(base); i2cSend(base, data_size, data);
这种情况下发生的情况是、它将在中断模式下发送配置的字节数(如果我们启用)、然后它将自动发送停止条件。
同样的收货程序。
但是、在某些情况下、我们可能需要在不发送停止条件的情况下重新启动 i2c。
例如、请参阅上文中的温度传感器读取方法、在这里、我们在两个传感器之间没有停止条件的情况下进行发送和读取。 在这些情况下、我们不应在配置字节数后发送停止条件。 而不是在完成发送字节后、我们应该再次设置起始条件并执行接收操作、然后我们可以发送停止条件。
我想以非阻塞的方式使用 I2C 主设备外设(while 循环不是无限的)。
尽管我们不想像轮询方法中的无限循环那样等待、但还是需要在 while (1)上构建状态机、以检查状态并执行下一个操作。
例如、我为上述温度读数程序提供代码。
int state =0; unsigned char Command_Byte = 0xAA; bool prev_cmd = false; unsigned char Temperature[2]; int main(void) { i2cInit(); while(1) { I2c_Temperature_Reading(); /*Other Tasks*/ } return 0; } void I2c_Temperature_Reading(void) { switch(state) { case 0: i2cSetSlaveAdd(base, slave_address); i2cSetDirection(base, I2C_TRANSMITTER); i2cSetMode(base, I2C_MASTER); i2cSetCount(base, 1); i2cSetStart(base); i2cSend(base, data_size, &Command_Byte); state =1; break; case 1: if(prev_cmd == true) { prev_cmd = false; i2cSetSlaveAdd(base, slave_address); i2cSetDirection(base, I2C_RECEIVER); i2cSetMode(base, I2C_MASTER); i2cSetCount(base, 2); i2cSetStop(base); i2cSetStart(base); i2cReceive(base, data_size, Temperature); } state =2; break; case 2: if(prev_cmd == true) { prev_cmd = false; /*Now we can Necessary operation on temperature data like printing/displaying/using for other tasks*/ /*If we want to read temperature again then we should call case-0 again*/ state =0; } break; default: break; } } void i2cNotification(i2cBASE_t *base, uint32 flags) { if (flags & I2C_SCD_INT) //< Stop condition detect { i2cClearSCD(base); } if (flags & I2C_TX_INT) //< Transmit data ready { g_tx_done = true; prev_cmd = true; } if (flags & I2C_RX_INT) //< Receive data ready { g_rx_done = true; prev_cmd = true; } if (flags & I2C_AL_INT) //< Arbitration lost (AL) { state =0; } if (flags & I2C_NACK_INT) //< No acknowledgement (NACK) { } if (flags & I2C_ARDY_INT) //< Register access ready (ARDY) { } if (flags & I2C_AAS_INT) //< Address as slave (AAS) { } }
如上面的示例所示、我们没有等到发送字节、而只是验证前一条命令是否成功执行。 那么我们要进行下一步操作。
我希望这有助于您了解和实现中断模式下的 i2c。
- 如何正确处理 i2cNotification 中的错误?
这同样取决于您的应用要求。 例如、如您在我的共享代码中所见、如果有任何仲裁、我只是将重新启动温度读取程序。
--
谢谢。此致、
Jagadish。
Jagadish、您好!
感谢您的回答。
如果我想向从机发送 n 个字节并想发送 STOP 条件,那么我们可以在设置 count 字节后和调用 i2csend 函数之前设置 stop 条件,就像您所做的那样。
感谢您解释如何使用 i2cSetStop()函数。
我仍然不确定如何处理 停止条件检测标志。
在您的示例中、我看到您还在中断中清除了 SCD。 这总是一个好主意吗?
如果通信中断、并且我们从未接收到 I2C_SCD_INT 中断、该怎么办? 我们如何从这种情况中恢复?
if (flags & I2C_SCD_INT) //< Stop condition detect { i2cClearSCD(base); }
例如、我为上述温度读数程序提供代码。
[/报价]感谢您分享此代码。
我看到、当您收到仲裁丢失(AL)时、您重置了状态机。
为什么你不做同样的 NACK ?
那么 ARDY 和 AAS 呢?
我们应该如何处理它们?BTW、在您的状态机中、
Fullscreen1state =2;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXstate =2;应该在 IF 条件内?
此致、
加布里埃尔
我还有另一个问题要问 Jagadish。
我不明白这些 API 之间的区别:
bool i2cIsMasterReady(i2cBASE_t *i2c); bool i2cIsBusBusy(i2cBASE_t *i2c); uint32 i2cIsTxReady(i2cBASE_t *i2c); uint32 i2cIsRxReady(i2cBASE_t *i2c);
它们之间有什么细微差别?
这些轮询 API 与接收 I2C_TX_INT 或 I2C_RX_INT 中断之间有什么区别?
尊敬的 Gabriel:
这些轮询 API 与接收 I2C_TX_INT 或 I2C_RX_INT 中断之间有何区别?
它们之间没有区别。 唯一需要注意的是、如果您正在以轮询方式开发代码、则必须使用这些 API。
例如、如下所示、突出显示的代码:
在该轮询代码中、要向数据寄存器写入一个新字节、我们只是等待前一个字节通过轮询 I2C_TX_INT 标志来移位。 如果设置该标志、则意味着先前写入数据寄存器的数据值已移到移位寄存器中、我们可以向其中写入一个新值。 在此驱动程序直接验证 I2C_TX_INT 位、但我们也可以使用"i2cIsTxReady" API、而不是在此处。
但如果是中断模式、我们无需轮询该位、而只需 在 IMR 寄存器中启用 I2C_TX_INT 中断标志。 如果我们这样做、如果数据寄存器值移动到移位寄存器、则我们会立即获得中断和控制权将转移到处理程序代码、因此我们可以向数据寄存器写入新值。
I2C_RX_INT 和 i2cIsRxReady API 也具有类似的行为。
i2cIsBusBusy -此 API 在轮询模式下也有助于识别已发送的所有字节或已接收的所有字节。 我的意思是、在发送起始条件后、该忙标志将被设置、在接收到停止条件后、它将被清除。
因此、它可按以下方式使用:
如您所见、在设置要传输的字节数并调用 i2cSend API 后、我们只需轮询 i2cby 标志以识别传输是否已完成。
i2cIsMasterReady-每当生成停止条件时、这意味着一个事务完成、则第一个 BB (总线忙)标志将被清除、然后 MST 位也被清除。
在开始新事务之前、必须清除该位、如果不清除该位、则我们不应开始新事务。
每当我们开始新事务时、都需要添加此检查。 例如您可以看到上面的代码、对于第一次交易、我们没有使用此检查、但在开始第二次交易之前、我们将使用此检查来确保第一次交易是否完成。 也可以在代码的中断模式下使用此检查、在开始第二个事务之前的第一个事务之后、最好检查此条件。
--
谢谢。此致、
Jagadish。
Jagadish、您好!
感谢您的回答。
它使 i2cIsMasterReady 更清晰。
您共享的这个 HalCoGen 代码具有一个有趣的含义。
如果我发送的消息只有1个字节、则永远不会接收 I2C_TX_INT、这意味着 prev_cmd 将永远不会设置为 True。
在不使用轮询的情况下、如何判断传输是否已完成、是否从未产生任何中断?
此外、对于错误管理:
当我发送格式错误的消息时、我收到一个 NACK。
接收到 NACK 后、似乎无法从它中恢复:i2cIsMasterReady 函数始终返回 False。
我们如何从这类错误中恢复总线?
尊敬的 Gabriel:
您共享的这个 HalCoGen 代码有一个有趣的含义。
是的、回答正确。 存在错误、请参阅 QJ 的以下权变措施。
(+) TMS570LS1115:I2C 中断不工作-基于 Arm 的微控制器论坛-基于 Arm 的微控制器- TI E2E 支持论坛
--
谢谢。此致、
Jagadish。
尊敬的 Gabriel:
当我发送格式错误的消息时,我收到一个 NACK。
接收到 NACK 后、似乎无法从它中恢复:i2cIsMasterReady 函数始终返回 False。
我们如何从这类错误中恢复总线?
为什么不启用 NACK 中断、如果生成了该中断、则尝试重新启动通信。
重启通信方式、首先发送一个停止条件、然后再发送启动和数据等。
--
谢谢。此致、
Jagadish。
是的、回答正确。 存在错误、请参阅 QJ 的以下权变措施。
[/报价]这是非常有帮助的,谢谢!
@我有与 μ suser5967417相同的问题:RX 中断可以工作、但 TX 中断不工作 。
当我在函数库中放置一个断点时、 i2c 中断 函数 I 没有接收到任何 TXRDY 中断。以下是我的 HalCoGen I2C 配置:
引脚多路复用器
外设
ISR
你知道为什么我不会收到 TXRDY 吗?
[/quote]为什么不启用 NACK 中断、如果生成了该中断、则尝试重新启动通信。
[/报价]有趣。 我今天将对此进行测试。
感谢你的帮助。
尊敬的 Gabriel:
您有什么想法为什么我不会收到 TXRDY 吗?
您连接到主 i2c 的从器件是什么?
用于 i2c 线路的上拉电阻器值是什么?
我能拿到您的整个项目进行验证吗?
--
谢谢。此致、
Jagadish。
Jagadish、您好!
您连接到主 i2c 的从器件是什么?
[/报价]我已使用 SHT3x-DIS 和 PT7C4563进行了测试。
[/quote][/quote]用于 i2c 线路的上拉电阻器值是什么?
[/报价]硬件已使用阻塞 i2c 代码进行验证。 这会是一个硬件问题、这对我来说是一个惊喜。
[/quote]
尊敬的 Gabriel:
确保从器件向主器件发送 ACK。
如果从器件不向主器件发送 ACK、则主器件不会向从器件发送任何数据。
例如、如上文中所示 pic、主器件向从器件发送了0x08地址、但从器件不会向主器件发送任何 ACK、因此主器件不会向从器件发送任何其他数据。
如果您在上面看到、pic 主器件会将0x4C 地址发送给从器件、而从器件提供 ACK 和主器件会进一步移动数据字节。 为了确保主从设备之间的通信正确无误、请从设备端确保完成以下操作。
1.确保主器件 SDA 和 SCL 线路与从器件 SDA 和 SCL 线路正确连接。
2.确保在 SDA 和 SCL 线上连接外部上拉电阻。 上拉不应过高或过小、最好在2.2K 到4.7K 之间。
(+) TMS570LS3137:I2C 无法正常工作-基于 Arm 的微控制器论坛-基于 Arm 的微控制器- TI E2E 支持论坛
3.确保从主设备发送正确的从设备地址。
--
谢谢。此致、
Jagadish。
Jagadish、您好!
感谢您的反馈。
由于 i2c 传输运行良好、因此我认为它与硬件无关。
我没有 验证从器件的 ACK、但由于我正确地从从从器件接收到多个字节、我似乎不太可能不会接收 NACK。
您确定不可能是另外一个 HalCoGen 错误吗?
在 这个线程中、看起来即使对于经修改的代码、用户也无法接收 TX ISR。
此致、
加布里埃尔
Jagadish gundavarapu 如果你想,我可以创建一个单独的线程,因为我们正在输入一个新的主题: HalCodeGen TX ISR 问题。
请创建新主题。 将所有内容合并到一个问题中可能并不好。
好的、下面是新主题: e2e.ti.com/.../rm46l852-i2c-txrdy-interrupts-never-fire-while-the-rxrdy-works-fine