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.

[参考译文] MSP430G2553:何时在 i2c 主控模式下生成停止条件?

Guru**** 2553260 points
Other Parts Discussed in Thread: MSP430G2553

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/860596/msp430g2553-when-to-generate-stop-condition-in-i2c-master-mode

器件型号:MSP430G2553

大家好、  

当我尝试从 MPU-9250从器件接收2个或更多字节时、我正在尝试弄清楚为什么我的代码不起作用。 接收一个字节正常工作、Tx 功能也正常工作。  

如果我注释掉:

if (i2c.length = 1)
{
UCB0CTL1 |= UCTXSTP;
} 

在 ISR 的主器件接收部分、并在读取最后一个字节后置1 UCTXSTP、它就会工作。 根据用户指南、UCTXSTP 应在接收字节时置1。

示例代码也以与我所做的类似的方式执行此操作。 有什么想法吗?
/*
MSP430_i2c.c
*
*创建日期:2019年11月1日
* 作者:Wayne
*
说明:用于 msp430g2553的 I2C 驱动器、使用中断。
*/
#include 

#defineSCL_PINBIT6
#defineSDA_PINBIT7

typedef 枚举{
State_Waiting、
状态读取、
State_writing
}MSP430_i2c_state;

typedef 结构{
易失性 MSP430_i2c_state;
unsigned char slave_reg;//第一个从器件寄存器。
unsigned char slave_reg_written;// 0如果从器件寄存器尚未写入。 *
unsigned char *数据;
无符号短长度;
启用无符号字符;
}MSP430_i2c_info;

静态 MSP430_i2c_info i2c ={
.enabled = 0
};

void i2c_enable ()
{
/*初始化 USCI I2C 模块*/
BCSCTL3 |= LFXT1S_2;// VLOCLK (~12KHz)馈送 ACLK (选择 ACLK 源为内部 VLO)
UCB0CTL1 |= UCSWRST | UCSSEL_1;//将 USCI_B 保持在复位状态以进行初始化(设置 UCSWRST)&选择 ACLK
UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC; // I2C 主模式| I2C 模式
UCB0BR0 = 8;//设置 i2c 频率
UCB0BR1 = 0;
P1SEL |= SDA_PIN | SCL_PIN; //配置端口
P1SEL2 |= SDA_PIN | SCL_PIN;
UCB0CTL1 &=~UCSWRST; //释放 USCI_B 以运行(清除 UCSWRST)
IE2 |= UCB0TXIE | UCB0RXIE;//通过 UCxRXIE 和/或 UCxTXIE 启用中断(可选)


int i2c_write (unsigned char SLV_addr、unsigned char reg_addr、unsigned char 长度、unsigned const char 数据
)*
/*填充结构。 *
I2C.state = State_writing;
i2c.slave_reg = reg_addr;
I2c.slave_reg_written = 0;
I2C.data =(unsigned char*) data;
I2c.length =长度;

UCB0I2CSA = SLV_addr; //将从器件地址写入 UCB0I2CSA 寄存器
UCB0CTL0 &=~UCSLA10; // 7位从器件寻址模式
UCB0CTL1 |= UCTR + UCTXSTT; //将 UCTR 设置为 TX 模式+将 UCTXSTT 设置为生成启动条件

while (i2c.state!= State_Waiting)
{//输入带中断的 LPM0 */
_bis_SR_register (CPUOFF + GIE);
I2C.state = State_Waiting;
}

返回0;//此返回无意义。 需要返回一些错误或其他
内容}


int i2c_read (unsigned char slv_addr、unsigned char reg_addr、unsigned char length、unsigned char * data)
{
//填充结构。 */
i2c.state = State_reading;
i2c.slave_reg = reg_addr;
i2c.slave_reg_written = 0;
i2c.data = data;
i2c.length = length;

UCB0I2CSA = SLV_addr;//将从器件地址写入 UCB0I2CSA 寄存器
UCB0CTL0 &=~UCSLA10;// 7位从器件寻址模式
while (UCB0CTL1 & UCTXSTP); //确保停止条件已发送
UCB0CTL1 |= UCTR | UCTXSTT; // I2C 启动条件

while (i2c.state!= State_Waiting)
{//输入 LPM0 w/中断*/
_bis_SR_register (CPUOFF + GIE);
i2c.state = State_Waiting;
}

return 0;
}

