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.

MSP430F5529LP interrupt timers and Free running counter

Other Parts Discussed in Thread: MSP430F5529

I am trying to use either the ACLK or the MCLK to get the free running counter in two interrupt service routines. I am not sure of how to actually do this. In my interrupt routines I want to save the current clock tick counter into a variable, then the next interrupt get the new current clock tick counter into a different variable so I can then do some math.

Also, I am using the input capture/compare on channel P6.0, and it says the VREF (from the example code for the LP) is connected to "-terminal" but I don't where this is on the actual board...I am pretty new as you might tell :) - is there a way to change the voltage value in software without changing the value to this hidden -terminal?

The project is trying to use the MSP430F5529 LaunchPad to create a ultrasonic measuring device. I am using Murata MA40S4S and Murata MA40S4R as my ultrasonic sender and receiver. The following code will initialize the device and set up the interrupts (not sure if I need to change these), then it will generate an interrupt every 250 ms and enable the second interrupt to occur.

I have a few possible logic errors, not too worried yet as I can't even get the clock counter into variables. I will probably need to disable the first interrupt while waiting for the second or change it to be action driven, such as a button press. Anyway, here is the code, my most pressing problem again is how to actually get the current counter value into my variables.

/* main.c
 * I am using the MSP430F5529 launchpad to try an set up ultrasonic measurements
 * I am using 40kHz ultrasonic transmitter and recievers.
 * Notes about the MSP430:
 * MSP430 requires 6 clock cycles before an ISR begins executing
 * An ISR always finishes with the return from interrupt instruction (reti) requiring 5 cycles
 *
 */
