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: Unable to get consistent I2C behavior with the MSP430FR5969 - UCSCLLOW doesn't change after setting UCTXSTT.

Part Number: MSP430FR5969

Tool/software:

Hi all,

I've been scratching my head on this one. Long story short, I am teaching myself I2C on the MSP430FR5969. I made the following circuit, consisting of an Arduino UNO and a MSP430FR5969 Launchpad. I connected P1.6 (SDA) and P1.7 (SCL) on the launchpad to SDA and SCL pins on the Arduino UNO. I also set the Launchpad to be a master transmitter and the Arduino Uno to be a slave receiver. I also have two 4.7 kOhm resistors connecting the SDA and SCL to a 5 V rail. 

What I have noticed is that the Launchpad would communicate through I2C initially because I can see the characters being received by the Arduino Uno via the serial monitor. But in the second time, the Launchpad will not run the ISR. I added some breakpoints and noticed that UCSCLLOW would not change. It remains 0. But when I reset the Arduino UNO and run the Launchpad with breakpoints again, UCSCLLOW would change to 1 right after I set UCTXSTT to the UCB0CTLW0 register.

I'm really confused. Some help would be greatly appreciated. I attached the two codes below. The address of the Arduino UNO is set to be 4.

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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) {
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
'

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • FYI, ignore the comment  on Line 30 that says the following:

     

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

  • 1) 

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

    This function starts a transaction, but doesn't wait for it to complete, so the second call tries to start while the I2C is busy. As a quick experiment, insert something like "__delay_cycles(1000);" in between.

    2) 

    > CSCTL1 = ~DCORSEL & ~DCOFSEL_2; // Set DCO to 1 MHz

    If I've done my arithmetic correctly, this sets RSEL=0, FSEL=5 (7MHz). That would run your I2C (/10) at 700kHz. I suspect you intended something more like:

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

    3) The I2C pins are not (true) open-drain, and must not be pulled up over about 3.6V. This is the kind of thing that could work for a while, until something burns up.

  • Bruce, having the __delay_cycles(1000); in between did resolve the issue. Do you have recommendations on where I can start on a more robust solution? Thank you very much.

  • P.S. You were also write about the clock. I think I goofed up my arithmetic on my end. Good catch.

  • Hey Andy,

    Glad Bruce was able to help you narrow in on your issues.  I did want to just provide some resources, this is probably our most robust I2C Host example: https://dev.ti.com/tirex/explore/node?node=A__ABsh79kxdPLraPXoO-jaAg__msp430ware__IOGqZri__LATEST 

    There is also a MSP430 Academy that covers this I2C example and how to modify it: https://dev.ti.com/tirex/explore/node?node=A__Adzfc.4g4jo4J768dzo1TA__MSP430-ACADEMY__8HaEUeq__LATEST 

    Thanks,

    JD

  • JD, thank you! I've been looking at the example and it makes sense for the most part. I do have two questions though.

    In Line 187, after the global interrupt enable bit is set, could it be possible that code past Line 187 gets executed before the MSP430 enters the ISR? If that is the case, wouldn't it lead to a possible data race condition.

    Also, for I2C_Master_ReadReg, why have the state and interrupt enable bits been set in such a way that causes UCTXIFG0 to be set?  Why not have the interrupt enable bits for UCRXIFG0 be set directly?

  • 1) Line 187 also sets LPM0_bits, which causes the CPU to halt there until those bits are cleared with __bic_SR_register_on_exit. [LPM0_bits==CPUOFF]

    2) ReadReg uses the I2C "register" model, where the sequence is (a) write register number [typically 1 byte] (b) repeated start (c) read data. This is setting up for (a), and (b)/(c) are performed in the ISR.

  • Bruce,

    Thank you again. Since I am still relatively new to the MSP430 and uC in general, do you know what section of the User's Guide I could find (1) in? I tried to look in Section 1.4 (Operating Modes), but couldn't find where it talks about that. 

  • These functions (really compiler intrinsics) implement the sequences described in UG (SLAU367P) Sec 1.4.2. In each pair, _bis_SR_register() is the first, and _bic_SR_register_on_exit() is the second. The LPMn_bits macros are provided so you don't have to memorize Table 1-2.

  • The device header file (msp430fr5969.h in this case) defines a variety of things, including macros to enter and exit the low power modes.

    I prefer the short versions:

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

**Attention** This is a public forum