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.

[参考译文] MSP430FR5969:无法获得与 MSP430FR5969一致的 I2C 行为-设置 UCTXSTT 后 UCSCLLOW 不#39;t 改变。

Guru**** 2451970 points
Other Parts Discussed in Thread: MSP430FR5969

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1482679/msp430fr5969-unable-to-get-consistent-i2c-behavior-with-the-msp430fr5969---ucscllow-doesn-t-change-after-setting-uctxstt

器件型号:MSP430FR5969

工具与软件:

大家好!

我一直在研究这个。 长话短说、我是在 MSP430FR5969上教自己的 I2C。 我制造了以下电路、其中包含一个 Arduino UNO 和一个 MSP430FR5969 Launchpad。 将 LaunchPad 上的 P1.6 (SDA)和 P1.7 (SCL)连接到 Arduino UNO 上的 SDA 和 SCL 引脚。 我还将 Launchpad 设置为主发送器、将 Arduino Uno 设置为从接收器。 我还通过两个4.7k Ω 电阻将 SDA 和 SCL 连接到5V 电压轨。  

我注意到的是、Launchpad 最初会通过 I2C 进行通信、因为我可以看到 Arduino Uno 通过串行监视器接收的字符。 但在第二次操作中、Launchpad 将不会运行 ISR。 我添加了一些断点、并注意到 UCSCLLOW 不会改变。 它保持为0。 但当我复位 Arduino UNO 并再次使用断点运行 Launchpad 时、在我将 UCTXSTT 设为 UCB0CTLW0寄存器后、UCSCLLOW 将立即更改为1。

我真的很困惑。 非常感谢您提供一些帮助。 我附上了下面的两个代码。 Arduino UNO 的地址设置为4。

#include <msp430.h>
#include <stdbool.h>
#include <stdint.h>

static inline
void launchpad_clk_config(void) {
    // The SMCLK will be used for both the SPI communication and the timers.
    // Due to the FRAM, we need to add in a wait condition so that higher frequencies can be used.

    CSCTL0_H =  CSKEY >> 8;                                  // Unlock CS registers for modification.
    CSCTL1   = ~DCORSEL & ~DCOFSEL_2;                        // Set DCO to 1 MHz
    CSCTL2   =  SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;  //
    CSCTL3   =  DIVA__1 | DIVS__1 | DIVM__1;                 // Set all dividers
    CSCTL0_H =  0;                                           // Lock CS registers back.
}

#define LP_SDA  BIT6
#define LP_SCL  BIT7

static inline
void launchpad_env_config(void) {
    P1SEL1    |=  LP_SDA;
    P1SEL0    &= ~LP_SDA;

    P1SEL1    |=  LP_SCL;
    P1SEL0    &= ~LP_SCL;

    UCB0CTL1  |=  UCSWRST;
    UCB0CTLW0 |=  UCMODE_3 + UCSYNC + UCMST + UCSSEL_2; // Using the SMCLK, and transmit.
    UCB0BRW    =  10;                                   // SMCLK will generate a clock of 12 MHz, which will be divided by 30 to yield 400 KHz
    UCB0CTLW1  =  UCASTP_2;                             // automatic STOP assertion
    UCB0CTL1  &= ~UCSWRST;                              // eUSCI_B in operational state
    UCB0IFG    =  0;
}

static inline
void launchpad_env_write(const char addr, const char bytes) {
    UCB0CTL1  |=  UCSWRST;
    UCB0TBCNT  =  bytes;
    UCB0I2CSA  =  addr;
    UCB0CTL1  &= ~UCSWRST;

    UCB0CTLW0 |=  UCTR;
    UCB0IE    |=  UCTXIE0 + UCSTTIE + UCNACKIE;
    UCB0CTLW0 |=  UCTXSTT;
}

char num = '9';

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;
    PM5CTL0 &= ~LOCKLPM5;

    launchpad_clk_config();
    launchpad_env_config();

    __enable_interrupt();

    launchpad_env_write(4, 1);
    launchpad_env_write(4, 1);
}

