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.

[参考译文] MSP430F5329:是否有将在 MSP430F5329上运行的 I2C 示例代码?

Guru**** 2500805 points
Other Parts Discussed in Thread: MSP430F5329

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/611950/msp430f5329-is-there-example-code-for-i2c-that-will-run-on-a-msp430f5329

器件型号:MSP430F5329

我需要简单的代码来读取和写入 I2C 器件。 MSP430是一个主器件、而其他主器件是硅器件。  

我发现、您拥有如此多的外设变体、而我在没有大量消息的情况下无法找到只能正常工作的代码、这让我感到惊讶。  

Google 搜索没有帮助。  

我发现的第一件事是来自 Jan Richter http://hackaday.com/2014/02/02/a-better-usi-i2c-library-for-the-msp430/的一些代码
是为不同版本的 MSP430编写的、但我认为它应该几乎是相同的吗? 错误。 它假定一个 USI I2C、  其中 MSP430F5329使用 USCI I2C、它们并不相似、因为我浪费了几天的时间尝试使其正常工作。 它太不同了。  

已找到 MSP430 I2C Wiki http://processors.wiki.ti.com/index.php/MSP430_I2C
说"每个 MSP430产品页面   的软件和工具 下都有代码示例.zip 文件-> 软件"

我查看了那里并找到了一个文件、该文件显示 了 MSP430F532x 代码示例(修订版 F) (ZIP217KB)  164次查看、2017年6月5日  
我觉得我很黄金、直到我查看了 I2C 的代码示例。  

下面是示例 I2C 中断例程。

