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.

[参考译文] MSP432P401R:I2C -当我应该接收1时接收2个字节-使用 Driverlib masterReceiveSingleByte

Guru**** 2562120 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/595409/msp432p401r-i2c---receiving-2-bytes-when-i-am-supposed-to-be-receiving-1---using-driverlib-masterreceivesinglebyte

器件型号:MSP432P401R

我正在尝试与 BQ27441电池电量监测计通信。 我的 I2C 通信在大多数情况下工作正常、但代码中有一个部分需要接收单字节校验和(其他情况和错误发生)。 当我使用 driverlib 函数接收单个字节时、我会得到2个字节!

我已附加了 driverlib 安装代码、问题代码和中断代码。

我还包括了 I2C 线路上发生的情况的逻辑分析仪输出。 正如您在下面看到的、我为寄存器写入0x60、然后我尝试读取一个字节、我返回0x00+ACK 和0x00+NACK。  

设置:

  • I2C 引脚6.6和6.7
  • 1K 上拉
  • 100kbps
  • 总线上只有 BQ27441
  • 该代码最初来自驱动程序库示例、但经过大量修改、以满足我们的需求

问题代码:

//发送块校验和命令以检查校验和
EUSCI_TXBuffer &= 0x00; //清除发送缓冲区
MAP_I2C_masterSendSingleByte (EUSCI_MODULE、BQ27441_extended_CHECKSUM);

num_of _REC_bytes = 1;
MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Receive_mode); //设置为接收模式
MAP_I2C_enableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //启用接收中断
uint8_t OLD_CSUM = MAP_I2C_ReceivmasterSingleByte (EUSCI_MODULE);
rxFlag = 0;
MAP_I2C_DisableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //禁用接收中断


MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Transmit 模式); //将 I2C 模式设置为发送
xferIndex = 0; //清除 RXData 索引

设置代码:

void FuelGauge_Setup()
{
//为 I2C 选择端口6 -将引脚4、5设置为输入主模块功能(UCB1SIMO/UCB1SDA、UCB1SOMI/UCB.S)。
#if SDApin =GPIO_PIN6 && I2Cport =GPIO_PORT_P6
MAP_GPIO_setPeripheralModuleFunctionInputPin (I2Cport、SDApin + SCLpin、GPIO_secondary 模块_function);
#else
MAP_GPIO_setPeripheralModuleFunctionInputPin (I2Cport、SDApin + SCLpin、GPIO_PRIMARY_MODULE_Function);
#endif
//以100kbs 的速率将 I2C 主设备初始化为 SMCLK,而不自动停止
MAP_I2C_initMaster (EUSCI_MODULE、&i2cConfig);

//指定从机地址
MAP_I2C_setSlaveAddress (EUSCI_MODULE、BQ27441_I2C_ADDRESS);

//将主机设置为发送模式
MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Transmit 模式);

//启用 I2C 模块以启动操作
MAP_I2C_enableModule (EUSCI_MODULE);

//启用和清除中断标志,以便在定义页中产生发送中断
MAP_I2C_clearInterruptFlag (EUSCI_MODULE、EUSCI_B_I2C_Transmit INTERRUPT0 + EUSCI_B_I2C_Receive_INTERRUPT0);

//启用主机接收中断
MAP_Interrupt_enableInterrupt (EUSCI_moduleINT);
} 

中断代码:

