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.

Launchpad MSP430FR5969 i2c driverlib hangs on while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG))

Other Parts Discussed in Thread: MSP430FR5969

Hello all. This is my first time posting in the forums here, but I did some digging around prior to this to try to make sure I wasn't being redundant in the issue I'm having. I saw an almost identical issue here, but it appears the initial problem was resolved by the poster and the solution to the initial question was not part of the discussion:

https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/363136#pi316701filter=all&pi316701scroll=false 

I'm attempting to use the msp430FR5969 to read temperature data from an mcp9808. I have constructed the following code based on as much information as I could gather regarding driverlib and the mcp9808. When I debug the code in CC, the initTempSensor() function runs all the way through, but the readTempsensor() method hangs on waiting for the interrupt flag within EUSCI_B_I2C_masterReceiveSingleByte() in the driverlib:

while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG))

My question is this; I have the interrupt enabled, I have configured and enabled the msp430 as a master device, I have enabled the secondary module function on the i2c pins; I am I doing any of these things improperly, or is there something obvious I missed that I need to add or take out of the code below to allow the flag to trigger?

Code:

#include "TempSensor.h"
#include "main.h"
#include "driverlib.h"
#include "math.h"
#include "time.h"

volatile unsigned char * tempUnit = &BAKMEM4_H;         // Temperature Unit
int degC;                          // Celcius measurement

