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/MSP430FR6989: Capture/Compare Interrupt not working with HR-S04 Ultrasonic Sensor

Part Number: MSP430FR6989

Tool/software: Code Composer Studio

I am currently trying to interface the HR-S04 Ultrasonic Distance Sensor to the MSP430FR6989. I have found several times over where the code has ben written, yet the code that supposedly works for others will not work for me. One difference between my scenario and the scenario that others are seen using is that I do not have an external LCD that I am printing to, and instead I am either trying to display the output to the onboard LCD on the Launchpad, or (since that didn't work for me) I am attempting to write it to the terminal via UART. Below is my code, as well as my guesses to what could potentially be the issue(s):

#include <msp430fr6989.h>

#include <stdio.h>

#define redLED BIT0

#define greenLED BIT7

#define US_TRIG         BIT4

#define US_ECHO         BIT5

#define FLAGS_TERM      UCA1IFG

#define RXFLAG          UCRXIFG

#define TXFLAG          UCTXIFG

#define TERM_TXBUFFER   UCA1TXBUF

#define TERM_RXBUFFER   UCA1RXBUF

unsigned int up_counter = 0,down_counter, distance_cm = 0, count = 0;

void initialize_TERM_UART(void)

{

    P3SEL1 &= ~ (BIT4|BIT5);

    P3SEL0 |= (BIT4|BIT5);

    UCA1CTLW0 |= UCSSEL_2;

    UCA1BRW = 8;

    UCA1MCTLW = UCBRS3 | UCBRS2| UCBRS0 | UCBRS6_H | UCBRS5_H;

    UCA1MCTLW &= ~UCOS16;

    UCA1CTLW0 &= ~ UCSWRST;

    UCA1IE |= UCRXIE;

    UCA1IFG &= ~RXFLAG;

}

void uart_write_char_TERM(unsigned char ch)

{

    // Wait for any ongoing transmission to complete

    while ( (FLAGS_TERM & TXFLAG)==0 ) {}

    // Write the byte to the transmit buffer

    TERM_TXBUFFER = ch;

}

void uart_digit_sep_TERM(unsigned int n)

{

    unsigned int digit;

    if (n >= 10000)

        {

            digit = (n/10000) % 10;

            uart_write_char_TERM(digit + '0');

        }

    if (n >= 1000)

        {

            digit = (n/1000) % 10;

            uart_write_char_TERM(digit + '0');

        }

    if (n >= 100)

    {

        digit = (n/100) % 10;

        uart_write_char_TERM(digit + '0');

    }

    if (n >= 10)

    {

        digit = (n/10) % 10;

        uart_write_char_TERM(digit + '0');

    }

    digit = (n % 10);

    uart_write_char_TERM(digit + '0');

    uart_write_char_TERM(' ');

}

#pragma vector = TIMER0_A0_VECTOR

__interrupt void TimerA0_ISR(void)

{

    P1OUT ^= redLED;

    P9OUT ^= greenLED;

    if (TA0CCTL0 & CCI)            // I wasn't sure if this is correct as CCI is the second bit in the TA0CCTL0 register, and by excluding a "!=0" or other equivalence could be incorrect

    {

        up_counter = TA0CCR0;      // Copy counter to variable

    }

    else

    {

        distance_cm = (TA0CCR0 - up_counter)/58;

        uart_digit_sep_TERM(distance_cm);

        uart_write_char_TERM('\n');

        uart_write_char_TERM('\r');

    }

}

/*

#pragma vector = TIMER0_A1_VECTOR

__interrupt void T0A1_ISR()

{

    P1OUT ^= redLED;

    P9OUT ^= greenLED;

    TA0CTL &= ~TAIFG; 

} //I know that the timer was not set up for rollover events, but I included this ISR just in case there was any weird scenario that I was unaware of

*/

void timer_init()

{

    TA0CCTL0 |= CM_3 + SCS + CCIS_0 + CAP + CCIE;

    TA0CCTL0 &= ~ CCIFG;

    TA0CTL |= TASSEL_2 + MC_2 + ID_0;

}

int main()

{

    WDTCTL = WDTPW | WDTHOLD;       // Stop Watch Dog Timer

    PM5CTL0 &=  ~LOCKLPM5;

    P1DIR |= redLED + US_TRIG;

    P9DIR |= greenLED;

    P1OUT &= ~(redLED | US_TRIG) ;

    P9OUT |= greenLED;

    P1DIR &= ~US_ECHO;        // Input direction for echo from sensor

    P1SEL1 |= US_ECHO;                // set US_ECHO as trigger for Timer from Port-1

    P1SEL0 |= US_ECHO;

    // Initialize timer for Ultrasonice distance sensing

    timer_init();

    initialize_TERM_UART();

    _enable_interrupts();

    while (1)

    {

        // measuring the distance

        P1OUT |= US_TRIG;                 // assert

        __delay_cycles(15);                 // 10us wide

        P1OUT &= ~US_TRIG;                 // deassert

        __delay_cycles(500000);             // 0.5sec measurement cycle

    }

}

I found in the User's Guide (slau367o) that the TAIV interrupt register only has capture/compare for TAxCCR1 through TAxCCR6 (i.e. doesn't include TA0CCR0) and this leads me to question whether or not the CCI technique works with TA0.0. 

