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 switching crystal oscillator Q2?

Other Parts Discussed in Thread: MSP430F413, MSP430F5529

I am building an ultrasonic measuring device based on  MSP430F413 (Link at the end of post, it's SLAA136A - October 2001). I am using the development board MSP430F5529LP, and wanted advice on how to do this. Here is some pseudo code that I have, I was thinking of changing the 32.768kHz crystal on Q2 to a 40kHz crystal because my sender and receiver ultrasonics operate at 40kHz. Is there a problem with switching this crystal out?

#include <msp430f5529.h>

/*
 * main.c
 * I am using the MSP430F5529 launchpad to try an set up ultrasonic measurements
 * I switched the Q2 to a 40kHz crystal oscillator because I am using 40kHz
 * ultrasonic transmitter and recievers.  
 */
void init_device();
void measurement_cycle();
unsigned long int i = 0;
int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    init_device();

    for(;;){
    	//update the serial out value with the value measured and then put the MSP430, initially it should be 000.
    	//to LPM3 sleep mode. The MSP430 remains in sleep mode until a BasicTimer1_ISR interrupt occurs
    	//and BasicTimer1_ISR returns it to active mode and initialized a measurement.
    	//stay in low power mode until we hit a basictimer1 interrupt
    	//after we get out of low power mode we have already done a measurement
    	//send out the value we measured to display
    }//stay in loop forever here, maybe change it later
	return 0;
}

/***********************Functions********************************/
void init_device(){
	//I switched the crystal from 32.7kHz to a 40kHz crystal on the xin and xout (on MSP430F5529 the Q2)
	//set P1.0 (ACLK) to output the 40kHz wave 
	//P1.2 (AT0.1) is for our receiver circuit to connect to, set up the opamp if needed
	//set up basictimer1 to interrupt the CPU every 205 ms? and initialize a measurement cycle
}

void measurement_cycle(){
	//get the free running counter right before we send off our signal
	//send our signal for 12 clock cycles
	//wait until we get an input from P1.2
	//from our input pin our P1.2 (AT0.1), capture our signal and get the free running counter when we get it back
	//now we do math on the free running counter, convert the clock cycles to time
	//change the time to distance
}
interrupt BasicTimer1_ISR(){
	//take out of low power mode
	//initialize a measurement cycle
	measurement_cycle();
}

