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.

[参考译文] MSP430I2041:不带标志轮询的 I2C 实现

Guru**** 2589245 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/727736/msp430i2041-i2c-implementation-without-with-flag-polling-only

器件型号:MSP430I2041

你好!

我正在开发一个可移植 I2C 库、该库应依赖可在 G2553至 I2041器件上找到的通用标志:我现在仅选择 TX、RX 和 NACK 标志。

然而、这个问题的目的是为了更好地了解 I2C 的运行、而不管所选的 MCU 是什么。 我在 I2C 寄存器和主操作流程图中阅读了三个或四个用户指南、但仍然不清楚应该如何以及何时复位标志。

这是参考方案(eUSCI I2C 模式、来自 SLAU335):

 

根据这项计划,我得出了以下结论,并编写了一个测试代码。 如果我错了、请告诉我。 
  1. 当我置位 UCTR 时、开始序列(连同从器件地址)被发送。 UCTXIFG 变为1、这意味着我可以在 UCBxTXBUF 中写入数据(TX 标志轮询)
  2. 如果并且只有在 UCBxTXBUF 中写入了某个内容、从器件才可以 ACK /否定应答地址字节、因此在写入数据后、我必须清除 UCTXIFG、检查 UCNACKIFG、并最终给出停止或启动条件。 因此、一个 ACK/NACK 要求在启动条件之后立即在 TXBUF 中写入一些内容。
  3. 在 TXBUF 写入之后、只有当我决定是发送另一个字节还是发出启动/停止条件时、UCTXIFG 才会被置位。
  4. 只有当我执行另一个 TXBUF 写入或一个启动/停止条件时、数据字节后的 ACK/NACK 才会出现。
因此、为了发送多个字节、我编写了此代码、但只能使用一个数据字节: 


char I2C_Send (unsigned char Slave_Address、unsigned char ByteNum、unsigned char * TxArrayAddr)
{

unsigned int txBuf_index=0;

UCB0I2CSA =从器件地址; //地址分配
UCB0IFG &=~(UCTXIFG + UCNACKIFG);//标志清零

UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX、启动条件
//UCB0IFG &=~ UCTXIFG; // Azzero UCTXIFG (si alza Solo Dopo l'ack)

while (!(UCB0IFG & UCTXIFG));// while TXIFG = 0

while (txBuf_index <(ByteNum - 1))
{
UCB0IFG &=~ UCTXIFG;// BO
UCB0TXBUF = TxArrayAddr[txBuf_index+];//填充 TxBuffer (从器件 CAN ACK / NACK)

while (!(UCB0IFG & UCTXIFG)) // Mbentre UCTXIFG è 0、
{
IF (UCB0IFG 和 UCNACKIFG) // se evo ricun Nack,ESCO。
{
UCB0CTL1 |= UCTXSTP; //发出停止
返回1;
}
}
IF (UCB0IFG 和 UCNACKIFG) // se evo ricun Nack,ESCO。
{
UCB0CTL1 |= UCTXSTP; //发出停止
返回1;
}
// se è uno (Posso trasmettere anche il sondo 字节)
//UCB0IFG &=~ UCTXIFG; //标志清除
}

UCB0IFG &=~ UCTXIFG;// BO
UCB0TXBUF = TxArrayAddr[txBuf_index++];
while (!(UCB0IFG & UCTXIFG)) // Mbentre UCTXIFG è 0、
{
IF (UCB0IFG 和 UCNACKIFG) // se evo ricun Nack,ESCO。
{
UCB0CTL1 |= UCTXSTP; //发出停止
返回1;
}
}


UCB0CTL1 |= UCTXSTP;

返回0;
}

我缺少什么? 是否明显有问题、我没有抓住它? 在两个字节后、我接收到一个 NACK 、但它将忽略它。

提前感谢您!





  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    很抱歉、UCTR、UCTR 和 UCTXSTT
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Mirco、

    通常、对于 USCI 模块、您不必轮询复位标志。 USCI 模块负责大多数 I2C 操作。 对于轮询解决方案、在假设您知道事务看起来像(又称长度)并且只与另一个器件通信的情况下、大多数操作只需要 TX、RX 和启动标志。 如果某些命令上的长度可变、则可能需要添加停止标志、但通常情况下、如果后面有另一个命令、则会执行重复启动。 您只需在事务的地址阶段轮询 NACK 标志、以确保与正确的终端设备通信并准备好接收命令。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用用户="Jace H">您好、Mirco、

    通常、对于 USCI 模块、您不必轮询复位标志。 USCI 模块负责大多数 I2C 操作。 对于轮询解决方案、在假设您知道事务看起来像(又称长度)并且只与另一个器件通信的情况下、大多数操作只需要 TX、RX 和启动标志。 如果某些命令上的长度可变、则可能需要添加停止标志、但通常情况下、如果后面有另一个命令、则会执行重复启动。 您只需在事务的地址阶段轮询 NACK 标志、以确保与正确的终端设备通信并准备好接收命令。

    [/报价]

    谢谢!

    抱歉、"轮询复位标志"是什么意思? 我是否必须手动清除标记?

    其理念是创建一个动态库、该库可以接收"n"个字节、并且可以管理 nack 而不会卡住。

    另一个问题:只有当我执行以下三个操作之一时、从器件才能 ACK /否定应答:在 txbuf 中写入一个字节、设置 STP 或 STT。 是这样吗? 如果是、如果 TXIFG 仅在 ACK / NACK 之后才会上升、我何时必须写入下一个数据字节?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    米尔科

    我想我误解了你刚才提出的有关复位的问题。 在 eUSCI 模块中、所有中断标志被自动清零、但是与特定的用户操作相关。 例如、当 TXBUFF 被填满时、TXIFG 标志被清零、并且一旦 RXBUFF 被读出、RXIFG 被清零。

    在从器件可以进行回送/否定应答的尽可能长的时间内、您必须始终阅读 I2C 规范文档。

    我知道:
    当主器件发送时:
    从器件在接收到一个地址后可以 ACK / NACK。 从器件也应在接收每个数据字节后进行 ACK /否定应答

    主机接收时:
    从器件在接收到一个地址后可以 ACK / NACK。 之后、主 ACKS/NACK 取决于它们是要继续传输还是要停止传输以及停止或重复启动。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢! 我的疑虑几乎已经结束了...

    请看上面方案的第一部分、在"a"方框之前、它说"时钟被拉伸、直至数据可用"。 每个数据字节后、时钟将被扩展?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mirco、

    根据 I2C 规范、从器件可以延长来自传入数据字节的任何位的时钟、直到被告知从器件准备好接收数据。 但实际上、它通常是数据流的第七位。 但是、为了回到您的问题、从器件可以在从主器件传入的任何数据字节上拉伸时钟。