// USCI_B0数据 ISR
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector = USCI_B0_Vector
__interrupt void USCI_B0_ISR (void)
#Elif defined (__GIC_)
void __attribute_(USCI_B0_Vector _)#interrupt USCI_B0_ISR (void

)(nuc1u_0_ISR vector)#b0!
#endif
{
switch (__even_in_range (UCB0IV、12))
{
case 0:break; //向量0:无中断
情况2:中断; //向量2:ALIFG
情况4:中断; //向量4:NACKIFG
情况6:中断; //向量6:STTIFG
情况8:中断; //向量8:STPIFG
情况10: //向量10:RXIFG
RXData = UCB0RXBUF; //获取 RX 数据
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出活动 CPU
中断;
案例12:中断; //向量12:TXIFG
默认值:break;
}

不是很有帮助、也不是我所说的真实示例。  


我想我在 SLAA382A 中使用 了 USCI I2C 主设备。  
我从 SLAA382A 下载了示例、该示例说明它适用于 USCI I2C 主设备。 但他使用的是"MSP430x261x"、它使用不同的引脚、不同的 USCI (UCB0而不是 UCB1)、并且具有用于 I2C 读取和写入的独立中断。  因此、需要做一些工作才能找到具体器件的问题所在。 我已经浪费了几天的时间走错了路。  


为什么每个处理器都没有示例代码?  为什么有这么多不同的 I2C 外设? 获取一个正常工作并继续使用它。 它不像一个新接口。  

我应该怎么做? 从何处开始?  

我们正在从 ST ARM 处理器切换到 MSP430、由于 ST 上的 I2C 有问题、我们必须在 ST 部件上位 bang I2C。 我的同事在一天之内将位 bang 代码从 ST 部分重写到 MSP430 (基本上他更改了引脚名称和时序延迟环路)、一周内我无法使用 MSP430 I2C 外设使其正常工作。


 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我解压缩了 SLAA382A。 将 P3SEL 更改为 P4SEL、并将所有 UCB0更改为 UCB1、并进行编译以查看我拥有的内容。 17编译错误、因为特殊函数寄存器具有不同的名称。

    我在这些名称上遇到错误。 UCB1I2CIE、IE2、USCIAB0RX_Vector、USCIAB0TX_Vector、IFG2
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    浏览代码后发现:

    ///----------------------------------
    // unsigned char TI_USCI_I2C_NO迎宾()
    //
    此函数用于检查是否有正在进行的通信。
    //
    //// out:unsigned char => 0:I2C 总线空闲、
    // 1:通信正在进行
    中//----------------------------------
    unsigned char TI_USCI_I2C_NO迎宾(){
    return (UCB1STAT 和 UCBBUSY);
    } 

    UCBBUSY 是 UCB1STAT 寄存器中的位4。  

    这意味着它返回0或16、而不是0或1。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    此芯片有八个示例程序。 每一个都说明了不同的东西。

    这些示例程序展示了如何访问硬件、但并不是独立的教程。 他们假设您正在阅读《用户指南》第38章。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当然、您指的是:

    MSP430F532x_uscib0_i2c_04.c USCI_B0 I2C 主器件从 MSP430主器件接收单个字节
    MSP430F532x_uscib0_i2c_05.c USCI_B0 I2C 从器件 TX 单字节到 MSP430从器件
    MSP430F532x_uscib0_i2c_06.c USCI_B0 I2C 主器件将单字节发送到 MSP430从器件
    MSP430F532x_uscib0_i2c_07.c 来自 MSP430主器件的 USCI_B0 I2C 从器件 RX 单字节
    MSP430F532x_uscib0_i2c_08.c USCI_B0 I2C 主器件将多个字节发送到 MSP430从器件
    MSP430F532x_uscib0_i2c_09.c USCI_B0 I2C 从器件从 MSP430主器件接收多个字节
    MSP430F532x_uscib0_i2c_10.c USCI_B0 I2C 主器件从 MSP430从器件接收多个字节
    MSP430F532x_uscib0_i2c_11.c USCI_B0 I2C 从器件将多个字节发送到 MSP430主器件

    大多数人对处理器作为主处理器感兴趣、并与一些从 IC 器件进行通信。 它可以是存储器、也可以是外设、操作系统一些其他特殊芯片。  

    该模式非常直接。 您必须写入外设地址。 那么可能是器件内部的地址。 然后、如果要写入、请继续写入。 如果您正在读取、请重新启动并对外设地址执行读取操作、然后执行多次读取。  

    没有相关示例。 这是 I2C 总线上最常见和最基本的交互。  

    拥有多个主设备或使用 I2C 在处理器之间进行通信的情况更少见、而且更先进。 您最好能够做到这一点、但您将其与有关 I2C 主发送器模式的文档混用在一起、这会使文档更难阅读。  

    但真正令人烦恼的是、您可能没有合适示例的原因是不同的 MSP430处理器具有不同的 I2C 外设和不同的寄存器名称。 因此、当您从一个 MSP430更改为另一个 MSP430时、这几乎就像从头开始一样。 这就是为什么我将尝试将这个项目从 MSP430切换到另一个不是问题的架构的原因。  

    为什么在一个 MSP430中使用 ICB1IE、在 另一个 MSP430中使用 ICB1I2CIE 和 IE2?  


    但与此同时,我现在仍然必须与这一个合作。  

    通过查看 MSP430F532x_uscib0_i2c_08.c USCI_B0 I2C 主器件 TX 多个字节到 MSP430从器件、可以看到如何发送多个字节。  


    因此、我们将以艰难的方式实现这一目标。  

    我有一个 MSP430F5329、我要与地址为0x18且无 CRC 的 bq7692006PWR 交谈。  


    我使用以下代码对其进行初始化:

    void i2c_init (void)
    {
    //设置引脚
    P4SEL |= 0x06; //设置为 P4.1 (SDA)、P4.2 (SCL)作为特殊功能引脚
    
    __disable_interrupt ();
    i2c_interrupt_count = 0;
    UCB1CTL1 = 0x81; //时钟为 SMCLK,不在错误字符上中断
    //不要在中断字符时中断
    //不处于休眠状态,下一帧是数据,下一帧不是中断,
    // I2C 保持在复位状态。
    
    UCB1BR0 = 148; //将比特率设置为14745600 / 148 = 99632.43bps
    UCB1BR1 = 0;
    
    UCB1CTL0 = 0x0F; // 7位寻址,单主器件
    //主控模式选择、I2C 模式、同步模式
    
    i2c_state = I2C_IDLE; //确保状态机处于空闲
    状态 UCB1CTL1 &=~(UCSWRST);//清除 I2C 复位现在 I2C 已设置并就绪。
    
    
    UCB1IE = 0x03; //启用发送和接收中断
    UCB1IFG = 0; //清除所有中断标志。
    
    //_enable_interrupt ();//通常在此处设置中断。 在运行之前不使用中断来执行它。
    
    #ifdef testbq796
    test_i2c ();
    #endif
    } 

    测试设置一系列数据。  

    const uint16_t i2c_testdata_sequence1[]={bq769x_Address_WR_t、0、I2C_restart、bq769x_Address_RD_t、I2C_Read、 I2C_READ、I2C_READ };

    因此、我们需要写入 bq769地址(0x18 + 0用于写入)、然后将 bq769的地址发送为0、我们要读取该地址。 然后通过读取地址(0x18+1表示读取)上的器件来执行重新启动、然后读取三次

    从地址0、1和2获取数据。

    因此、在没有中断的情况下、我执行以下代码:

    void start_communications (void)
    {
    uint16_t i;
    UCB1CTL1 |= UCTR | UCTXSTT; //发送器和发送启动
    
    UCB1I2CSA =(((char)(* i2c_sequence))>> 1;//加载 I2C 地址、不带 r/w 位字节
    
    I2C_SEQUEST++;
    I2C_SEQUEST_LENGTH--;
    
    I2C_Prepare_data_xmit_recv ();
    I2C_state = I2C_Prepare_ACKNACK;//下一状态:准备接收数据 ACK/NACK
    
    while (UCB1IFG = 0);//等待任何中断标志
    
    for (i=0;i<10;i++);//此处的调试中断
    
    } 

    看一下中断标志 UCB1IFG、我得到0x22。  这意味着我有一个 UCNAKIFG 和一个 UCTXIFG。  我需要 TX 中断、不需要 NAK 中断。  

    观察示波器、其中黄色为 SCL、蓝色为 SDA

    如果地址为0x18、我认为是正确的、请参阅随附的文件 NAK。  

    如果示波器显示有 Ack、 为什么 UCNAKIFG 为1?



    您可以看到观察1窗口显示 UCB1IFG = 0x22。  

    那么、我怎么做呢?  

    根据文档、ACK 是1

    在 SLAU412E 第13页中、它显示  

    1.3.4.2.1 I 2 C 主机发送器模式

    初始化之后、通过将所需的从器件地址写入来启动主发送器模式
    UCBxI2CSA 寄存器、通过 UCSLA10位选择从地址的大小、为设置 UCTR
    发送器模式、以及设置 UCTXSTT 以生成启动条件。

    USCI 模块检查总线是否可用、生成启动条件、并发送从器件
    地址。 当 START 条件被生成并且第一个数据将被发送时、UCTXIFG 位被置位
    发送的数据可以被写入 UCBxTXBUF。 一旦从器件确认地址
    UCTXSTT 位被清零。

    UCTXSST 看起来会被清除、因此从器件会确认地址。 我们通过示波器图像确认。

    e2e.ti.com/.../RycherI2CRevC.zip

    我包含了完整的源文件。  

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

    这些示例程序使用 MSP 作为从器件、因为从器件类型无关紧要;I²C 仅传输字节。 没有多个主器件。
    这些示例存在的一个问题是、它们不显示如何处理重复起始。

    在所示的波形中、最后一位为高电平;这不是 ACK、而是 NAK。 (您使用的是什么从设备?)

    USI 和 USCI 是不同的硬件模块。 Jan Richter 提供的代码适用于 USI、对 F5329没有帮助。

    SLAA382代码用于2xx 器件。 我不知道 TI 为什么移动了中断标志;我想5xx 器件可以有更多的 USCI 模块、因此这些位不适合单个寄存器。 无论如何、此代码也不支持重复启动。

    以下(未经测试)代码执行寄存器读取、不会产生中断、也不会进行错误检查:

    void init_i2c (void)
    {
    UCB1CTL1 = UCSSEL_SMCLK + UCSWRST;
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;
    UCB1BRW = 148;
    UCB1CTL1 &=~UCSWRST;
    }
    
    void write1_read3 (void)
    {
    UCB1I2CSA = 0x18;
    
    UCB1CTL1 |= UCTR + UCTXSTT;
    
    while (!(UCB1IFG & UCTXIFG));
    UCB1TXBUF = 0x00;
    
    UCB1CTL1 &=~UCTR;
    UCB1CTL1 |= UCTXSTT;
    
    while (!(UCB1IFG & UCRXIFG));
    字节1 = UCB1RXBUF;
    
    while (!(UCB1IFG & UCRXIFG));
    字节2 = UCB1RXBUF;
    
    UCB1CTL1 |= UCTXSTP;
    while (!(UCB1IFG & UCRXIFG));
    字节3 = UCB1RXBUF;
    } 
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我发现 Jan Richters 代码用于 USI、而不是 USCI、 但是我喜欢他在中断中创建状态机的方式、这样我就可以指定一个序列、通信将在后台进行、并且我可以在完成后处理接收到的数据。

    但我发现我有更基本的问题只是让它说话。

    在 I2C 总线上、有3个从器件:BQ34Z100PWR、BQ7694006DBT 和 MCP47FEB22A0-E/ST

    我被告知 他们 BQ34Z100PWR 和 ST32处理器存在 I2C 问题。 为了解决这个问题、他们决定不使用 I2C 硬件、而是进行位拆裂。

    他们能够将位 bang 代码转换为 MSP430并使其正常工作。

    我的任务是使 I2C 代码正常工作、以便处理器可以更长时间地关闭以节省电池电量。

    我从 BQ7694006DBT 开始、因为它们没有任何问题。  然后、我将介绍 BQ34Z100PWR、以了解他们在该芯片上遇到的问题。  如果它是从器件问题或主器件问题。  我不知道我是从第二个或第三个方面获得信息。 ST32代码是在亚洲编写的。 ST32的位 bang 修复和 MSP430的转换是在奥斯汀编写的、我在普莱诺。

    我运行了您的代码示例。  在我们发送从器件地址时、您得到的内容与我得到的内容相同。 在 while (!(UCB1IFG & UCTXIFG))期间;在发送从器件地址后、UCB1IFG = 0x22、 就像上面的问题一样。 UCNAKIFG 和 UCTXIFG 位被置位。  如果我在中断中使用此中断(这是我要转到的位置)、UCB1IV 寄存器将具有 UCNAKIFG 中断、因为它具有更高的优先级。 但我不明白为什么处理器认为我获得了 NAK、因为 NAK 是0、ACK 是1、我在示波器上看到1。  那么、这就是问题1。 当 NAK 看起来像 ACK 时、为什么选择它?

    问题2:

    它会在下一次时卡住。  您的代码为:

    UCB1TXBUF = 0x00;
    
    UCB1CTL1 &=~UCTR;
    UCB1CTL1 |= UCTXSTT;
    
    while (!(UCB1IFG & UCRXIFG)); 

    但在上  

    while (!(UCB1IFG & UCRXIFG)); 

    UCB1IFG = 0x20、这仍然是否定的。  那么、在发送0x00之前、我是否需要清除 NAK? 并应在 while 之后执行  

    UCB1TXBUF = 0x00; 

    因为它正在被发送。 (我未在示波器上看到它。)

    我将稍微播放一下、看看会发生什么情况。


    |


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

    您会得到 UCNAKIFG、因为总线上有一个 NAK。 NAK 为1 (高级)。
    (在 NAK 之后、您不得继续传输。)

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

    我稍微更改了您的代码。 它现在看起来是这样的。

    void write1_read32 (void)
    {
    UCB1I2CSA = 0x18;
    
    UCB1CTL1 |= UCTR + UCTXSTT;
    
    while (!(UCB1IFG & UCTXIFG));
    
    UCB1IFG = 0;
    UCB1TXBUF = 0x00;
    while (!(UCB1IFG & UCTXIFG));
    
    
    UCB1CTL1 &=~UCTR;
    UCB1CTL1 |= UCTXSTT;
    
    while (!(UCB1IFG & UCRXIFG));
    字节1 = UCB1RXBUF;
    
    while (!(UCB1IFG & UCRXIFG));
    字节2 = UCB1RXBUF;
    
    UCB1CTL1 |= UCTXSTP;
    while (!(UCB1IFG & UCRXIFG));
    字节3 = UCB1RXBUF;
    }
    

    一旦我可以将数据放入 UCB1TXBUF、就会立即传递第一个"while"。  

    该文档指出:

    USCI 模块检查总线是否可用、生成启动条件、并发送从器件
    地址。 当 START 条件被生成并且第一个数据将被发送时、UCTXIFG 位被置位
    发送的数据可以被写入 UCBxTXBUF。 一旦从器件确认地址
    UCTXSTT 位被清零。

    我们仍然存在 UCNAKIFG 问题、但我通过将 UCB1IFG 寄存器设置为0来忽略它

    然后我将0x00写入 UCB1TXBUF 缓冲区并等待它被发送。

    如果在从器件的发送过程中仲裁没有丢失、那么写入 UCBxTXBUF 的数据就会被发送
    地址。 一旦数据从缓冲器传输到移位寄存器、UCTXIFG 就会再次置位。 如果
    在应答周期前、没有数据被载入 UCBxTXBUF、在期间总线被保持
    SCL 为低电平的确认周期、直到数据被写入 UCBxTXBUF。 数据被传输或总线被传输
    只要 UCTXSTP 位或 UCTXSTT 位未置位、就会保持该状态。

    未写入数据。 (根据示波器。 它看起来与上面一样、只写入从器件地址。) 我只有一个主器件、因此我不知道如何失去仲裁。 但 UCTXIFG 未置1。
    UCB1IFG = 0x20、因为 NAK 发生在我清零 UCB1IFG 之后。

    因此、我仍然卡在同一个位置。  
     

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    从器件没有 ACK。 您不能传输任何数据、因为传输没有开始;清除 NAKIFG 不会改变这种情况。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    NAK 为1? 这是一个问题。

    我在文档中找不到它说什么是 ACK 或 NAK。 每次它都显示 ACK 位。 它没有任何地方说 ACK 是高电平或低电平。

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

    https://en.wikipedia.org/wiki/I²C#Physical_layer

    波形看起来正常。 可能是到从器件的连接错误、或电压电平错误。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我取得了一些进展、我将地址切换到了 I2C 总线上的另一个器件、并开始获得有效的响应。

    BQ7694006DBT 发生了什么情况。 他们说、当他们把这个板交给我时、这个板就能工作了。 :(

    我尝试编写一个循环、该循环将扫描所有128个地址以查看哪些地址会进行 ACK (以查看其位于另一个地址)、但它看起来像是在一个地址上发送数据、除非我循环通电、否则无法让它执行另一个操作。 我尝试添加 STOP、并重新初始化寄存器。 我是否需要知道秘密?


    现在仍在努力工作,但现在有了一些工作,进展应该很快得到改善。