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.

MSP430FR6989: Why isn't the I2C interrupt flag triggering?

Part Number: MSP430FR6989

Here are some setup functions I've used to initialize my system:

void accel_init() {

	//PIN CONFIGURATION for I2C on P4.0 and 4.1. Note 4.0 is SDA, 4.1 is SCL
	P4SEL1 |= (SDA | SCL);
	P4SEL0 &= ~(SDA | SCL);

	UCB1CTLW0 |= UCSWRST;//This command enables setup of the UCB.
	UCB1CTLW0 |= UCMODE_3 | UCMST | UCSYNC | UCSSEL_2;//I2C mode | master | synchronous | SMCLCK
	UCB1CTLW0 &= ~UCTR;//receiving data mode
	UCB1CTLW1 |= UCASTP_2;//stop condition generated automatically
	UCB1BRW = 3;//set baud rate, 10^6/3=333.333k
	UCB1BR1 = 0;

	UCB1TBCNT = 1;//send one byte at a time to slave
	UCB1I2CSA = 0x26;//address of slave.

	UCB1CTLW0 &= ~UCSWRST;//disable setup of the UCB.

	//Interrupts:
	UCB1IE |= UCRXIE | UCNACKIE | UCBCNTIE | UCSTPIE;//currently receive interrupt | nack interrupt | cnt value reached interrupt | start interrupt

}

void initMSP430(void) {

    /*********************** Test Data Generator 1 kHz *********************/
	P9DIR   |= BIT1 | BIT2 | BIT3 | BIT4;   // Test Data Output
	TA2CTL   = TASSEL__SMCLK | MC__CONTINUOUS | TACLR;
	TA2CCR1  = 1000;                                    // 1MHz * 1/1000 Hz
	TA2CCTL1 = CCIE;                                    // enable interrupts
	testcnt  = 0;                                       // start test counter at 0

    /**************************** PWM Backlight ****************************/

	P1DIR   |= BIT3;
	P1SEL0  |= BIT3;
	P1SEL1  &= ~BIT3;
	TA1CCR0  = 511;
	TA1CCTL2 = OUTMOD_7;
	TA1CCR2  = 255;
	TA1CTL   = TASSEL__ACLK | MC__UP | TACLR;

    /******************************** SPI **********************************/

	P2DIR  |=   LCD_CS_PIN;	                    // DC and CS
	P4DIR  |=   LCD_DC_PIN;
	P1SEL0 |=   LCD_MOSI_PIN | LCD_UCBCLK_PIN;      // MOSI and UCBOCLK
	P1SEL1 &= ~(LCD_MOSI_PIN | LCD_UCBCLK_PIN);

	UCB0CTLW0 |= UCSWRST;		// Reset UCB0

    /*
     * UCBxCTLW0 	 - eUSCI_Bx Control Register 0
     * UCSSEL__SMCLK - SMCLK in master mode
     * UCCKPL 		 - Clock polarity select
     * UCMSB		 - MSB first select
     * UCMST		 - Master mode select
     * UCMODE_0      - eUSCI mode 3-pin SPI select
     * UCSYNC		 -	Synchronous mode enable
     */
    //UCB0CTLW0 |= UCSSEL__SMCLK | UCCKPL | UCMSB | UCMST | UCMODE_0 | UCSYNC;
	UCB0CTLW0 |= UCSSEL__SMCLK | UCCKPH | UCMSB | UCMST | UCMODE_0 | UCSYNC;
    //    UCB0CTLW0 = UCCKPH + UCMSB + UCMST + UCSYNC + UCSSEL_2; // 3-pin, 8-bit SPI master


	UCB0BR0   |= 0x01;         // Clock = SMCLK/1
	UCB0BR1    = 0;
	UCB0CTL1  &= ~UCSWRST;     // Clear UCSWRST to release the eUSCI for operation
	PM5CTL0   &= ~LOCKLPM5;    // Unlock ports from power manager

	__enable_interrupt();

}

And here is my main function:

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// kill the watchdog

    initMSP430();
    accel_init();

    __delay_cycles(10);

	/*The goal now is to send the desired information when the interrupts are enabled
	 * I will try to do this using the cnt interrupt system*/
    	UCB1CTLW0 |= UCTR | UCTXSTT;//start transmitting
    	UCB1TXBUF = 0x01;//send 1



    while (TRUE) {
    	P6DIR ^= BIT1;//just whatever. _nop() would probably be fine here too.
    }
}

