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.

[参考译文] CCS/MSP432P401R:MSP432 LCD I2C通信停止(等待从未发生的TX中断)

Guru**** 2533390 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/576600/ccs-msp432p401r-msp432-lcd-i2c-communication-stops-waiting-on-tx-interrupt-that-never-occurs

部件号:MSP432P401R

工具/软件:Code Composer Studio

大家好,

i2c驱动程序的问题是在读取单字节后无法执行写入。
我已经测试过,可以在写入后读取2,4,最多32字节,没有问题,但如果我执行读取1字节,下一次写入将等待从未发生的传输中断。
我可以通过执行另一个写操作,然后 再写,然后再读1个以上的字节来清除错误-这有时会失败,有时不会,有时需要两个读写周期才能清除。

使用总线盗版来写入/读取i2c总线或单字节读取不是问题(即生成独立的接地真),这 或多或少会导致我得出结论,这是432芯片或driverlib存在问题。

利用这个论坛,我看到其他人也有同样或类似的问题--这些问题似乎没有得到解决,这使我得出结论,这只是一个真正的问题,而不是我。

无论您向我还是我向您提供任何帮助?  我可以运行测试,我可以向您发送代码,无论...

Thx,

Bob s

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Bob,
    如果您可以提供一个很好的示例。 否则,我将转换行中的示例,在这些示例中,主中继器先写入两个字节,然后读取10 -交换读取一个字节,然后写入10。

    此致,
    Chris
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我使用i examples i2c_master*作为模板,更改了B-Base配置以匹配我的卡(B2),并将*WithTimeout替换为锁定的呼叫。 我使用的核心频率是48Mhz,i2c速率是100kHz。

    我写的代码是一个更大项目的一部分,432卡是定制的,我为板载I2C器件,Linear Technologies LTC2945定制了示例。

    我将剪切并粘贴代码片段并上载它们,也许您可以看到我错过的内容。
    下面不包括DelayMs(),DumpBuffer()和putUsart()。

    片段中有一些路径可以探索可以做些什么,一条路径可以探索由TI员工发布的替代驱动程序,并且存在一些明显错误的事情,例如不写而读-我可以让巴士海盗做这件事,但不能让标准的TI驱动程序做这件事。 虽然备用驱动程序通常可以正确读取(首先执行写入),但存在其他协议问题(完成读取前完成握手)。

    我找到了解决问题的方法->如果我收到丢失的TX中断错误,我会重新调用init,然后调用下一个传输,接着是Read,这通常是有效的。 我不确定init中的哪个步骤会重置硬件。

    ---


    /* I2C主配置参数*/
    const eUSI_I2C_MasterConfig i2cConfig48 =

    EUSCI_B_I2C_CLOCKSOURCE_SMCLK, // SMCLK时钟源
    4800万, // SMCLK = 48MHz
    EUSCI_B_I2C_SET_DATA_RATE_100KBPS, //所需的I2C时钟为100kHz
    0, //无字节计数器阈值
    EUSCI_B_I2C_NO_AUTO_STOP //不自动停止
    };
    /*
    *----------------------------------
    */
    int i2c_init(void)

    内部状态=0;
    char txbuf[2];
    char rxbuf[32];

    GPIO _setAsPeripheralModuleFunctionInputPin (GPIO_PORT_P3, GPIO _PIN6 | GPIO _PIN7,GPIO主要模块功能);
    如果(g_coreMhz == 48)

    /*在没有自动停止的情况下将I2C主设备初始化到SMCLK AT */
    MAP_I2C_INITMaster (EUSCI_B2_BASE,&i2cConfig48);
    }
    否则

    如果(g_coreMhz == 24)

    /*在没有自动停止的情况下将I2C主设备初始化到SMCLK AT */
    MAP_I2C_INITMaster (EUSCI_B2_BASE,&i2cConfig24);
    }
    否则

    /*
    *永远不应到达此处,因为频率与传入USART的参数相同
    */
    状态=-1;
    strcpy(g_info,"Invalid core frequence, via i2c_init()\r\n");
    InABadPlace (g_info);
    }
    }
    /*将主中继器设置为传输模式*/
    MAP_I2C_setMode (EUSCI_B2_BASE,EUSCI_B_I2C_Transmit_MODE);

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

    /*启用并清除中断标志*/
    MAP_I2C_clearInterruptFlag (EUSI_B2_BASE,
    EUSCI_B_I2C_Transmit_INTERRUPT0 + EUSCI_B_I2C_receive _INTERRUPT0);
    /*
    *测试与i2c电源监视器的通信
    */
    txbuf[0]=0;
    txbuf[1]=5;
    #ifdef I2CTEST
    状态= i2c_put _ get_bis (PM_slaver_address,txbuf,2,rxbuf,32);
    #否则
    状态= i2c_put _get (PM_slaver_address,txbuf,2,rambuf,32);
    #endif
    退货状态;
    }//结束i2c_init

    /*
    *----------------------------------
    */
    int i2c_put获取(int saddr,unsigned char *tx,int txcnt,unsigned char *Rx,int rxcnt)

    Int status =0;//返回状态
    int ii; //迭代器
    int tx_f; //传送标志
    static int last_addr =-1;
    布尔NOT_TMO_f;


    如果((saddr ==-1)&&(last_addr ==-1))

    putUsart ("未设置开始地址\r\n");//位置不好。锁定代码。
    状态=-1;
    退货状态;
    }

    tx_f = 0;
    stopSent =假; //清除全局互斥
    如果(txcnt > 0)

    TXByteCtr = txcnt -1;//设置要传输的字节数,现在首先发送
    ts_f = 1; //是,正在传输
    xferIndex = 1; //在传输时最多计数至TXByteCtr,在接收时最多计数至rxcnt
    //启用主接收中断
    MAP_I2C_enableInterrupt (EUSCI_B2_BASE,EUSCI_B_I2C_Transmit_INTERRUPT0);

    }

    RXByteCnt = rxcnt; //全局,用于中断处理程序

    MAP_I2C_setSlaveAddress (EUSCI_B2_BASE,saddr);/*指定从属地址*/

    IF (TX_f)

    /*确保最后一笔交易已全部发出*/
    二=0;
    while (MAP_I2C_MASTOISStopSent (EUSCI_B2_BASE)== EUSCI_B_I2C_Sending停止)

    II++;
    DelayMs(100);
    如果(ii = 50)

    状态=-2;
    strcpy(g_info,"i2c停止失败.\r\n");
    }
    }
    /*发送开始和传输缓冲区的第一个字节。 我们必须发送
    *两个字节,用于清除缓冲区中先前发送的内容
    *(以上评论来自示例:I2C_MASTER_RW_RESICATE_START- MASTER)
    */
    MAP_I2C_setMode (EUSCI_B2_BASE,EUSCI_B_I2C_Transmit_MODE);
    MAP_I2C_clearInterruptFlag (EUSI_B2_BASE,
    EUSCI_B_I2C_Transmit_INTERRUPT0 + EUSCI_B_I2C_receive _INTERRUPT0);
    MAP_I2C_enableInterrupt (EUSCI_B2_BASE,EUSCI_B_I2C_Transmit_INTERRUPT0);
    MAP_Interrupt_enableInterrupt (INT_EUSCIB2);
    //map_I2C_masterSendMultiByteStart(EUSI_B2_base, I2C_TXData[0]);//这就是xferIndex从索引1开始的原因。
    /*
    *超时不是"超时",而是倒计时。
    */
    NOT_TMO_f = MAP_I2C_masterSendMultiByteStartWithTimeout(EUSSCI_B2_BASE,I2C_TXData[0],1000);
    如果(!NOT_TMO_f)// double negative == TRUE

    Sprintf (g_info,"map_I2C_masterSendMultiByteStartWithTimeout超时\r\n");
    putUsart (g_info);//这是否是真正的错误? 尝试接收
    状态=-1;
    返回状态;//提前退出
    }
    否则

    MAP_I2C_masterSendMultiByteNext(EUSI_B2_BASE,I2C_TXData[0]);
    }
    }
    else //设置接收而不传输

    Memset (I2C_RXData,0x00,MAXBUF);
    MAP_I2C_setMode (EUSCI_B2_BASE,EUSCI_B_I2C_receive模式);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart (EUSCI_B2_BASE);
    MAP_I2C_enableInterrupt (EUSCI_B2_BASE,EUSCI_B_I2C_receive _INTERRUPT0);
    }
    /*
    *注:TX和Rx发生在中断处理程序内
    */
    // map_pcm_gotoLPM0(); // LPM工作正常(2017年2月17日测试),以防需要低功率模式
    对于(ii=0;iii<50;ii++)//循环等待设置标志

    IF (停止Sent)
    中断;

    DelayMs(100);
    }
    如果(!stopSent)

    sprintf (g_info,"未收到预期的i2c中断\r\n");
    putUsart (g_info);
    //status =-2;//这是否是真正的错误? 尝试接收...
    }
    如果(状态=0)

    IF (rxcnt >0)

    IF (rxcnt != xferIndex)

    sprintf (g_info,"接收到的i2c数据计数:%d不等于请求的:%d\r\n",xferIndex,rxcnt);
    putUsart (g_info);
    状态=-3;
    }
    否则

    dumpBuffer (I2C_RXData,xferIndex);
    }
    }
    }
    stopSent = FALSE;//清除全局

    如果((status ==0)和(saddr !=-1))

    last_addr = saddr;//现在允许不带写入的读取
    }
    退货状态;
    }//结束i2c_put
    作废EUSCIB2_IRQHandler (作废)

    UINT_FAST16_t状态;

    //注意:xferIndex在此处设置为0,然后包含接收数据的长度
    //注:stopSent是中断外的互斥锁

    #ifdef I2CTEST
    返回euscib2IntHandler();//测试处理程序
    #endif

    状态= MAP_I2C_getEnabableInterruptStatus (EUSCI_B2_BASE);
    MAP_I2C_clearInterruptFlag (EUSCI_B2_BASE,状态);

    /*如果我们达到传输中断,则表示我们位于的索引1
    *传输缓冲区。 在我们到达之前反复启动时
    *最后一个字节我们需要将模式更改为接收模式,设置开始
    *条件发送位,然后将最后一个字节加载到TXBUF中。
    */
    IF (状态和EUSCI_B_I2C_Transmit_INTERRUPT0)

    IF (TXByteCtr) /*如果下一个传输是最后一个字节或更多到最后一个字节*/

    MAP_I2C_masterSendMultiByteNext (EUSCI_B2_BASE,I2C_TXData[xferIndex+]); //对于多字节启动是必需的
    TXByteCtr
    }
    否则

    MAP_I2C_masterSendMultiByteStop (EUSCI_B0_BASE); //如果仅发送1个字节,或最后一个字节
    MAP_I2C_DisableInterrupt (EUSCI_B2_BASE,EUSCI_B_I2C_Transmit_INTERRUPT0);

    IF (RXByteCnt) //过渡到接收

    MAP_I2C_setMode (EUSCI_B2_BASE,EUSCI_B_I2C_receive模式);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart (EUSCI_B2_BASE);
    MAP_I2C_enableInterrupt (EUSCI_B2_BASE,EUSCI_B_I2C_receive _INTERRUPT0);
    }//如果转换为接收,则结束

    stopSent = TRUE;//如果写入后没有读取,则信号完成

    }//结束其他已完成的传输
    }//如果传输中断则结束

    /*将字节接收到接收缓冲区。 如果我们已收到所有字节,
    *然后发送停止条件
    */
    IF (状态和EUSCI_B_I2C_Receive_INTERRUPT0)

    IF (xferIndex == RXByteCnt -2)//如果在最后一个字节旁边

    MAP_I2C_masterReceiveMultiByteStop(EUSI_B2_base);//"whoa"命令?
    I2C_RXData[xferIndex+]= MAP_I2C_masterReceiveMultiByteNext(EUSI_B2_base);
    }
    否则

    IF (xferIndex == RXByteCnt -1)// IF最后一个字节

    MAP_I2C_masterReceiveMultiByteStop(EUSI_B2_base);//"whoa"命令?
    I2C_RXData[xferIndex+]= MAP_I2C_masterReceiveMultiByteNext(EUSI_B2_base);
    MAP_I2C_DisableInterrupt (EUSCI_B2_BASE,EUSCI_B_I2C_Receive_INTERRUPT0);
    MAP_I2C_setMode (EUSCI_B2_BASE,EUSCI_B_I2C_Transmit_MODE);
    stopSent =真; //设置互斥锁
    MAP_Interrupt_DisableSleepOnIsrExit();//发出指令前的低功耗
    }
    else //否则不是最后一个或最后一个字节的旁边

    I2C_RXData[xferIndex+]= MAP_I2C_masterReceiveMultiByteNext(EUSI_B2_base);
    }//结束其他项不是最后一个或最后一个
    }// end else不在最后一个字节旁边
    }//如果接收中断则结束
    }
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    如果我可以提出后续问题:
    问:如何测试驱动程序库?
    只是重新运行driverlib的示例并不会测试边界条件。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我刚在传输端发现一个错误(我自己的)-总是传输0而不是预期数据,但是这不影响我在接收端看到的问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    测试这一点的一个好方法可能是使用名为"i2c_master_rw_重复 性_start-master_code"的TI示例项目。
    然后将常量NUM_OF_REC_Bytes从10减少到1。

    由于我的代码基于您的代码,如果您没有代码锁定,则会指向我的代码,而不是您的代码。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢罗伯特。  我仍然需要消化先前的职位。  我根据您引用的示例将一个示例放在一起,但我需要与设计人员联系,因为如果只收到一个字节,那么在知道何时设置停止点时似乎存在问题。  您将在我的代码中找到一个'hack',尝试在每个TRM的接收字节内设置停止时间(图24-13)。  如果您对代码有任何疑问,请告诉我。

    此致,

    Chris

    e2e.ti.com/.../i2c_5F00_master_5F00_rw_5F00_repeated_5F00_start_2D00_master_5F00_code_5F00_edits.c

    e2e.ti.com/.../i2c_5F00_master_5F00_rw_5F00_repeated_5F00_start_2D00_slave_5F00_code_5F00_edits.c

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

    您好,Chris,

    感谢您确认此问题。

     在发送的示例中,中断处理程序中发出的"stop-interrupt"调用发生在从下一个字节到最后一个字节的读取中。

    我的问题是,对于一个字节的读取,没有“从下一个到最后一个”字节。  

    我是否正确理解代码和您的解释?

    如果我修改我的代码以启用 EUSCI_B_I2C_STOP_INTERRUPT,并在最后一个字节上进行停止-中断调用,这是否能解决问题,

    或者,我是否需要执行虚拟读取以实际触发停止中断?

    Bob s

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我的后续问题是,读取(超出规格允许的待定从属设备范围)可能会导致该从属设备出现问题。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Bob,
    在代码示例中,如果只想读取一个字节,则必须将NUM_OF_RX_Bytes更改为1,并取消注释NUM_OF_RX_BYTED_is_one的定义(第83,84行)。 这将删除从下一个字节到最后一个字节的代码,只需发送开始,发送停止,然后读取停止ISR中的RX buf。 诀窍是在发送启动后等待多长时间,然后发送停止,我正在尝试定义。 如果我错过了什么,请告诉我。

    此致,
    Chris
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您清除此信息。
    我将等待您确定停止和启动之间的等待时间。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我没有耐心。
    我对您的解决方案进行了编码,使用我的从属设备地址和B2配置进行多字节读取(非异常情况为Read > 1),并且处理程序在最后一次xmit后的第一个while语句中锁定。 我将跳过while循环并重试。

    这一点从不断言->
    同时
    (!BISTBAND_PERI(EUSI_B_CMIS(EUSI_B2_BAC)->IFG, EUSCI_B_IFG_TXIFG0_OFS))
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    1.修订的中断处理程序中的第一个while循环挂起。 所以我评论了一下,然后重试了。
    2.读取1字节后的传输+读取不再挂起,但根据从属规范,回读的值无效,它们都是0xff。
    问:为什么要从multistybytestart切换到start?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Bob,
    我删除了multibytegstart,因为它似乎损坏了发送的第一个字节。

    /*发送开始和传输缓冲区的第一个字节。 我们必须发送
    *两个字节,用于清除缓冲区中以前缓冲区中的任何内容
    *发送*/
    MAP_I2C_masterSendMultiByteStart (EUSCI_B0_BASE,TXData[0]);
    MAP_I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[0]);


    /*发送停止后启用传输中断*/
    MAP_I2C_enableInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_INTERRUPT0);

    在我的适应中,我只是发送开始,然后处理ISR内的数据传输。

    /*发送开始和传输缓冲区的第一个字节。 我们必须发送
    *两个字节,用于清除缓冲区中以前缓冲区中的任何内容
    *发送*/
    MAP_I2C_masterSendStart (EUSCI_B0_BASE);
    // MAP_I2C_masterSendMultiByteStart (EUSCI_B0_BASE,TXData[0]);
    // MAP_I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[0]);

    MAP_I2C_enableInterrupt (EUSCI_B0_BBASE,EUSCI_B_I2C_Transmit_INTERRUPT0);

    在您之前的POST中,数据将被移动到ISR中的TX缓冲区。 当最后一个字节加载到TX buf时,中断被禁用,然后代码在更改模式和发送重新启动之前等待(轮询TXIFG)。

    MAP_I2C_masterSendMultiByteNext(EUSI_B0_BASE,TXData[xferIndex+]);
    IF (xferIndex == NUM_OF_TX_Bytes)

    MAP_I2C_DisableInterrupt (EUSCI_B0_BASE,EUSCI_B_I2C_Transmit_INTERRUPT0);
    /*
    *调试以开始工作
    *等待IFG设置完成后再继续
    */
    同时
    (!BISTBAND_PERI(EUSI_B_CMIS(EUSI_B0_BASE)->IFG, EUSCI_B_IFG_TXIFG0_OFS))

    MAP_I2C_setMode (EUSCI_B0_BBASE,EUSCI_B_I2C_Receive_mode);
    xferIndex = 0;
    MAP_I2C_masterReceiveStart (EUSCI_B0_BASE);

    我发现,如果您不等待,最后一个字节将被破坏。 我在轮询IFG时未遇到问题。 您使用的芯片是哪一版本?

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

    当我使用多字节开头执行2字节TX时,即:<address><register_id><data>,
    此外,还使用多字节开头,回读时的数据字似乎没有损坏。
    但是,当我在测试SendStart之后测试多字节时,数据在回读时显示为已损坏。 很有趣

    我没有执行任何多字xmits,因为我的从属协议是这样的形式:<address><register_id><data>,和
    不是所有寄存器都可以进行w/r设置,有些寄存器是状态,不会随写入而更改。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    后续:我今天花了很多时间对变体进行编码和测试,以查看影响因素,我发现:
    1.添加此语句map_I2C_masterSendMultiByteStop(EUSI_B2_base);
    完成传输以使协议握手看起来正确时,会导致以下多字读取失败,除非调用re-init。 此调用不在您的代码中,而是在示例"master with multibyte master code"中。
    删除停止传输呼叫可使读取成功进行每个呼叫。
    2.您发送的编码更改(轮询和接收延迟1)允许读取单字节不会导致下一次传输失败,
    这将成功进行一行中的多个呼叫。 但是,读取中返回的数据始终是错误的(与读取时的2字节相比
    注册ID)。 此时,我不记得我使用的早期版本是否返回了良好的数据,因为我关注的是下一个呼叫的故障。 我被消耗殆尽,明天我将尝试重新压缩单字节读取代码。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我的后续行动的后续行动。 我在放弃一天之前尝试了最后一次运行,并在读取单字节时设置了断点。
    由于遇到断点所需的额外时间导致读取值正常。 我在EUSCI_B_I2C_STOP_INTERRUPT之后以及读取将解决我的问题之前有一段延迟。 我明天再讨论这个问题。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,

    我现在有一些有用的东西,基本上就是定制您的代码+我 在其他示例中使用的代码。

     我注意到您使用的是核心频率8MHz,而我使用的是核心频率48MHz。 这会影响延迟的值。

    如果嵌入式设备永远不会锁定,那么当您将示例发布到正式版本时,您可能需要重写等待循环。

    下面是我所做的工作,如果状态永远不会变为现实,并且这类事情发生在驱动程序的多个位置,我将提供反馈:

            对于(ii=0;iii<5;i++)

             {

              /*

              *如果该位从未实现,不确定是否为错误,但是

              *绝对不想锁定

              */

              __DELAY周期(1000);

              IF (BITBAND_PERI(EUSI_B_CMIS(EUSI_B2_base)->CTLW0,EUSCI_B_CTLW0_TXSTT))

              {

                ; //仍在等待

              }

              否则

              {

               match_f = true; //就绪

               中断;       //退出循环

              }

             }

             如果(!match_f)

              I2C_tmo2_f =真;