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.

[参考译文] MSP430FR5730:I2C问题

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/576425/msp430fr5730-i2c-issue

部件号:MSP430FR5730

您好,

我正在尝试为MMA8452 (加速计)实施I2C驱动程序,如下所示

我编写了以下驱动程序。 但是,我从UC得到了一些非常奇怪的输出。 当我尝试从总线检索单字节数据时,它总是尝试获取两个字节。 在UC发出第二个字节的时钟后,I2C总线被锁定。  摆脱锁定的唯一方法是重启主板。 为什么UC尝试获取第二个字节? 我甚至特别使用 了EUSCI_B_I2C_masterReceiveSingleByte,但UC仍尝试获取第二个字节。

uINT8_t I2c_read_byte(uint8_t slaver_address, uint8_t reg_address, uint8_t len, uint8_t *data){
uINT8_t i;
uINT16_t retry=0x1000;

//启用I2C模块以启动操作
EUSCI_B_I2C_ENABLE (EUSCI_B0_BASE);

EUSCI_B_I2C_setSlaveAddress (EUSCI_B0_BASE,SLAVE_ADDRESS);

//在传输模式下设置
EUSCI_B_I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_mode);

EUSCI_B_I2C_clearInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_INTERRUPT0);

/*发送注册地址*/
EUSCI_B_I2C_masterSendMultiByteStart (EUSCI_B0_BASE,REG_ADDRESS);

//传送中断标志轮询。
while (!(HWREG16 (EUSCI_B0_BBASE + OFS_UCBxIFG)& UCTXIFG)&& retry)

重试--;
}

如果(!retry){

返回I2C_Time_Out;
}


/*在接收模式*/中设置eUSI_B0
EUSCI_B_I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_Receive_mode);

DATA[0]=EUSI_B_I2C_masterReceiveSingleByte(EUSI_B0_BAC_base);

/*if(len==1){
DATA[0]=EUSI_B_I2C_masterReceiveSingleByte(EUSI_B0_BAC_base);
}
否则

EUSCI_B_I2C_masterReceiveStart (EUSCI_B0_BASE);
对于(i=0;i<len-1;i++)
Data[I]= EUSI_B_I2C_masterReceiveMultiByteNext(EUSI_B0_base);
Data[len-1]=EUSI_B_I2C_masterReceiveMultiByteFinish(EUSI_B0_BASE;
}*/

返回0;
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您不需要调用EUSCI_B_I2C_setMode();发送/接收函数会自动设置此值。

    为什么要调用EUSCI_B_I2C_clearInterrup()? 您是否确实使用了中断?

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

    我看到所有这些示例代码都使用EUSCI_B_I2C_setmode在写入/读取之前更改模式。

    我确实启用了I2C上的中断。

    我轮询TXIFG的原因是 EUSCI_B_I2C_masterSendMultiByteStart不会在返回前等待传输完成。 我必须确保在读取数据之前完成写入数据。

    但是,我并不认为所有这些都与UC读取两个字节相关,而是被告知具体读取一个字节。 其他人是否曾遇到过此问题?

    此致

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    所有这些示例代码都是错误的(它们包含多余的代码)。

    如果使用的是中断,请显示中断处理程序以及启用了哪些中断处理程序。 然后,您将无法轮询中断标志,因为处理程序在主程序看到它之前就被调用了。

    为什么您认为需要等待传输完成?

    我不知道为什么会有第二个字节;理论上,EUSCI_B_I2C_masterReceiveSingleByte()设置UCTXSTP标志,这应该会导致nack。 中断处理程序可能会执行某些操作。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我的最后一个回复似乎丢失了。

    我做了几次测试。 我发现,如果I2C写入在I2C读取之前发送而没有停止位, 它将触发2字节读取问题。 I2C读取中的停止位丢失,因此I2C总线被锁定。 另一个停止位必须单独发送,以便I2C总线不会被锁定。

    中断处理程序中尚未出现任何内容。 我禁用了所有中断,但仍然遇到相同的问题。

    如果我不等待发射完成并调用接收功能,它将导致I2C控制器在发射过程中切换模式。 传输将被打乱。 我已经掌握了这个案例。 如果不需要等待,则在发送从属地址后立即发送两个0xFF。 您需要等待切换模式。

    我最后重新编写了驱动程序,但没有调用任何函数。 基本上,我复制了函数中的所有代码,但在末尾将起始位和停止位分开。我还得到了额外的一个字节读取。 但巴士不会被锁住。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的,我知道 了一切。  在此处共享,以防其他人遇到相同的问题来为器件(例如PMBus器件或此加速计传感器(MMA8452))实施以下I2C事务。

    根本原因是MSP430微控制器中的I2C主模块始终在传输字节后期望一个起始位或停止位。 即使它从传输模式切换到接收模式。  I2C模块以比起始位更高的优先级处理停止位。 (我个人认为这是一个硬件错误。  我在TIVA处理器中的同一驱动程序中没有看到此问题)

    因此,当我从发送切换到接收时,EUSCI_B_I2C_masterReceiveSingleByte同时设置起始位和停止位。 I2C模块首先发送停止位(在示波器上捕获)。 然后,它发送起始位以触发接收进程。 因为已使用并清除停止位。 接收过程一直持续到接收缓冲区(2字节)已满。 现在,I2C总线被锁定,因为它在接收结束时等待停止位或启动位。

    要解决此问题,必须分别及时设置起始位和停止位。 首先设置起始位,然后轮询起始位。 必须在清除起始位后立即设置停止位。 否则,I2C模块将在发送第一个字节后继续运行,您将获得第二个字节的读取。 EUSCI_B_I2C_masterReceiveSingleByte需要修改以适应所有情况。  

    通过改装,我的驾驶员工作出色。

    ///////////////////////////////////////////////////////////////////////////////

    UINT8_t EUSCI_B_I2C_masterReceiveSingleByte (uint16_t baseAddress)

      //将USCI设置为接收模式

      HWREG16 (baseAddress + OFS_UCBxCTLW0)&=~UCTR;

      //开始发送

      HWREG16 (baseAddress + OFS_UCBxCTLW0)|| UCTXSTT;

     //轮询起始位

      While (HWREG16 (EUSCI_B0_BBASE + OFS_UCBxCTLW0)& UCTXSTT);

     //设置停止位

     HWREG16 (EUSSCI_B0_BASE + OFS_UCBxCTLW0)|| UCTXSTP;

      //接收中断标志轮询。

      while (!(HWREG16 (baseAddress + OFS_UCBxIFG)和UCRXIFG))

      {

        ;

      }

      //发送单字节数据。

      返回(HWREG16 (baseAddress + OFS_UCBxRXBUF));

    }