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/MSP430F5529:I2C 主设备问题

Guru**** 2539500 points
Other Parts Discussed in Thread: MSP430F5529

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/570781/ccs-msp430f5529-problems-with-i2c-master

器件型号:MSP430F5529

工具/软件:Code Composer Studio

大家好

我有一个与传感器通信的板、但我想使用 MSP430F5529而不是该板。  我正在 MSP430 (主器件)和传感器(从器件)之间通过 I2C 进行通信。 我已经为主器件编写了代码、但无法完全正常工作。

这就是处理事务之间的延迟时的工作方式。  第一个延迟约为15us 、第二个延迟约为60us。 SMCLK 为200kHz。

主器件首先发送一个开始条件、然后发送寄存器地址(0)。 之后、他进行重启、从机发送数据(15)。

这就是它目前的情况。 问题是事务之间没有延迟、因此从站无法传输数据。 主器件始终接收"0"而不是"15"。   

以下是我的代码:

int main (空)

WDTCTL = WDTPW + WDTHOLD;//停止 WDT

P3SEL |= 0x03;//将 I2C 引脚分配给 USCI_B0

P8DIR |= BIT1;//将 P8.1设置为输出方向

P8OUT |= BIT1;

for (x=100;x>0;x--);

UCB0CTL1 |= UCSWRST;//启用 SW 复位

UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;// I2C 主器件、同步模式

UCB0CTL1 = UCSSEL_2 + UCSWRST;//使用 SMCLK

UCB0BR0 = 6;// fSCL = SMCLK/6 =~200kHz

UCB0BR1 = 0;

UCB0I2CSA = 0x55;//从器件地址为055h

UCB0CTL1 &=~UCSWRST;//清除 SW 复位,恢复运行

UCB0IE |= UCRXIE;//启用 RX 中断

UCB0CTL1 |= UCTR+UCTXSTT;// I2C 开始条件、写入

while (!(UCB0CTL1 & UCTXSTT));//确保发送了 START 条件

while (!(UCB0IFG & UCTXIFG));//等待数据可以被写入

UCB0IFG &=~UCTXIFG;//复位 Tx 中断标志

UCB0TXBUF = 0x00;//发送数据

while (!(UCB0IFG & UCTXIFG));//等待数据可以被写入

UCB0IFG &=~UCTXIFG;//复位 Tx 中断标志

UCB0CTL1 &=~UCTR;//设置接收器模式

UCB0CTL1 |= UCTXSTT;//发送重启

while (UCB0CTL1 & UCTXSTT);//等待直到 START 条件复位

UCB0IFG &=~UCRXIFG;//复位 Rx 中断标志

while (!(UCB0IFG & UCRXIFG));//等待接收标志被复位

__no_operation()//用于调试器

// 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 (_GNU_)