I simply want the UCBCNTIFG to trigger. In debug mode, the flag is never thrown. I do not understand why. According to the Family User Guide (pg. 841 of the April 2020 revision) this interrupt is available in master mode. It should occur after transmitting one byte because I've set UCB1TBCNT = 1 and because automatic stop conditions are being generated per UCB1CTLW1 |= UCASTP_2. The interrupt is enabled is the accel_init() function, and __enable_interrupt() is called in the initMSP430() function, so GIE should be set. I have the system set to transmitting mode and call the start condition in main(). The buffer could contain whatever, but happens to be 0x01.

Since I am sending a byte, and UCB1 is tied to the smclk, my expectation is that it will take somewhere around 8 clock cycles for it to send a byte. Thus, the interrupt flag should throw around that time, and it should fall into my ISR (which is an infinite while loop where I've stuck a breakpoint in the debugger). However, it does not. The interrupt is not triggering at all, and I don't understand why. Instead, the program falls into the main() while() loop that just toggles an unused pin direction. 

Can anyone shed some light on this? With my device, I can't get any interrupt flags to throw when attempting I2C communications, and I'm worried I've done something improper in the setup. I can't rule out a hardware issue, but if the flag should throw here, and there's nothing wrong with the software, then that would suggest a hardware problem.

Any help would be greatly appreciated.

  • I suggest you insert something like "while (!(UCB1IFG & UCTXIFG))/*EMPTY*/;" between setting STT and setting TXBUF.

    Notwithstanding User Guide (SLAU367P) Fig 32-12, I'm not convinced the TXIFG=1 is instantaneous.

  • I've actually tried using just such a loop. Unfortunately, the UCTXIFG flag never raises, and so it just sits in that loop forever. This is part of the reason I'm exploring interrupt-based options, and it's also part of why I suspect a hardware issue. Sadly, I don't have a second copy of the sensor I'm using to compare with, and so - for the time being - I'm trying to ensure the software isn't improperly configured.

    At any rate, I'll add the loop to see if it changes any behavior, since I haven't tried it in this context yet. Perhaps it will have an impact.

  • The only reason I can think of for TXIFG not to set (with UCTR=1) is that the bus itself is in a bad state, such that the I2C unit can't issue the Start. Do you have a scope?

  • I do have a scope. I've checked the activity on the lines and found no sign of activity. Basically, once configured, the system stays in the I2C idle state. Even when triggering the scope on an edge (for both the SCL and SDA lines), I see no activity unless I press the MSP430 reset button, in which case I'll detect the rising/falling edges as the system goes from idle to reset and back to idle.

    Possibly the most surprising result of this is that the SCL line isn't changing. That should be bound to SMCLK, yet nothing is happening on the line at all. I may be wrong, but my understanding of this functionality is that I do not need a timer to drive the SCL line (or the SDA line). Instead, when I "bind" it to a clock (SSEL_2 in this case), that should drive everything automatically, and I only need to send start/stop conditions, pick the data, select a send/receive mode, etc.

  • But, to add an additional thought, I suppose if there's an issue with the MSP430 seeing the start condition when I set it, that would mean things would stay in the idle state. Though, if that's the case, I think that would imply the problem is with the MSP430 rather than my peripherals.

  • I put your code on a Launchpad with an LIS3DH breakout attached. I didn't add a UCB1 ISR, I just let it fall into isr_trap and looked at the registers. 

    With the code as-is, it hung with TXIFG requested (no CNTIFG).

    When I added that line I suggested, it went through the entire transaction, and hit the ISR with CNTIFG=1 (and STPIFG=1).

    I'm not sure what we're doing differently.

    Here's the second (success) case:

  • By "idle" I suppose you mean "high". If the I2C unit pulls a wire low, and it doesn't go low, it can really only conclude "I'm not in control of the bus", which is a slightly weaker statement. This is a fairly unusual case, and it might (e.g.) mean that something is actively driving the bus high -- that's not supposed to happen, but that's not the I2C unit's purview.

    The more common case is that it releases the bus but it doesn't go high. If we're talking about SCL, that's just clock-stretching. If it's SDA, there's a section about that in UM10204 [3.1.16], for which a (somewhat glib) paraphrase would be "you're sunk".

    [Edit: Added section number]

**Attention** This is a public forum