#pragma vector=USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void) {
    switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)) {
        case USCI_NONE:
            __no_operation();
            break;
        case USCI_I2C_UCNACKIFG:
            __no_operation();
            break;
        case USCI_I2C_UCTXIFG0:
            UCB0TXBUF = num++;
            break;
        case USCI_I2C_UCRXIFG0:
            __no_operation();
            break;
        default:
            break;
    }
    return;
}
'

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

#include <Wire.h>

void setup() {
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
  delay(1);
}

void receiveEvent(int howMany) {
  while (Wire.available()) {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);      // print the character
  }
}

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

    仅供参考、请忽略 第30行的以下评论:

     

    // SMCLK will generate a clock of 12 MHz, which will be divided by 30 to yield 400 KHz

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

    1)  

    > launchpad_env_write(4, 1);
    > launchpad_env_write(4, 1);

    此函数启动一个事务、但不等待它完成、因此第二个调用会在 I2C 繁忙时尝试启动。  作为快速实验、在中间插入"__delay_cycles (1000);"之类的内容。

    2)  

    > CSCTL1 =~Δ V DCORSEL 且 Δ V DCOFSEL_2;~将 DCO 设为1 MHz

    如果我已经正确地完成了算术运算、这将设置 RSEL=0、FSEL=5 (7MHz)。 这将以700kHz 的频率运行 I2C (/10)。 我怀疑您想要的东西更像:

    CSCTL1 &=Δ~(DCORSEL | DCOFSEL_7);// RSEL=0、FSEL=0 -> 1 MHz

    3) 3) I2C 引脚不是(真)开漏、并且 不得上拉至超过大约3.6V。 这是一种可以工作一段时间,直到某个东西烧毁。

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

    Bruce、用__delay_cycles (1000);中间的步骤确实解决了问题。 关于如何着手开发更稳健的解决方案、您有什么建议吗? 非常感谢。

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

    此外、您还撰写了有关时钟的内容。 我想,我的鸡巴在妈妈的屁眼里已经完全放不下了 不错的地方

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

    嗨、Andy、

    很高兴 Bruce 能够帮助您缩小问题范围。  我只想提供一些资源、这可能是我们最强大的 I2C 主机示例: https://dev.ti.com/tirex/explore/node?node=A__ABsh79kxdPLraPXoO-jaAg__msp430ware__IOGqZri__LATEST 

    还有一个 MSP430 Academy 涵盖了这个 I2C 示例以及如何修改: https://dev.ti.com/tirex/explore/node?node=A__Adzfc.4g4jo4J768dzo1TA__MSP430-ACADEMY__8HaEUeq__LATEST 

    谢谢!

    JD

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

    JD、谢谢您! 我一直在查看该示例、其中大部分内容都是有道理的。  不过、我有两个问题。

    在行187中、设置了全局中断使能位后、是否有可能在 MSP430进入 ISR 之前执行过行187的代码? 如果是这种情况、不会导致可能的数据竞态条件。

    另外 、对于 I2C_UIFG0、为什么状态和中断使能位的设置方式会使 Master_Read 被置位?  为什么不直接设置 UCRXIFG0的中断使能位?

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

    1)第187行还设置了 LPM0_BITS、这会导致 CPU 在该处停止、直到使用 _BIC_SR_register_on_exit 清除这些位。 [LPM0_BITS==CPUOFF]

    2) ReadReg 使用 I2C"寄存器"模型、其中序列为(a)写入寄存器编号[通常为1个字节](b)重复开始(c)读取数据。 这是针对(a)进行的设置、(b)/(c)在 ISR 中执行。

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

    Bruce、

    再次感谢你。 由于我仍然相对较新、一般而言 MSP430和 uC、您知道我可以在用户指南的哪个部分(1)中找到(1)吗? 我试图查看第1.4节(工作模式)、但找不到它与之相关的地方。  

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

    这些函数(REQUIRED 编译器内在函数)实现了 UG (SLAU367P) 1.4节中描述的序列。 在每一对中,_bis_SR_register()是第一个,而_BIC_SR_register_on_exit()是第二个。 提供了 LPMn_BITS 宏、您无需记忆表1-2。

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

    器件头文件(本例中为 msp430fr5969.h)定义了各种内容、包括用于进入和退出低功耗模式的宏。

    我更喜欢短版本:

    #define LPM0      __bis_SR_register(LPM0_bits)         /* Enter Low Power Mode 0 */