void __attribute__((中断(USCI_B0_vector)) USCI_B0_ISR (void)

其他

错误编译器不受支持!

#endif

switch (__evo_in_range (UCB0IV、12))

情况0:中断//向量0:无中断

情况2:中断//向量2:ALIFG

情况4:中断//向量4:NACKIFG

情况6:中断//向量6:STTIFG

情况8:中断//向量8:STPIFG

情况10://向量10:RXIFG

RXData = UCB0RXBUF;//获取 RX 数据

中断;

情况12:中断//向量12:TXIFG

默认值:break

有人知道我做了什么错误、或者我如何 解决这个问题吗?

 

感谢你的帮助

Fabian

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

    请重新发布您的图片、因为它们未正确附加。 您的代码不应手动更改 IFG、而是通过操作相应的缓冲寄存器来寻址这些 IFG。 您也不会启用全局中断、因此您的 ISR 永远不会被访问、您可以使用 IDE 的调试器来确认这一点。 我建议重温 TI 提供的 MSP430F55xx I2C 代码示例。

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

    您好、Ryan

    我目前不使用中断函数。

    这是图像

    当我将 降级板与传感器一起使用时、看起来像这样、字节之间存在延迟。  第一个延迟约为15us 、第二个延迟约为60us。 主器件首先发送一个带有从器件地址的起始条件、然后是寄存器地址(0)。 之后、他使用从器件地址进行重启 、从器件发送数据(15)。

    这就是使用 MSP430时的情况。 我认为问题是 字节之间没有延迟、因此从站无法传输数据。 字节之间通常有延迟吗?我该怎么做? 主器件始终接收"0"而不是"15"。   

    在主器件发送起始条件以及从器件地址和接收到的用于更正数据("15")的主器件之后设置断点后、我立即执行该操作。 这就是为什么我认为延迟是问题所在。

    以下是我的代码:

    #include 
    
    unsigned char RXData;
    int x;
    
    int main (void)
    {
    WDTCTL = WDTPW + WDTHOLD; //停止 WDT
    P3SEL |= 0x03; //将 I2C 引脚分配给 USCI_B0
    P8DIR |= BIT1; //将 P8.1设置为输出方向
    P8OUT |= BIT1;
    for (x=100;x>0;x--);
    UCB0CTL1 |= UCSWRST; //启用 SW 复位
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
    UCB0CTL1 = UCSSEL_2 + UCSWRST; //使用 SMCLK
    UCB0BR0 = 6; // fSCL = SMCLK/6 =~200kHz
    UCB0BR1 = 0;
    UCB0I2CSA = 0x55; //从器件地址为055h
    
    UCB0CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
    UCB0IE |= UCTXIE; //启用 TX 中断
    UCB0IE |= UCRXIE; //启用 RX 中断
    
    
    UCB0CTL1 |= UCTR+UCTXSTT;// I2C 启动条件、
    写入 while (!(UCB0CTL1 & UCTXSTT)); //确保在
    
    (!(UCB0IFG & UCTXIFG)时发送起始条件;//等待数据可以被写入
    UCB0TXBUF = 0x00;//在
    
    (!(UCB0IFG & UCTXIFG)时发送数据;//等待数据可以被写入
    UCB0CTL1 &=~UCTR;//设置接收器模式
    UCB0CTL1 |= UCTXSTT;//发送重启
    
    while (UCB0CTL1 & UCTXSTT);//等待直到 START 条件复位
    while (!(UCB0IFG & UCRXIFG));//等待接收标志被复位
    
    __no_operation(); //对于调试
    器}
    
    // 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 (__GICS__)
    _编译器(void)_ USCI_B0_b0_interrupt (void
    
    )#USCI_b0_b0_isr_)(void)
    #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 数据
    中断;
    案例12:中断; //向量12:TXIFG
    默认值:break;
    }
    

    感谢你的帮助

    Fabian

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    理论上、μ I²C 不需要在字节之间进行任何暂停(如果从器件需要更多时间、它可以进行时钟扩展)。

    但为什么要使用200kHz? 从器件实际上支持的频率是否超过100kHz? 尝试使用更少的。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    从站支持高达400kHz 的频率、但我将使用时钟扩展来尝试它
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这不是时钟扩展 的意义;如果受控器件支持、它将自动使用它。

    您可以尝试添加__delay_cycles (...) 在代码中等待循环之后。

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

    所以我误解了这一点。 感谢您的观看。

    但还有另 一个问题。  如果我添加 delay_cycle、它不会出现在确认结束时。  它出现 在 Byte 和确认之间。

    那么、如果我已经收到确认、我是否必须进行查询、或者我可以做什么?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    USCI 模块符合 μ I²C 规范。 如果你想做的事情超出这个范围、你必须使用位拆裂来编写你自己的 μ I²C 实现。

    (我不确定问题是否实际是延迟、但如果不了解从器件的任何信息、则无法进行调试。)
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在发送重新启动指令之前、您可以使用 UCBUSY while 循环来确认主器件已完成传输。 这样、__delay_cycles 函数将在通信序列期间的适当时间出现。

    您应该在代码的末尾放置一个永久性的 while 循环、这样它就不会完成 main、这样您就不需要依赖调试器在断点处停止。

    此致、
    Ryan

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

    这看起来是一个完全有效的读取事务。 在最后一次测量之后、您是否通过发送 EN 上的上升沿来实际进入工作模式?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当我添加 UCBUSY while 环路时、结果就是这样。 主机发送寄存器地址("0")、但我不会停止。 UCBUSY 只在一个停止后被清除。

    以下是我更改的代码部分:

    UCB0CTL1 |= UCTR+UCTXSTT;// I2C 开始条件、写入
    while (!(UCB0CTL1 & UCTXSTT)); //确保在
    
    (!(UCB0IFG & UCTXIFG)时发送起始条件;//等待数据可以被写入
    UCB0TXBUF = 0x00;//发送数据
    
    while (!(UCB0IFG & UCTXIFG);//等待数据可以被写入
    while (UCB0STAT 和 UCBBUSY);//等待总线不忙
    UCB0CTL1 &=~UCTR;//设置接收器模式
    UCB0CTL1 |= UCTXSTT;//发送重新启动
    
    
    while (UCB0CTL1 & UCTXSTT);//等待直到 UCB0CTG
    (UCB0CTL & UCTXSTT)条件被复位;//等待直到 UCB0IFG (UCB0IFG)
    
    __no_operation(); //用于调试器
    while (1); 

    要清洁男士 Ladisch:

    对于主器件发送第一个启动条件、EN 上有1ms 的上升沿、EN 保持高电平到最后

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

    我想"第一次启动"是指"每次启动、而不是重新启动"?

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

    不只有一次。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我的错误 Fabian、我忘记了 UCBUSY 主要适用于 SPI 和 UART、而不是 I2C。 您是否尝试使用中断而不是轮询? TI 提供了多个示例、值得至少尝试查看这些示例是否会改变问题的行为。

    此致、
    Ryan
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我解决了这个问题。
    我唯一需要的是在 EN 高电平和启动条件之间有更多的时间、如上图所示。 但感谢大家的帮助。