When I run the above program in debug mode, the TIMER0_A0_VECTOR ISR is never entered, which tells me that the interrupt is either not configured correctly or as I stated above TA0.0 is not able to handle CCIE events. This is confusing for me as numerous others are able to run the code above and they state that it works correctly for them.

  • Alex,

    Please give me a couple of business days to look into this and then I will get back to you. Thank you for your patience.

    Best regards,

    Matt

  • Hi Alex,

    I think it would help if you read through Chapter 25 of the device family user's guide that you mention in your post. One thing you will notice when you read through that chapter is that there are two different interrupt vectors associated with the 16-bit Timer_A module. When an input capture event occurs on TAxCCR0 and the timer is configured properly, the CCIFG flag is set corresponding TAxCCR0 interrupt vector is executed. The TAxIV interrupt vector sources the other timer capture/compare channels so an event on the CCR0 channel will not trigger the TAxIV interrupt.

    You mention that the above code works for other individuals but not you, and that the only difference is that your source code implements a different communication strategy for sending out the data. Have you tried stripping your code down to just the timer functionality to see if you are able to get that working by itself first before attempting to incorporate the additional functionality?

    P.S. For future code uploads, please use the "insert code" tool so that it is easier to read when trying to debug.

    Best regards,

    Matt

  • Hi Matt, thanks for your thorough reply.

    I'll respond backwards to your reply as that may read better. I will use the code function from now on; this is actually my first post here so I wasn't even aware of that feature. 

    In regards to the communication protocol, I have used the exact same protocol/set up in other projects and it worked fine then, my only thought about that would be if I potentially configured the timers differently in the UART initialization block vs the main function. I incorporated the UART function as other than inserting breakpoints in the code, I am unaware of how to test the code to check the interrupts. Would you happen to have any creative ideas for that?

    I will read more thoroughly in the family user guide as you suggested and see if I can find anything. In the mean time, did you see anything perhaps in the timer configuration or the UART configuration that could be an issue? I will copy/paste it here using the insert code function so it is more readable. 

    void timer_init()
    {
        /* Timer A0 configure to read echo signal:
        Timer A Capture/Compare Control 0 =>
        capture mode: 1 - both edges +
        capture synchronize +
        capture input select 0 => P1.5 +
        capture mode +
        capture compare interrupt enable */
        TA0CCTL0 |= CM_3 + SCS + CCIS_0 + CAP + CCIE;
        TA0CCTL0 &= ~ CCIFG;
    
        /* Timer A Control configuration =>
        Timer A clock source select: 1 - SMClock +
        Timer A mode control: 2 - Continuous up +
        Timer A clock input divider 0 - No divider */
        TA0CTL |= TASSEL_2 + MC_2 + ID_0;
    }
    
    void initialize_TERM_UART(void)
    {
        P3SEL1 &= ~ (BIT4|BIT5);
        P3SEL0 |= (BIT4|BIT5);
        UCA1CTLW0 |= UCSSEL_2;
        UCA1BRW = 8;
        UCA1MCTLW = UCBRS3 | UCBRS2| UCBRS0 | UCBRS6_H | UCBRS5_H;
        UCA1MCTLW &= ~UCOS16;
        UCA1CTLW0 &= ~ UCSWRST;
        UCA1IE |= UCRXIE;
        UCA1IFG &= ~RXFLAG;
    }

    Thanks again for your time and effort. It really helps to get a second set of eyes on things.

  • I ran the code on a different sensor and the other sensor worked fine. I guess I happened to run it on a bad sensor the first time. 

    Thanks for all of your help.