#include <msp430f5529.h>
void init_device();
unsigned int i;
unsigned long int BEGIN_TIME;
unsigned long int END_TIME;
unsigned long int TOTAL_CLOCK_CYCLES;
float DISTANCE;
static unsigned int INCHES_IN_FOOT = 12;		//12 inches to 1 foot
static float SPEED_OF_SOUND = 1116.43;			//1115.43 ft/sec at room temperature
static unsigned long int MCLK_FREQ = 4000000;	//set to 4 MHz??
int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    init_device();				//set up clocks, timers and interrupts
    for(;;){
    	//stay in loop forever, we do everything in our interrupts
    }
	return 0;
}
/***********************Functions********************************/
void init_device(){
	P4DIR |= BIT7; 		/* Digital out to a LED just to make sure we work :) */
	P1DIR &= 0xFB ; 	//xxxx x0xx - set out channel 1.2 to an input
	//P2DIR |= BIT2;    //P2.2 set to output
	P2SEL |= BIT2;	  	// SMCLK sent out to P2.2, this will be my sensor out pin
	P7DIR |= BIT7;    	// MCLK sent out to pins 2.4, just to check it, verify correct operation
						// We will comment this out in the low power mode
	P7SEL |= BIT7;		//select MCLK to output on pin 7.7, we want to test for functionality
	P5SEL |= BIT2+BIT3;	// 	Port select XT2 (for MCLK)
	UCSCTL6 &= ~XT2OFF;	//	enable XT2
  /*Set up MCLK, ACLK, and SMCLK*/
    UCSCTL3 |= SELREF_2;                   	// Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_5 + SELM_5 + SELS_4;   	// Set MCLK(SELM) to XT2 (4MHz)101b = XT2CLK when available, otherwise DCOCLKDIV
    										// Set SMCLK(SELS) 100b = DCOCLKDIV
    										// SET ACLK (SELA) 101b = XT2CLK when available, otherwise DCOCLKDIV
    UCSCTL5 |= DIVS_5;	//=> SMCLK/32 = 1.277953 MHz /32 = 39.936kHz to use for my signal
    					//101b = f(SMCLK)/32, or we could use DIVS__32
    UCSCTL0 = 0x1700; 	//DCOx = 23? Set DCOx, MODx first half is DCO, second MOD : x x x _ _ _ _ _  | _ _ _ _ _ x x x
    					//Look at DCORSEL on spec sheet, gives range, we now have 32 chances in our range,
    					//trial and error to find the exact value needed here.
    do					// Loop until XT1,XT2 & DCO stabilizes, in our case XT2 and DCO
    {
      UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); 	// Clear XT2,XT1,DCO fault flags
      SFRIFG1 &= ~OFIFG;          					// Clear fault flags
    }while (SFRIFG1&OFIFG);  						// Test oscillator fault flag
    __bis_SR_register(SCG0);            			// Disable the FLL control loop
    UCSCTL1 = DCORSEL_2;              				// Select DCO range up to ~.25MHz to ~ 2.45MHz operation
    UCSCTL2  = FLLD__1 + 38;                			// Set DCO Multiplier for
                                              	  	 	// (N + 1) * FLLRef = Fdco
                                              	 		// (38 + 1) * 32768 = 1.277953 MHz
    __bic_SR_register(SCG0);						// Enable the FLL control loop
    // Worst-case settling time for the DCO when the DCO range bits have been
    // changed 32 x 32 x 1.28MHz / 32,768 Hz = 40000 = MCLK cycles for DCO to settle
    __delay_cycles(40000);
    // Setup ComparatorB
  	CBCTL0 |= CBIPEN + CBIPSEL_0; // Enable V+, input channel CB0
  	CBCTL1 |= CBPWRMD_1;          // normal power mode
  	CBCTL2 |= CBRSEL;             // VREF is applied to -terminal
  	CBCTL2 |= CBRS_3+CBREFL_1;    // R-ladder off; bandgap ref voltage (1.2V)
	 	                          // supplied ref amplifier to get Vcref=1.5V (CBREFL_2)
   	CBCTL3 |= BIT0;               // Input Buffer Disable @P6.0/CB0
 	__delay_cycles(75);           // delay for the reference to settle
	CBINT &= ~(CBIFG + CBIIFG);   // Clear any errant interrupts
    CBINT  |= CBIE;               // Enable CompB Interrupt on rising edge of CBIFG (CBIES=0)
    TA0CCR0 = 10000;//We are using SMCLK At 40kHz, 10000 clock cycles = 250 ms
    				//For testing this is how often we want our interrupt to occur
    				//eventually we will set it to occur off an interrupt from audio jack interface
    				//this doesn't work, truncates to 16 bit, which max is 2^16 = 65536
    TA0CTL =  TASSEL_2 + MC_1; 		// Timer_A set to ACLK, UPMODE(count up to CCR0 for interrupt to occur)
    								//TASSEL_0  = TACLK
    								//TASSEL_1  = ACLK.
    								//TASSEL_2  = SMCLK
    								//TASSEL_3  = INCLK
    TA0CCTL0 = CCIE; 				// CCR0 interrupt enabled
    __bis_SR_register(GIE); 		/* Enable maskable interrupts */
    _EINT();//enable global interrupts
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
    P4OUT ^= BIT7;//flash our led to make sure we are getting into our interrupt correctly
    //take out of low power mode
	//initialize a measurement cycle
	//:::::::::::measurement_cycle::::::::::
		//get the free running counter from our MCLK right before we send off our signal - PUT INTO BEGIN_TIME
    	BEGIN_TIME = TBR;//this holds the free running counter of when we got into the interrupt
		//send our signal out on P2.2 for 48 clock cycles (using the SMCLK)
    	P2DIR |= BIT2;    	//P2.2 set to output
    	for(i=0; i<48 ; i++);	//we send out for 48 MCLK clock cycles, which is 5 rising edges of 40kHz out sig
    		//if not enough time, up the amount of clock cycles we output
		//disable our P2.2 so we don't waste Power
    	//P2DIR &= 0xFB;//1111 1011 = 0xFB, We want to turn off our 2.2 now- update - this makes unstable output pin
    	//enable our Timer1 interrupt for a compare
    	CBCTL1 |= CBON;//enables our compareB channel. Vcompare is on P6.0
		//wait until we get a signal back on our input pin P1.2
		//Wait for Comparator Interrupt
	//__bis_SR_register(LPM3_bits + GIE);       // Enter LPM3, interrupts enabled
	//__no_operation();                         // For debugger
}

