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.

Tone generation without the use of timer pin

Other Parts Discussed in Thread: MSP430F5438A

Hi everbody,

I'm working on a project that has a MSP430F5438A on a custom PCB design. On this design there is a buzzer that i want to let "peep" on a 2.88kHZ frequency. Using the following formula: Hz = 1/Time of sinus i have a period time of 347us and a actual beep time of 174us. So the beeper port needs to be '1' for 174us.

I have found some great examples that use timerB as PWM generator but the problem is that our buzzer is not connected to a pin that has alternative timer b function, it is just connect to a normal GPIO pin with no alternative function. 

I want to use the 32kHz krystal as a source for Aclk and use Aclk for the tone generation. What is the best and most relaible way to generate a 2.88kHz tone using a buzzer on a GPIO pin and tx1 as a source?

Any suggestions and tips are welcome!

  • What pin do you use?

    P1.0/TA0CLK/ACLK

    Though you can internally keep ACLK /1 you can div its output pin (if I understand it correctly)
    ACLK output (divided by 1, 2, 4, 8, 16, or 32)

    But /16 will give you 2.05 KHz,
    so unless you play around with REFOCLK into the FLL settings to get a 46KHz ACLK

  • Hi Tony,

    First off all thank you for your reply! ACLK gets it's source from a external 32kHz crystal, maybe a stupid question but then i don't have to use the REFOCLK? We can't use the MCLK or SMCLK because in our code we need to shift speed and in the program on certain points. 

    So by using the TX1 for a clock we always get the same speed, the buzzer is not on P1 but on a other port i think it is on P5 or 6(don't know what pin). It is sunday here and i got the documentation at the office, i will add the correct information to my reply tomorrow (don't know the exact pin on top of my head). But i think the pin it is connected to a pin that has no alternative function.

    Do you (or someone else) have an suggestion how to get (around) 2.88 kHZ buzzer frequency with the 32k kristal and with the buzzer on a GPIO pin?

    Tony many thanks for your feedback so far!

    PS we still have timer B available, is there a way that we can use this timer (and using ACLK as source) to generate the frequency with the buzzer on a non timer B pin, (a pin without a alternative function)?

  • Use software IRQ for TimerB and toggle P5.xOUT inside it.
    up-to-CCR0 = 5, or use  CCRx += 6 in continues-mode

    32768HZ / 2880HZ / 2 (toggle) = 5.688 = rounded = 6 value for CCR0 -1

    Uses more (battery) power to wakeup that often and some small time variation could happen
    if msp430 is busy with other IRQ's


    And as you can see, with a slow aclk granularity is not dead-on as you will get 2.73KHz
    So maybe use smlk for TimerB, but then LPM3 will not be available while using buzzer.

  • Hi Tony,

    if i understand you correcty then i start timerb  when i want to use  the buzzer?  I set the timer to up mode and the compare value is set to 5688. Can you tell me how you get. to this value? Using the ack sources with tx at 32 kHz? I mean how idd you come up with thuis value if i may ask? When the timer reaches this value the interrupt is fired and the pin is toggled for 174us and back again when the timer is reached again (and so on for the duration that the buzzer is needed?  This will create a frequency of around 2.88 kHz?I Will try this tommorow and get. back to you! 

    Many thanks again for your feedback!

  • I updated it forgot Kilohertz, so it's only 6 minus1 for CCR0

  • Hi Tony,

    So the actual code line should be TBCRR0 = (6-1)? Or just TBCRR0 = 5? And i need to enable interrupt for the timer right? Is my unsterstanding of your solution correct in the text of my previous post? I will try your suggestion tomorrow!

    Many thanks! I will get back to you with the result!

  • TBCRR0 = (6-1)? Or just TBCRR0 = 5

    Either one,
    we like to use -1 as to visually acknowledge that counter goes around back to zero after the next tick

  • Oke thanks!

    So i just use TBCRR0 = 5 tomorrow! Thanks!

  • Hi Tony,

    Today i checked our PCB datasheet and is says that the buzzer is connected to P4.0! This means that i can use timer B0 for PWM. Bellow is the program, the problem is that the buzzer does not make a sound ( is the CCR0 and CCR1 value correct for a 50% duty cycle?, so that the buzzer plays at  around 2.88 kHz). Would you mind take a look? I can't tell if the timere is set correctly.

    First is start the crystal and source it ACLK, next i configure the buzzer port and timer. And at the end i spin in a while loop. Many thanks in advance!

    static void StartCrystalOscillator(void)
    {
    /* Set up XT1 Pins to analog function, and to lowest drive */
    P7SEL |= (BIT1 | BIT0);

    UCSCTL6 &= ~(XT1OFF);

    /* Set internal cap values. */
    UCSCTL6 |= XCAP_3;

    /* Loop while the Oscillator Fault bit is set. */
    while(SFRIFG1 & OFIFG)
    {
    while (SFRIFG1 & OFIFG)
    {
    /* Clear OSC fault flags. */
    UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);

    SFRIFG1 &= ~OFIFG;
    }

    /* Reduce the drive strength. */
    UCSCTL6 &= ~(XT1DRIVE1_L + XT1DRIVE0);
    }

    // Source clock signal to ACLK
    UCSCTL4 = SELA_0;

    __bis_SR_register(GIE);
    }


    main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT


    // Start crystal and source to ACLK
    StartCrystalOscillator();

    // Set buzzer port to output
    P4DIR |= BIT0;
    // Select alternative mode
    P4SEL |= BIT0; 

    TB0CCR0 = 5; // PWM Period, is this right?
    TB0CTL = OUTMOD_7; // CCR1 reset/set
    TB0CCR0 = 2; // CCR1 PWM duty cycle, 50% duty cycle, is 2 right?
    TB0CTL = TBSSEL_1 + MC_1; // ACK for timer source, up mode

    while(1){

    }
    }

    // Vector not needed anymore?
    #pragma vector=TIMER0_B0_VECTOR
    __interrupt void TIMER_INTERRUPT(void) {
    P4OUT ^= BIT0;

    /* Exit from LPM if necessary (this statement will have no effect if */
    /* we are not currently in low power mode). */
    LPM3_EXIT;
    }

  • Hi Tony,

    I got the code working with PWM! But i don't know if the buzzer is peeping around 2.88 kHz. I have set TBCCR0 to 5 (  TBCCR0 = 5) and the duty cyle to 2 (TB0CCR2 = 2). Is this correct for 2.88kHz?

    Below is the current PWM code

    void InitBuzzerPWM(){

    P4DIR |= BIT2;
    P4SEL |= BIT2; 
    TBCCR0 = 5; 
    TB0CCTL2 = OUTMOD_7; // CCR1 toggle/set
    TB0CCR2 = 2; // CCR1 PWM duty cycle
    TB0CTL = TBSSEL_1 + MC_1; // ACLK, up-down mode
    }

    void StartBuzzerPWM(){
    P4DIR |= BIT2;
    P4OUT |= BIT2;
    }

    void StopBuzzerPWM(){
    P4DIR &= ~BIT2;
    P4OUT &= ~BIT2;
    }

  • P4.0/TB0.0

    As you can see you have access to CCR0.
    And only good mode for that would be toggle.
    So don't bother setting up CCR1 or CCR2
    Just CCR0=5 with toggle mode 
    TB0CCTL0 = OUTMOD_4; // CCR0 toggle

    And of course you can only get 50% duty.

    You should also stop Counter when you are not using it.
    OUTMOD_0 will set the pin to a known state while at rest.

  • Hi Tony,

    Ance again thank you for your feedback you have been a great help! The HW guys had a error in the documentation, the buzzer is on P4.2. So then i have to use the CCR2 registers right? 

    I changed the code to the following (this works, is the duty cycle right? for a 2.88 kHz?):

    void InitBuzzer(void) {

    P4DIR |= BIT2; // P4.2
    P4SEL |= BIT2; 
    TBCCR0 = 5; // PWM Period/2
    TB0CCTL2 = OUTMOD_4; // CCR2 toggle/set
    TB0CCR2 = 2; // CCR2 PWM duty cycle
    TB0CTL = TBSSEL_1 + MC_1; // ACLK, up-down mode

    P4DIR &= ~BIT2;
    P4OUT &= ~BIT2;
    }

    When i change the TBCCR0 = 5;to TBCCR2 = 5; then nothing happens,  does this mean is still have to use CCR0 even if the pwm is for pin 2? Are these settings good for a 2.88 Khz output?

    And is this line:" TB0CCR2 = 2; // CCR2 PWM duty cycle" not needed at all (because of the toggle setting)?

    Since this is already calculated by you (32768HZ / 2880HZ / 2 (toggle) = 5.688) which means that the value 5 is already a 50% duty cycle and given a ACLK of 32768 kHZ the frequency is there fore already around 2.88 kHz?

    Once again many thanks!

  • P4.2/TB0.2

    As you no longer need to toggle, but instead you could use 
    set/reset and then should no longer divide by 2 the CCR0 value

    CCR0 = 12 -1
    CCR2 = 6

    TB0CCTL2 = OUTMOD_3     /* PWM output mode: 3 - PWM set/reset */

    Your are not using up-down but MC_1     /* Timer mode control: 1 - Up to CCR0 */
    MC_1 is correct in this job.

  • Hi Tony,

    So the following settings should give me a 2.88 Khz beep when timer b is sourced by aclk and aclk has TX1? Just asking for a conformation ;).

    P4DIR |= BIT2; // P4.2 buzzer port
    P4SEL |= BIT2; // P4.2 alternative mode (timer b, to generate PWM)
    TBCCR0 = 12-1; 
    TB0CCTL2 = OUTMOD_3; 
    TB0CCR2 = 6; 
    TB0CTL = TBSSEL_1 + MC_1; // ACLK, up-down mode

    Many thanks for your help again!

  • yes, simple formula:
    32768 Hz ACLK / 2880 buzzer = 11.377

    Actually if rounded it would be 11 -1 for CCR0

    TBCCR0 = 11-1; 
    TB0CCTL2 = OUTMOD_3; 
    TB0CCR2 = 5; 

    But try both as one may sound better.

  • HI Tony,

    I think it works now! We will check the result with a ossiloscope later this week and i will get back to you with the final result! Many thanks for all your feedback and help!

**Attention** This is a public forum