#if defined (__TI_Compiler_version_)|| defined (__IAR_ICR_BIAS_COVERS



(void)#BIAS_BIAS_COMPLETE_COMPLETE_COMPLETOR (void)#BIAS_COMPLETE_COMPLETE_COMPLETE_COMPLETE_COMPLETE_COMPLETE_COMPLETE_TRIE_TRIE_INEST_BIST_NOW_#BIST_COMPLETE_COMPLETE_SIONENTS_BIST_INEST_VERS (nLETE)#BIST_COMPLE


#endif
{
if (IFG2 & UCB0RXIFG)//主机接收?
{
i2c.length--;
if (i2c.length)
{
* i2c.data++= UCB0RXBUF;
if (i2c.length = 1)
{
UCB0CTL1 |= UCTXSTP;
}

否则
{
* i2c.data = UCB0RXBUF;
//UCB0CTL1 |= UCB0TXIFG
;= UCB0TXIFG 和~UCB0TXIFG;//清除 TX 中断标志
__BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出 LPM0
}


否则(IFG2 & UCB0TXIFG)//主机发送?
{
switch (i2c.state)
{
case State_writing:
if (!i2c.slave_reg_writing)
{
i2c.slave_reg_write= 1;//
UCB0TXBUF = i2c.slave_reg;//发送从地址
}
否则(i2c.length)//要发送的数据?
{
char next =* i2c.data;//
i2c.data++;//递增字节
i2c.length-;//递减待发送的数据量
//写入 TXBUF 必须始终是最终操作。 //
UCB0TXBUF = NEXT;
}
否则//没有更多数据要发送?
{
UCB0CTL1 |= UCTXSTP;//生成停止条件。
IFG2 &=~UCB0TXIFG;//清除 Tx 中断标志
__BIC_SR_REGISTER_ON_EXIT (CPUOFF + GIE);
}
break;
case State_reading:
if (!i2c.slave_reg_written)
{
i2c.slave_reg_written = 1;
UCB0TXBUF = i2c.r_rev.rn



);重复启动 RX 模式。 //
UCB0CTL1 &=~UCTR;
UCB0CTL1 |= UCTXSTT;

//如果是单字节,请立即准备 STOP 信号。 //
if (i2c.length ==1)
{
//井,不是立即。 首先、我们需要确保
*已发送启动信号。
//
while (UCB0CTL1 & UCTXSTT);
UCB0CTL1 |= UCTXSTP;
IFG2 &=~UCB0TXIFG;//清除 TX 中断标志
}

中断;
}

}}

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

    很抱歉、我不知道语法突出显示项。 我的问题的最后一部分是第一个代码片段的末尾。

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

    您好、Wayne、

    1.您能否在整个代码中发布整段代码并注释这部分代码? 这将使我很容易理解发生了什么。

    if(i2c.length == 1)
    {
        UCB0CTL1 |= UCTXSTP;
    }
    伊斯天
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您的意思是"当我尝试接收2个或更多字节时、为什么我的代码不起作用"? 您可以接收一个还是无?

    您能否自行发布一些调试信息?

    伊斯天

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

    如果需要、我可以稍后在有机会时发布整个代码、但这段代码从上面整个代码的第108行开始。

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

    当我调用长度参数设置为1的函数"i2c_read"时 、一切都正常。

    当我调用长度参数设置为2的相同函数时、代码将无法正常工作。

    我想我可以发布调试信息、您希望看到什么类型的信息?

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

    您好、Wayne、

    1.您的意思是"调用长度参数设置为2的相同函数"是"i2c_read (length=2)"?  

    2."代码不起作用。" 有不同的方法。 您能更详细地介绍一下发生了什么情况吗?

    3)我需要的调试信息是:1)不同情况下的 I2C 波形。 2)    调试 视图中的寄存器和数组状态。

    4.查看您的代码:

    IF (IFG2 & UCB0RXIFG) //主机接收?
    {
    I2C.length--;
    if (i2c.length)
    {
    *i2c.data++= UCB0RXBUF;
    if (i2c.length = 1)
    {
    UCB0CTL1 |= UCTXSTP;
    }
    }
    其他
    {
    *i2c.data = UCB0RXBUF;
    // UCB0CTL1 |= UCTXSTP;
    IFG2 &=~UCB0TXIFG; //清除 TX 中断标志
    _BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出 LPM0
    }
    }
    

    如果您设置 i2c.length =2,它将跳转至"UCB0CTL1 |= UCTXSTP",然后生成 STOP,然后通信完成。 您将仅接收一个数据

    伊斯天

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

    在生成重复起始条件之前、我解决了清除 UCTXIFG 位的问题。 下面是工作代码。 顺便说一下、如果有人想知道、我可以使用 MSP430G2553和 MPU-9250进行此工作。

    主:

    /*
    main.c
    *
    *创建日期:2019年11月22日
    * 作者:Wayne
    */
    
    #include 
    #include "msp430_i2c.h"
    
    
    void main()
    {
    unsigned char * PRxData;// Rx 数据的指针
    volatile unsigned char RxBuffer[64];//为 Rx 数据分配空间
    
    unsigned char const * PTxData; //指向 TX 数据
    的指针 unsigned char const TxData[]= //要发送
    的数据表{
    0x40、
    0x4A
    };
    
    PTxData = TxData;
    PRxData =(无符号字符*) RxBuffer;//指向 RxBuffer 的起始地址
    
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    
    i2c_enable ();
    //i2c_write (0x68、0x6A、PTxData);//停止看门狗计时器 i2c_enable//启用 fifo
    //i2c_write (0x68、0x77、2、PTxData);
    
    
    while (1)
    {
    //i2c_write (0x68、0x13、2、PTxData);//启用 fifo
    i2c_read (0x68、0x75、2、PRxData);//读取 whoami 寄存器。}下一步不是0x76 b}
    
    

    MSP430_i2c.c:

    /*
    MSP430_i2c.c
    *
    *创建日期:2019年11月24日
    * 作者:Wayne
    *
    说明:用于 msp430g2553的 I2C 驱动器、使用中断。
    */
    #include 
    
    #defineSCL_PINBIT6
    #defineSDA_PINBIT7
    
    typedef 枚举{
    State_Waiting、
    状态读取、
    State_writing
    }MSP430_i2c_state;
    
    typedef 结构{
    易失性 MSP430_i2c_state;
    unsigned char slave_reg;//第一个从器件寄存器。
    unsigned char slave_reg_written;// 0如果从器件寄存器尚未写入。 *
    unsigned char *数据;
    无符号短长度;
    启用无符号字符;
    }MSP430_i2c_info;
    
    静态 MSP430_i2c_info i2c ={
    .enabled = 0
    };
    
    void i2c_enable ()
    {
    /*初始化 USCI I2C 模块*/
    BCSCTL3 |= LFXT1S_2;// VLOCLK (~12KHz)馈送 ACLK (选择 ACLK 源为内部 VLO)
    UCB0CTL1 |= UCSWRST | UCSSEL_1;//将 USCI_B 保持在复位状态以进行初始化(设置 UCSWRST)&选择 ACLK
    UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC; // I2C 主模式| I2C 模式
    UCB0BR0 = 8;//设置 i2c 频率
    UCB0BR1 = 0;
    P1SEL |= SDA_PIN | SCL_PIN; //配置端口
    P1SEL2 |= SDA_PIN | SCL_PIN;
    UCB0CTL1 &=~UCSWRST; //释放 USCI_B 以运行(清除 UCSWRST)
    IE2 |= UCB0TXIE | UCB0RXIE;//通过 UCxRXIE 和/或 UCxTXIE 启用中断(可选)
    
    
    int i2c_write (unsigned char SLV_addr、unsigned char reg_addr、unsigned char 长度、unsigned const char 数据
    )*
    /*填充结构。 *
    I2C.state = State_writing;
    i2c.slave_reg = reg_addr;
    I2c.slave_reg_written = 0;
    I2C.data =(unsigned char*) data;
    I2c.length =长度;
    
    UCB0I2CSA = SLV_addr; //将从器件地址写入 UCB0I2CSA 寄存器
    UCB0CTL0 &=~UCSLA10; // 7位从器件寻址模式
    UCB0CTL1 |= UCTR + UCTXSTT; //将 UCTR 设置为 TX 模式+将 UCTXSTT 设置为生成启动条件
    
    while (i2c.state!= State_Waiting)
    {//输入带中断的 LPM0 */
    _bis_SR_register (CPUOFF + GIE);
    I2C.state = State_Waiting;
    }
    
    返回0;//此返回无意义。 需要返回一些错误或其他
    内容}
    
    
    int i2c_read (unsigned char slv_addr、unsigned char reg_addr、unsigned char length、unsigned char * data)
    {
    //填充结构。 */
    i2c.state = State_reading;
    i2c.slave_reg = reg_addr;
    i2c.slave_reg_written = 0;
    i2c.data = data;
    i2c.length = length;
    
    UCB0I2CSA = SLV_addr;//将从器件地址写入 UCB0I2CSA 寄存器
    UCB0CTL0 &=~UCSLA10;// 7位从器件寻址模式
    while (UCB0CTL1 & UCTXSTP); //确保停止条件已发送
    UCB0CTL1 |= UCTR | UCTXSTT; // I2C 启动条件
    
    while (i2c.state!= State_Waiting)
    {//输入 LPM0 w/中断*/
    _bis_SR_register (CPUOFF + GIE);
    i2c.state = State_Waiting;
    }
    
    return 0;
    }
    
    #if defined (__TI_Compiler_version_)|| defined (__IAR_ICR_BIAS_COVERS
    
    
    
    (void)#BIAS_BIAS_COMPLETE_COMPLETE_COMPLETOR (void)#BIAS_COMPLETE_COMPLETE_COMPLETE_COMPLETE_COMPLETE_COMPLETE_COMPLETE_TRIE_TRIE_INEST_BIST_NOW_#BIST_COMPLETE_COMPLETE_SIONENTS_BIST_INEST_VERS (nLETE)#BIST_COMPLE
    
    
    #endif
    {
    if (IFG2 & UCB0RXIFG)//主机接收?
    {
    i2c.length--;
    if (i2c.length)
    {
    * i2c.data++= UCB0RXBUF;
    if (i2c.length = 1)
    {
    UCB0CTL1 |= UCTXSTP;
    }
    
    否则
    {
    * i2c.data = UCB0RXBUF;
    //UCB0CTL1 |= UCB0TXIFG
    和~UCTXG;// UCB0TXIFG//清除 TX 中断标志
    __BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出 LPM0
    }
    
    
    否则(IFG2 & UCB0TXIFG)//主机发送?
    {
    switch (i2c.state)
    {
    case State_writing:
    if (!i2c.slave_reg_writing)
    {
    i2c.slave_reg_write= 1;//
    UCB0TXBUF = i2c.slave_reg;//发送从地址
    }
    否则(i2c.length)//要发送的数据?
    {
    char next =* i2c.data;//
    i2c.data++;//递增字节
    i2c.length-;//递减待发送的数据量
    //写入 TXBUF 必须始终是最终操作。 //
    UCB0TXBUF = NEXT;
    }
    否则//没有更多数据要发送?
    {
    UCB0CTL1 |= UCTXSTP;//生成停止条件。
    IFG2 &=~UCB0TXIFG;//清除 Tx 中断标志
    __BIC_SR_REGISTER_ON_EXIT (CPUOFF + GIE);
    }
    break;
    case State_reading:
    if (!i2c.slave_reg_written)
    {
    i2c.slave_reg_written = 1;
    UCB0TXBUF = i2c.r_rev.rn
    
    
    
    );重复启动 RX 模式。 */
    IFG2 &=~UCB0TXIFG;//清除 TX 中断标志(不确定是否正确)
    UCB0CTL1 &=~UCTR;
    UCB0CTL1 |= UCTXSTT;
    
    //如果是单字节,请立即准备 STOP 信号。 //
    if (i2c.length ==1)
    {
    //井,不是立即。 首先、我们需要确保
    *已发送启动信号。
    //
    while (UCB0CTL1 & UCTXSTT);
    UCB0CTL1 |= UCTXSTP;
    IFG2 &=~UCB0TXIFG;//清除 TX 中断标志
    }
    
    中断;
    }
    
    }}