void EUSCIB3_Receive (void)
{
uint_fast16_t status; //标志状态

= MAP_I2C_getEnabledInterruptStatus (EUSCI_MODULE); //抓取触发
的任何标志 MAP_I2C_clearInterruptFlag (EUSCI_MODULE、STATUS); //清除被触发的中断标志

IF (STATUS & EUSCI_B_I2C_Receive_INTERRUPT0) //如果接收的中断标志已经被触发
{
if (NUM_OF_REC_Bytes > 1) //如果接收字节数设置为大于1的值
{
if (xferIndex = NUM_OF_REC_Bytes - 2) //当 xferIndex 位于第三个到最后一个字节上时
{
MAP_I2C_masterReceiveMultiByteStop (EUSCI_MODULE);
RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_MODULE); //接收字节并将字节存储到 RXData
}
否则、如果(xferIndex = NUM_OF_REC_Bytes - 1) //当 xferIndex 位于第二个到最后一个字节上时
{
RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_MODULE); //接收字节并将字节存储到 RXData 中
MAP_I2C_DisableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //禁用接收中断
MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Transmit 模式); //将 I2C 模式设置为发送
xferIndex = 0; //清除 RXData 索引
rxFlag = 1; //将接收中断标志置为高电平
num_of _REC_bytes = 0; //清除 NUM_OF_REC_Bytes
}
其他 //执行直到 xferIndex 在距 NUM_OF_REC_Bytes 长度2的范围内
{
RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_MODULE);
}
}否则{
rxFlag = 1; //将接收中断标志置为高电平
num_of _REC_bytes = 0; //清除 NUM_OF_REC_Bytes
}
}


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

    没有 driverlib 函数来接收具有中断的单字节。 理论上,可以在之后立即调用 I2C_masterReceiveStart(),然后调用 I2C_masterReceiveMultiByteStop();然后中断处理程序应该使用 I2C_masterReceiveSingle()。

    但是、继续使用 I2C_masterReceiveSingleByte()可能会更容易、而不仅仅是启用中断。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Clemens、感谢您的回复。 我已经用相同的结果尝试了以下两种方法(接收到2个字节)。 我出了什么问题?

    //发送块校验和命令以检查校验和
    EUSCI_TXBuffer &= 0x00; //清除发送缓冲区
    MAP_I2C_masterSendSingleByte (EUSCI_MODULE、BQ27441_extended_CHECKSUM);
    MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Receive_mode); //设置为接收模式
    MAP_I2C_DisableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //禁用接收中断
    uint8_t OLD_CSUM = MAP_I2C_ReceivmasterSingleByte (EUSCI_MODULE); 

    //发送块校验和命令以检查校验和
    EUSCI_TXBuffer &= 0x00;
    MAP_I2C_masterSendSingleByte (EUSCI_MODULE、0x60);
    
    num_of _REC_bytes = 1;
    MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Receive_mode); //设置为接收模式
    MAP_I2C_enableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //启用接收中断
    MAP_I2C_masterReceiveStart (EUSCI_MODULE); //开始接收
    MAP_I2C_masterReceiveMultiByteStop (EUSCI_MODULE);
    xferIndex = 0; //将 RXData 索引设置为0
    while (rxFlag!= 1); //等待接收到接收中断标志
    rxFlag = 0;
    uint8_t OLD_CSUM = RXData[0]; 

    第二次试验的中断代码如下所示:

    void EUSCIB3_Receive (void)
    {
    uint_fast16_t status; //标志状态
    
    = MAP_I2C_getEnabledInterruptStatus (EUSCI_MODULE); //抓取触发
    的任何标志 MAP_I2C_clearInterruptFlag (EUSCI_MODULE、STATUS); //清除被触发的中断标志
    
    IF (STATUS & EUSCI_B_I2C_Receive_INTERRUPT0) //如果接收的中断标志已经被触发
    {
    if (NUM_OF_REC_Bytes > 1) //如果接收字节数设置为大于1的值
    {
    if (xferIndex = NUM_OF_REC_Bytes - 2) //当 xferIndex 位于第三个到最后一个字节上时
    {
    MAP_I2C_masterReceiveMultiByteStop (EUSCI_MODULE);
    RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_MODULE); //接收字节并将字节存储到 RXData
    }
    否则、如果(xferIndex = NUM_OF_REC_Bytes - 1) //当 xferIndex 位于第二个到最后一个字节上时
    {
    RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_MODULE); //接收字节并将字节存储到 RXData 中
    MAP_I2C_DisableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //禁用接收中断
    MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Transmit 模式); //将 I2C 模式设置为发送
    xferIndex = 0; //清除 RXData 索引
    rxFlag = 1; //将接收中断标志置为高电平
    num_of _REC_bytes = 0; //清除 NUM_OF_REC_Bytes
    }
    其他 //执行直到 xferIndex 在距 NUM_OF_REC_Bytes 长度2的范围内
    {
    RXData[xferIndex++]= MAP_I2C_ReceivmasterMultiByteNext (EUSCI_MODULE);
    }
    }否则{
    RXData[0]= EUSCI_B3->RXBUF;
    rxFlag = 1; //将接收中断标志置为高电平
    num_of _REC_bytes = 0; //清除 NUM_OF_REC_Bytes
    }
    }
    
    
    
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    EUSCI_TXBuffer &= 0x00; //清除发送缓冲区 

    这不会清除任何内容;对 TX 缓冲区的任何写入访问都会发送一个字节。

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

    Clemens、感谢您与我一起处理这个问题。

    如果我不写入该行、则 masterSendSingleByte (有时是多字节发送)将发送0xFF。

    突出显示的器件(绿色和黄色)对应于我尝试发送0x60 (BQ27441_extended_CHECKSUM)并对其进行读取的位置。

    //设置要访问的数据锁
    EUSCI_TXBuffer &= 0x00; //该块仅在 EISCI+TXBuffer 为&且为0时有效
    MAP_I2C_masterSendMultiByteStart (EUSCI_MODULE、BQ27441_extend_DATABLOCK);
    MAP_I2C_masterSendMultiByteNext (EUSCI_MODULE、0x00);
    MAP_I2C_masterSendMultiByteStop (EUSCI_MODULE);
    
    
    
    //发送块校验和命令以检查校验和
    ///EUSCI_TXBuffer &= 0x00; //清除发送缓冲区
    MAP_I2C_masterSendSingleByte (EUSCI_MODULE、BQ27441_extended_CHECKSUM);
    MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Receive_mode); //设置为接收模式
    MAP_I2C_DisableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //禁用接收中断
    uint8_t OLD_CSUM = MAP_I2C_ReceivmasterSingleByte (EUSCI_MODULE); 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    无法查看是否有正确的开始条件;请放大更多内容、并在事务之前添加等待。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这是代码的一部分(包含在下面)、其中包含前后的延迟。 SDA 和 SCL 线在1秒内保持高电平、然后在下一位代码之前执行此操作(图2)。 我还包括了 Saleae 逻辑采集。

    图2.

    延迟(80000);
    //发送块校验和命令以检查校验和
    ///EUSCI_TXBuffer &= 0x00; //清除发送缓冲区
    MAP_I2C_masterSendSingleByte (EUSCI_MODULE、BQ27441_extended_CHECKSUM);
    MAP_I2C_setMode (EUSCI_MODULE、EUSCI_B_I2C_Receive_mode); //设置为接收模式
    MAP_I2C_DisableInterrupt (EUSCI_MODULE、EUSCI_B_I2C_Receive_INTERRUPT0); //禁用接收中断
    uint8_t OLD_CSUM = MAP_I2C_ReceivmasterSingleByte (EUSCI_MODULE);
    延迟(80000); 

    e2e.ti.com/.../Saleae-Logic-Capture.zip

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

    这很奇怪。 要排除各种 USCI 勘误表、您可以尝试使用(与同步的时钟) MCLK 作为时钟源吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我该怎么做? 我不太善于确定时钟...

    这是我当前拥有的配置:

    // I2C 主配置参数
    const eUSCI_I2C_MasterConfig i2cConfig =
    {
    EUSCI_B_I2C_CLOCKSOURCE_SMCLK、 // SMCLK 时钟源
    80000、 // SMCLK = 8MHz
    EUSCI_B_I2C_SET_DATA_RATE 100KBPS、 //所需的100kHz I2C 时钟
    0、 //无字节计数器阈值
    EUSCI_B_I2C_NO_AUTO_STOP //无自动停止
    }; 

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

    这就是我们设置时钟的方式

    //配置时钟
    MAP_CS_setDCOFrequency (CLK_FQ);//将 DCO (时钟)设置为指定的时钟速度
    
    MAP_CS_initClockSignal (CS_SMCLK、CS_DCOCLK_SELECT、CS_CLOCK _DIVIDER_1);//将 SMCLK 连接到 DCO
    MAP_CS_initClockSignal (CS_ACLK、CS_VLOCLK_SELECT、CS_Clock_divider _1);//将 ACLK 连接到 VLO 
    #define CLK_FQ8000000//<时钟频率@注意您必须手动更改 UART 波特率分频器! 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    假设 MCLK 也使用 DCO、这可能与这些勘误表无关。

    我在代码中看不到任何明显的问题。
    您能否返回到一些简单的 driverlib 示例、并检查它是否起作用?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我可以、但我在周一之前不在办公室。 我会在那之后发布。

    Clemens、感谢您迄今为止提供的所有帮助!
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    该示例中的 I2C 在运行时工作正常、但它使用多字节起始、下一个等
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    下面是有关仅1字节 I2C 通信的附加讨论: e2e.ti.com/.../576600

    Chris