/*#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER1_A1_ISR(void)*/
#pragma vector=COMP_B_VECTOR
__interrupt void Comp_B_ISR (void)
{
	//As soon as we get a signal from P1.2 (AT0.1) get the free running counter and put into END_TIME
	END_TIME = TBR;//this holds the free running counter from start of interrupt
	CBINT &= ~CBIFG;// Clear Interrupt flag
	CBCTL1 &= 0xFBFF;//disable interrupt 1111 1011 1111 1111 = disable ON bit
	//:::::::::::::Math on the Clock Cycles:::::::::
		//We are using the MCLK for measurements on the timer, MCLK = 25MHz?
		//now we do math on the free running counter, convert the clock cycles to time
		//might need to check the Timer overflow flag on the MCLK, not sure yet
		TOTAL_CLOCK_CYCLES = END_TIME - BEGIN_TIME;//we wait for ?? clock cycles sending, then another ?? for incoming)
		//change the time to distance.
		DISTANCE = (TOTAL_CLOCK_CYCLES * SPEED_OF_SOUND/(2*MCLK_FREQ*INCHES_IN_FOOT));//distance is in inches
	//display our DISTANCE out to the user.
        //TODO: display
		//eventually we will send via our audiojack interface
		//send on the microphone in line to display on the phone
	//__bis_SR_register(LPM3_bits + GIE);       // Enter LPM3, interrupts enabled
	__no_operation();                         // For debugger
}

  • The register with TimerA0's current counter value is not called TBR but TA0R.

    V+ and V- are the names of the internal connections of the comparator. These are labeled just + and - in figure 31-1 in the User's Guide.

    To delay for a specific number of cycles, you must use __delay_cycles(); a simple for loop will be optimized away.

  • So I updated my code, as shown below. I end up using the TB0R because my timerA is at 40 kHz clock and I wanted to be faster, so I just set the TimerB to ACLK at 4MHz. So the problem I am now having is my TB0R is not being set in my COMP_B_ISR. Is it different? My BEGIN_TIME gets a value that looks like it is the free running counter, but I guess I'm not really positive if it is.

    How to fix the END_TIME getting the counter?

    #include <msp430f5529.h>
    #include <stdlib.h>
    #define GPIO_ALL	GPIO_PIN0|GPIO_PIN1|GPIO_PIN2|GPIO_PIN3| \
    					GPIO_PIN4|GPIO_PIN5|GPIO_PIN6|GPIO_PIN7
    
    extern unsigned char bButton1Pressed;
    void init_device();
    unsigned int i;
    unsigned long int BEGIN_TIME;
    unsigned long int END_TIME;
    unsigned long int TOTAL_CLOCK_CYCLES;
    float DISTANCE;
    static unsigned int INCHES_IN_FOOT = 12;		//12 inches to 1 foot
    static float SPEED_OF_SOUND = 1116.43;			//1115.43 ft/sec at room temperature
    static unsigned long int MCLK_FREQ = 4000000;	//set to 4 MHz??
    int main(void) {
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
        init_device();				//set up clocks, timers and interrupts
        for(;;){
        	//stay in loop forever, we do everything in our interrupts
        }
    	return 0;
    }
    /***********************Functions********************************/
    void init_device(){
    	//Initialize the button P1.1
    	P1IE |= BIT1; 		// P1.1 interrupt enabled
    	P1IFG &= ~BIT1; 	// P1.1 IFG cleared
    	P1DIR |= BIT0; 		//P1.0 as output
    	P1OUT &= ~BIT0;		//make sure our LED starts off
    	P4DIR |= BIT7; 		/* Digital out to a LED just to make sure we work :) */
    	P4OUT &= ~BIT7;		//we don't have a valid distance to start, turn off led
    	P1DIR &= 0xFB ; 	//xxxx x0xx - set out channel 1.2 to an input
    	P2SEL |= BIT2;	  	// SMCLK sent out to P2.2, this will be my sensor out pin, enable/disable in interrupts
    	P7DIR |= BIT7;    	// MCLK sent out to pins 2.4, just to check it, verify correct operation
    						// We will comment this out in the low power mode
    	P7SEL |= BIT7;		//select MCLK to output on pin 7.7, we want to test for functionality
    	P5SEL |= BIT2+BIT3;	// 	Port select XT2 (for MCLK)
    	UCSCTL6 &= ~XT2OFF;	//	enable XT2
      /*Set up MCLK, ACLK, and SMCLK*/
        UCSCTL3 |= SELREF_2;                   	// Set DCO FLL reference = REFO
        UCSCTL4 |= SELA_5 + SELM_5 + SELS_4;   	// Set MCLK(SELM) to XT2 (4MHz)101b = XT2CLK when available, otherwise DCOCLKDIV
        										// Set SMCLK(SELS) 100b = DCOCLKDIV
        										// SET ACLK (SELA) 101b = XT2CLK when available, otherwise DCOCLKDIV
        UCSCTL5 |= DIVS_5;	//=> SMCLK/32 = 1.277953 MHz /32 = 39.936kHz to use for my signal
        					//101b = f(SMCLK)/32, or we could use DIVS__32
        UCSCTL0 = 0x1700; 	//DCOx = 23? Set DCOx, MODx first half is DCO, second MOD : x x x _ _ _ _ _  | _ _ _ _ _ x x x
        					//Look at DCORSEL on spec sheet, gives range, we now have 32 chances in our range,
        					//trial and error to find the exact value needed here.
        do					// Loop until XT1,XT2 & DCO stabilizes, in our case XT2 and DCO
        {
          UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); 	// Clear XT2,XT1,DCO fault flags
          SFRIFG1 &= ~OFIFG;          					// Clear fault flags
        }while (SFRIFG1&OFIFG);  						// Test oscillator fault flag
        __bis_SR_register(SCG0);            			// Disable the FLL control loop
        UCSCTL1 = DCORSEL_2;              				// Select DCO range up to ~.25MHz to ~ 2.45MHz operation
        UCSCTL2  = FLLD__1 + 38;                			// Set DCO Multiplier for
                                                  	  	 	// (N + 1) * FLLRef = Fdco
                                                  	 		// (38 + 1) * 32768 = 1.277953 MHz
        __bic_SR_register(SCG0);						// Enable the FLL control loop
        // Worst-case settling time for the DCO when the DCO range bits have been
        // changed 32 x 32 x 1.28MHz / 32,768 Hz = 40000 = MCLK cycles for DCO to settle
        __delay_cycles(40000);
    
    
        // Setup ComparatorB
      	CBCTL0 |= CBIPEN + CBIPSEL_0; // Enable V+, input channel CB0
      	CBCTL1 |= CBPWRMD_1;          // normal power mode
      	CBCTL2 |= CBRSEL;             // VREF is applied to -terminal
      	CBCTL2 |= CBRS_3+CBREFL_1;    // R-ladder off; bandgap ref voltage (1.2V)
    	 	                          // supplied ref amplifier to get Vcref=1.5V (CBREFL_2)
       	CBCTL3 |= BIT0;               // Input Buffer Disable @P6.0/CB0
     	__delay_cycles(75);           // delay for the reference to settle
    	CBINT &= ~(CBIFG + CBIIFG);   // Clear any errant interrupts
        CBINT  |= CBIE;               // Enable CompB Interrupt on rising edge of CBIFG (CBIES=0)
        //this is for backup interrupt
        TA0CCR0 = 10000;//We are using SMCLK At 40kHz, 10000 clock cycles = 250 ms
        				//this interrupt is to disable multiple button presses
        				//also to display error if no signal came back
        TA0CTL =  TASSEL_2 + MC_1; 		// Timer_A set to ACLK, UPMODE(count up to CCR0 for interrupt to occur)
        								//TASSEL_0  = TACLK
        								//TASSEL_1  = ACLK.
        								//TASSEL_2  = SMCLK
        								//TASSEL_3  = INCLK
        TB0CTL = TASSEL_1 + MC_2;		//ACLK with continuous mode counting
        __bis_SR_register(GIE); 		/* Enable maskable interrupts */
        _EINT();//enable global interrupts
    }
    
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    {
    	__delay_cycles(0x23FF); //Cheap debounce.
    	P1OUT ^= BIT0; // P1.0 = toggle
    	    //take out of low power mode
    		//initialize a measurement cycle
    		//:::::::::::measurement_cycle::::::::::
    			//get the free running counter from our MCLK right before we send off our signal - PUT INTO BEGIN_TIME
    	    	BEGIN_TIME = TB0R;//this holds the free running counter of when we got into the interrupt
    			//send our signal out on P2.2 for 48 clock cycles (using the SMCLK)
    	    	P2DIR |= BIT2;    	//P2.2 set to output
    	    	__delay_cycles(48);	//we send out for 48 MCLK clock cycles, which is 5 rising edges of 40kHz out sig
    	    	//enable our Timer1 interrupt for a compare
    	    	CBCTL1 |= CBON;//enables our compareB channel. Vcompare is on P6.0
    	P1IFG &= ~BIT1; // P1.1 IFG cleared
    	TA0CCTL0 = CCIE; // CCR0 interrupt enabled, this is to make sure we get signal back
    }
    
    
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void)
    {
        if(BEGIN_TIME==0&&END_TIME==0){
        	P4OUT &= ~BIT7;
        	//we need to clear any button interrupts or compare interrupts, disable compare interrupt
        	P1IFG &= ~BIT1; 	// P1.1 IFG cleared
        	CBINT &= ~CBIFG;	// Clear Interrupt flag for COMPB
        	CBCTL1 &= 0xFBFF;	//disable interrupt 1111 1011 1111 1111 = disable ON bit
        	TA0CCTL0 &= ~CCIE;	//disable the timer interrupt, don't need it until next button press
        	P2DIR &= ~BIT2;		//turn off our sending, wait till next time
        	//display an error distance to the user
        	DISTANCE = -1;
        }
    }
    
    /*#pragma vector=TIMER0_A1_VECTOR
    __interrupt void TIMER1_A1_ISR(void)*/
    #pragma vector=COMP_B_VECTOR
    __interrupt void Comp_B_ISR (void)
    {
    	//As soon as we get a signal from P1.2 (AT0.1) get the free running counter and put into END_TIME
    	P4OUT |= BIT7;
    	END_TIME = TB0R;//this holds the free running counter from start of interrupt
    	CBINT &= ~CBIFG;// Clear Interrupt flag
    	CBCTL1 &= 0xFBFF;//disable interrupt 1111 1011 1111 1111 = disable ON bit
    	//:::::::::::::Math on the Clock Cycles:::::::::
    		//We are using the MCLK for measurements on the timer, MCLK = 25MHz?
    		//now we do math on the free running counter, convert the clock cycles to time
    		//might need to check the Timer overflow flag on the MCLK, not sure yet
    		TOTAL_CLOCK_CYCLES = END_TIME - BEGIN_TIME;//we wait for ?? clock cycles sending, then another ?? for incoming)
    		//change the time to distance.
    		DISTANCE = (TOTAL_CLOCK_CYCLES * SPEED_OF_SOUND/(2*MCLK_FREQ*INCHES_IN_FOOT));//distance is in inches
    		//we reset these values so if we don't get a value back we can show error to user
    		END_TIME = 0;
    		BEGIN_TIME = 0;
    		TA0CCTL0 &= ~CCIE;	//disable the timer interrupt, don't need it until next button press
        	P2DIR &= ~BIT2;		//turn off our sending, wait till next time
    		//display our DISTANCE out to the user.
    		//TODO: display
    		//eventually we will send via our audiojack interface
    		//send on the microphone in line to display on the phone
    		__no_operation();                         // For debugger
    }

  • What do you mean with "not being set"?
  • The END_TIME is always a 0, it never is set to another value, even when I test 10s of times.

    *edit*

    I updated the code, I had versions where BEGIN_TIME and END_TIME were signed ints, but I have them as unsigned so that I get the value even after a rollover. The END_TIME will get set in my interrupt to a -1 or a 0 (depending on the version of the code), the current code it gets set to a 0 and it never changes. I can't figure out why.

  • Does the interrupt handler actually run?
  • It goes into all the interrupts correctly. When a button is pressed it goes into the Port1 interrupt and it enables both the capture/compare interrupt and the timer interrupt in case I don't get a signal back. When I receive a signal back, I am going into the capture/compare interrupt as expected, but my timerB TB0R doesn't have anything in it or something? I'm not sure.
  • I changed my timer to use the SMCLK at 40kHz as it still gave me 1/6" accuracy, then it worked fine, not sure why.

**Attention** This is a public forum