const unsigned char TXData[] = { 0xA1, 0xB1, 0xC1, 0xD1 };
volatile unsigned char TXByteCtr;
void initTempSensor()
{
    
    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_P1,
        GPIO_PIN6 + GPIO_PIN7,
        GPIO_SECONDARY_MODULE_FUNCTION
        );

    EUSCI_B_I2C_initMasterParam param={};
    param.selectClockSource=EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
    param.dataRate=EUSCI_B_I2C_SET_DATA_RATE_100KBPS,
    param.i2cClk=CS_getSMCLK();
    param.byteCounterThreshold=1;
    param.autoSTOPGeneration=EUSCI_B_I2C_NO_AUTO_STOP;

    EUSCI_B_I2C_initMaster(EUSCI_B0_BASE, &param);

    // Specify slave address
    EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE, 0x18);
    // Set in transmit mode
    EUSCI_B_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);

    //enable interrupt
    EUSCI_B_I2C_enableInterrupt(EUSCI_B0_BASE,EUSCI_B_I2C_TRANSMIT_INTERRUPT0 +
           EUSCI_B_I2C_STOP_INTERRUPT);

    //Enable USCI_B_I2C_Module to start operations
    EUSCI_B_I2C_enable(EUSCI_B0_BASE);
    // Delay if bus is busy
    while(EUSCI_B_I2C_isBusBusy(EUSCI_B0_BASE));
    // Send single byte data specifying the register to read from on the mcp9808
    EUSCI_B_I2C_masterSendSingleByte(EUSCI_B0_BASE, 0x05);

}
int readTempSensor()
{
    // Set in receive mode
    EUSCI_B_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
    //Enable USCI_B_I2C_Module to start operations
    EUSCI_B_I2C_enable(EUSCI_B0_BASE);

    unsigned char tempHighByte, tempLowByte;

    //The mcp9808 sends a high and low byte back consecutively with the temperature data 
    tempHighByte=EUSCI_B_I2C_masterReceiveSingleByte(EUSCI_B0_BASE);
    while(EUSCI_B_I2C_isBusBusy(EUSCI_B0_BASE));
    tempLowByte=EUSCI_B_I2C_masterReceiveSingleByte(EUSCI_B0_BASE);
    while(EUSCI_B_I2C_isBusBusy(EUSCI_B0_BASE));
    __delay_cycles(100);
    return tempLowByte | (tempHighByte << 8);
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)) { case USCI_NONE: break; // Vector 0: No interrupts case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG UCB0CTLW0 |= UCTXSTT; // resend start if NACK break; case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3 case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3 case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2 case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2 case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1 case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1 case USCI_I2C_UCRXIFG0: break; // Vector 22: RXIFG0 case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0 if (TXByteCtr) // Check TX byte counter { //UCB0TXBUF = TXData[SlaveFlag]; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB0CTLW0 |= UCTXSTP; // I2C stop condition UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } break; default: break; } }
  • *Quick edit, the readtempsensor function should have a close bracket ( } ) after the return, not sure how that got left out
  • Hi Zachary,
    You have mentioned that initTempSensor() runs all the way through. Do you mean the EUSCI_B_I2C_masterSendSingleByte successfully sends the byte at the end of initTempSensor?
    I also see that the following code snippet is missing in your initialization./*
    * Disable the GPIO power-on default high-impedance mode to activate
    * previously configured port settings */ PMM_unlockLPM5();Thanks,
    Kasthuri
  • Hi Kasthuri,
    Thank you for your prompt response. I added PMM_unlockLPM5(); . I just looked at the SDA and SCL lines with a scope and it does not appear there is any output signal; I appears that EUSCI_B_I2C_masterSendSingleByte does not successfully send a byte at the end of initTempSensor.
  • I was looking over some other documenation; it looks like the issue may exist in the pin settings; do you have any thoughts on this? I know the hardware i2c pins are P1.6 and P1.7; I understand the pins have to be set as (input or output?) prior to using i2c and must have the secondary module function set. I was a little confused by this as the boosterpacj header on the launchpad lists two other pins as SDA and SCL, but those are software pins in the boosterpack standard that don't appear to work with driverlib.
  • Hello Zach,

    I'm not if you worked out your issues here. please tell us if you have. As far as using HW pins for I2C, you are correct that this does not conform to the LaunchPad (LP) standard due to compatibility reasons. You still can use HW pins for I2C by setting pins 1.6/1.7. Just keep in mind that in the standard these are SPI pins and some BoosterPacks (BPs) are configured that way. This means you will loose some compatibility with some BPs. Some customers have chosen this route and some BPs come with alternate pin configurations for this reason, especially when the performance of HW I2C is needed on 20-pin layout LPs.

    Regards,
    JH
  • Dear Zachary Farmer and Others

    Did you find a solution for this issue? I am stuck in the same line in my code as shown below.

    void EUSCI_B_I2C_masterSendMultiByteStart(uint16_t baseAddress,

                                             uint8_t txData)

    {

       //Store current transmit interrupt enable

       uint16_t txieStatus = HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE;

       //Disable transmit interrupt enable

       HWREG16(baseAddress + OFS_UCBxIE) &= ~(UCTXIE);

       //Send start condition.

       HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTR + UCTXSTT;

       //Poll for transmit interrupt flag.

       while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG))

       {

           ;

       }

       //Send single byte data.

       HWREG16(baseAddress + OFS_UCBxTXBUF) = txData;

       //Reinstate transmit interrupt enable

       HWREG16(baseAddress + OFS_UCBxIE) |= txieStatus;

    }

    Program never leaves the loop i have highlighted. If you have found a solution, please be kind enough to share.

    Help from anyone is highly appreciated.

  • Hi Zachary and othes.

    I thought I should contribute since I stumbled across these issues. I'm also hoping to use driverlib functions to control a variety of I2C peripherals. I came to grief in a few places and have a few work arounds that seem to work for me.

     

    1)     EUSCI_B_I2C_masterSendMultiByteStartWithTimeout : Where driverlib sets the start bit, I had to add in a check for the falling edge of the start flag or it hangs up further on down. Without this check I believe the code executes straight through to the sending of the single byte of data to the TX buffer before the I2C peripheral is ready to receive it. I can see this on a scope. Here's my hacked version.




    bool EUSCI_B_I2C_masterSendMultiByteStartWithTimeout(uint16_t baseAddress, uint8_t txData, uint32_t timeout) { //Store current transmit interrupt enable uint16_t txieStatus = HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE; //Disable transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) &= ~(UCTXIE); //Send start condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTR + UCTXSTT; // wait until start flag falls (after slave addr). while(EUSCI_B_I2C_masterIsStartSent(EUSCI_B0_BASE)) { ; } //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Reinstate transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) |= txieStatus; return(STATUS_SUCCESS); }

    2) I wanted to then use EUSCI_B_I2C_masterReceiveSingleByte to implement a restart condition and read back a single byte. I found that this function fails when it tries to simultaneously write the start and stop flags. The stop flag is lost, the I2C peripheral does not send the expected NACK, and it finds itself attempting to do subsequent reads, and in doing so it holds the bus hostage. I amended the function as follows:

        	// Wait until transmitted byte is done.
        	while(!(HWREG16(EUSCI_B0_BASE + OFS_UCBxIFG) & UCTXIFG))
        	    {
        	        ;
        	    }
    
    
            //Set USCI in Receive mode
            HWREG16(EUSCI_B0_BASE + OFS_UCBxCTLW0) &= ~UCTR;
    
            //Send start.
            HWREG16(EUSCI_B0_BASE + OFS_UCBxCTLW0) |= UCTXSTT;
    
            // wait until start flag falls (after slave addr).
            while(EUSCI_B_I2C_masterIsStartSent(EUSCI_B0_BASE))
            {
            	;
            }
    
            // send stop
            HWREG16(EUSCI_B0_BASE + OFS_UCBxCTLW0) |= UCTXSTP;
    
            //Poll for receive interrupt flag.
            while(!(HWREG16(EUSCI_B0_BASE + OFS_UCBxIFG) & UCRXIFG))
            {
                ;
            }
    
            //Send single byte data.
            i2cData[0] =  (HWREG16(EUSCI_B0_BASE + OFS_UCBxRXBUF));
    

     

    2 randon thoughts:

    1. Are there any requirement on the speed of the clocks here. I've tried this with the MCLK set to 8 times the SMCLK that drives the I2C and again with MCLK = SMCLK, with the same outcome. And I've slowed the transfer baud right down. Which does set alarm bells ringing a bit.

    2. It also occurs to me that code were broken up into smaller chunks and implemented inside an interrupt handler, the problems might go away, if care was taken with the interrupts. But as it stands, it looks like these driverlib functions don't quite work? Although, that not to say they aren't an awesome resource, and a fantastic starting point. Is there anyone out there who is thinking 'that guys doesn't know what he's talking about! He's doing it all wrong'. If so, please put me straight! I love it when I'm wrong. That way, I learn something!

    Thanks all,

    Al.

**Attention** This is a public forum