http://www.ti.com/lit/an/slaa136a/slaa136a.pdf

 

  • The DCO/FLL can generate other frequencies; you do not necessarily need to switch the crystal. (On the F413, you'd have to use SMCLK instead of ACLK.)

    On the F5529, I'd recommend to use driverlib functions to initialize the crystal and the clocks.

    How exactly do you want to capture the signal?

  • Christopher Wright65 said:

    board MSP430F5529LP, and wanted advice on how to do this. Here is some pseudo code that I have, I was thinking of changing the 32.768kHz crystal on Q2 to a 40kHz crystal because my sender and receiver ultrasonics operate at 40kHz. Is there a problem with switching this crystal out?

    
    

     Crystal frequency has nothing to do with ultrasound transducers, anyway you have to generate transmit pulses from timer not from oscillator and start measure fly time from packet start. This cannot be done with an oscillator or anyway it can be done at expense of useless complex external circuitry.

  • So I am misunderstanding something here, so I beg for your patience. I am using 490-7707-ND sender and 490-7706-ND receiver parts from digikey. When testing them I hooked the sender up to a function generator at 40kHz and the receiver to a oscilloscope. If I didn't send 40 kHz I didn't get anything at my receiver. I was planning on taking the 40kHz sine wave from the oscillator, converting to a square wave with an op-amp to send out on my ultrasonic sender. Then I would get the signal back on the ultrasonic receiver and amplify the signal for use in the microcontroller. If I don't use the crystal frequency I wasn't sure how to get the exact 40kHz wave on a pin out, as I looked at dividers of clocks and couldn't figure out anything to give me exactly 40.
  • I was planning on using 90-7707-ND sender and 490-7706-ND receiver parts from digikey and using an opamp on the signal in to amplify the signal. I am new to embedded programming, so I was thinking I could just wait to get a high on the pin I have set for the input? If that doesn't work maybe I could set it for an interrupt or something.
  • The actual names of these components are Murata MA40S4S and MA40S4R.

    The datasheet says that the sender wants a 40 Khz sine wave, not a rectangle wave as generated by a digital output, but this should be easy to do with an appropriate low-pass filter.

    You don't need to be too exact; if you look at the sender's and receiver's frequency plots, you see that anything near 40 kHz will work:

    Generating the output with the DCO/FLL, either with or without any crystal as reference), should work fine.

    As far as I can see from the receiver test circuit (below), the output is a voltage level.
    So what you need to read from the MSP is an analog voltage level; in other words, you need to connect this to an ADC input.

  • Thank you very much for your reply, this is helping me learn quite a bit as I go along here, as you might tell I am a bit green. First off thank you for clarifying the parts, I wasn't actually able to find the figures you posted, I didn't really know where to look.

    So if I understand correctly, instead of using the LFXT1 clock for my signal, I will instead use the DCO, and try to get the frequency just as close as I can to 40kHz, but I shouldn't be too picky? 

    As for making it a sine wave, I should be able to use a filter pretty easily, I misunderstood the requirements for the sensors, so no worries there.

    This brings me to another question, which clock should I use to do the timing though if I use the DCO for output? I was planning on the DCO, maybe at 8MHz-16MHz, to be accurate at timing the sound travel. I guess this could be a bit extreme, but what other clock should I use?

    The input shouldn't be too hard to just put to an ADC pin and take the timer when it goes high, I will definitely follow the advice!

    Thank you again for you reply and help, I really appreciate it!

     

  • So this is what I have come up with, going off your advice (hopefully I understood correctly)



    UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2; // Set ACLK = REFO
    UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
    do// Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
    {
    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_1; // Select DCO range up to ~.25MHz to ~ 2.45MHz operation
    UCSCTL2 |= 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);
    //Timer Setup
    //set my SMCLK to be DCO /32 => 1.277953 MHz /32 = 39.936kHz to use for my signal

    I am still working on the SMCLK, was planning on outputting the SMCLK on a pin and using a filter to make a sine wave as you suggested.


    So, I am headed in the right direction?
  • So update on the problem...
    I did what was suggested and I am using the DCO/FLL to make about 40kHz for my SMCLK that I am outputting on my P2.2
    I am inputting on P1.2. I have the SMCLK going out on the 2.2, and it is a square wave right around 40.5kHz according to my oscilloscope.

    So now I am having an issue that I am not even getting into my interrupt, and I can't figure out why. Any help is much appreciated. Thank you!


    /* main.c
    * I am using the MSP430F5529 launchpad to try an set up ultrasonic measurements
    * I am using 40kHz ultrasonic transmitter and recievers.
    */
    #include <msp430f5529.h>
    void init_device();
    unsigned long int BEGIN_TIME;
    unsigned long int END_TIME;
    unsigned long int TOTAL_CLOCK_CYCLES;
    float DISTANCE;
    static unsigned int FEET_TO_INCHES = 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 = 1270000;//set to 1.27 MHz??
    int main(void) {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    init_device();
    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 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
    /*Set up MCLK, ACLK, and SMCLK*/
    UCSCTL3 = SELREF_2; // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2; // Set ACLK = REFO
    UCSCTL5 |= DIVS__32;//=> SMCLK/32 = 1.277953 MHz /32 = 39.936kHz to use for my signal
    UCSCTL0 = 0x1700; //DCOx = 23? Set DCOx, MODx first half is DCO, second MOD : x x x _ _ _ _ _ | _ _ _ _ _ x x x
    do// Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
    {
    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);
    TA0CCR0 = 10000;//We are using SMCLK At 40kHz, 10000 clock cycles = 250 ms, this is how often we want our interrupt to occur
    TA0CTL = TASSEL_2 + MC_1; // Timer_A set to SMCLK, UPMODE(count up to CCR0 for interrupt to occur)
    TA0CCTL0 = CCIE; // CCR0 interrupt enabled
    __bis_SR_register(GIE); /* Enable maskable interrupts */
    //set P1.0 to output the 40kHz wave using the ACLK (LFXT1) clock
    //set P1.2 (AT0.1) to use the MCLK for the input, it will make us more accurate
    }
    #pragma vector=TIMER1_A0_VECTOR
    __interrupt void TIMER1_A0_ISR(void)
    {
    //P1OUT ^= BIT0;
    //P2OUT ^= BIT0;
    P4OUT ^= BIT7;//flash our led to make sure we are working
    //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
    //send our signal out on P2.2 for 12 clock cycles (using the ACLK)
    //disable our P2.2 so we don't waste Power
    //wait until we get a signal back on our input pin P1.2
    //As soon as we get a signal from P1.2 (AT0.1) get the free running counter and put into END_TIME
    //:::::::::::::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;
    //change the time to distance.
    //DISTANCE = (TOTAL_CLOCK_CYCLES * SPEED_OF_SOUND/(2*MCLK_FREQ*FEET_TO_INCHES));//distance is in inches
    //display our DISTANCE out to the user.



    //__bis_SR_register(LPM3_bits + GIE); // Enter LPM3, interrupts enabled
    //__no_operation(); // For debugger
    }
  • TA0CCTL0.CCIE corresponds to TIMER0_A0_VECTOR.

    The ADC generates interrupts for all conversions. It might be a better idea to use a comparator instead to detect a raising voltage level.

    (Please use the "Insert code" button to insert code.)

  • Thank you for pointing out my mistake, I appreciate the help! I will update when I work out the interrupt.
  • So I am stuck here a bit, any help is appreciated!

    I get into both interrupts but I am misunderstanding how to use the free running counter, or the equivalent for TI (not much experience here). I want to assign the current clock timer count (MCLK or ACLK) in my interrupts to END_TIME and BEGIN_TIME.Then I want to be able to do the math on it from there to calculate my distance.

    Another question, for my COMPB, I wanted to verify that it is using channel P6.0 for the input, and this line of code:

    CBCTL2 |= CBRSEL;             // VREF is applied to -terminal (That is what I gather from the MSP430F55xx_compB_03.c example) 

     points out it says VREF is applied to the -terminal, I am struggling to find where the "-terminal" on the board.

    Can I use something on board without applying a VREF to a certain pin? I would like to be able to change this value depending on what range I want for receiving. 

     /* main.c
     * I am using the MSP430F5529 launchpad to try an set up ultrasonic measurements
     * I am using 40kHz ultrasonic transmitter and recievers.
     */
    #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 FEET_TO_INCHES = 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
    	P5SEL |= BIT2+BIT3;	// 	Port select XT2
    	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 = TA0CCR1;//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 = TBCCR0;//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*FEET_TO_INCHES));//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
    }

  • You should let the hardware work for you.
    You want a 40kHz square wave signal (filtered to sine by a low-pass filter externally).
    The timer can do this for you in hardware.
    Let's take Timer A2 for this. unfortunately, P2.2 can't be used, but you can use P2.3, which is TA2.0 output.
    Let's also assume you run the MSP at 16MHz.
    40kHz on 16MHz is 400. Use SMCLK (16MHz) as clock for the timer. Set the timer to up mode.
    Then set TA2CCR0 to 199 ((400/2)-1). This will make TA2 count from 0 to 199 and then roll over to 0 again in up mode. (200 ticks per cycle).
    Next you set the output mode (OUTMOD_x) of TA2CCR0 to toggle mode. And select P2.3 for module usage and output.
    As a result, the timer will count form 0 to 199 and then roll over to 0 again, and each time it reaches 199, it will toggle the sate of P2.3.
    For perfect 16MHz, this will give a perfect 40kHz, 50% duty cycle square wave output signal. Without any further CPU interaction required.
    All that is left to do for your code is to start or stop the timer if you want or don't want the output (or switch the port pin from module to GPIO and back and let the timer run). It may be controlled by using a different timer (you have four on this MSP) to do the on/off timing

    However, depending on the final application (i.e. what do you want to do with the ultrasonic signal), a slightly different approach may further reduce the required CPU operation. Like using the hardware UART to generate an IrDA-modulated gating signal for your 40kHz, to transmit serial data etc.)

**Attention** This is a public forum