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: Producing a BEEP sound using Buzzer in EDUMKII Booster Pack

Part Number: MSP430FR6989
Other Parts Discussed in Thread: ENERGIA

Tool/software: Code Composer Studio

Hi I was looking at TI's wiki page for playing "The Imperial March" link: http://processors.wiki.ti.com/index.php/Playing_The_Imperial_March 

My goal is to produce the first beep of the song using my Buzzer in my EDUMKII Booster Pack using the MSP430FR6989 Launchpad. 

My code is given below:

;-------------------------------------------------------------------------------
; MSP430 Assembler Code Template for use with TI Code Composer Studio
;
;
;-------------------------------------------------------------------------------
.cdecls C,LIST,"msp430.h" ; Include device header file

;-------------------------------------------------------------------------------
.def RESET ; Export program entry-point to
; make it known to linker.
;-------------------------------------------------------------------------------
.text ; Assemble into program memory.
.retain ; Override ELF conditional linking
; and retain current section.
.retainrefs ; And retain any sections that have
; references to current section.

;-------------------------------------------------------------------------------
RESET mov.w #__STACK_END,SP ; Initialize stackpointer
StopWDT mov.w #WDTPW|WDTHOLD,&WDTCTL ; Stop watchdog timer


;-------------------------------------------------------------------------------
; Main loop here
;-------------------------------------------------------------------------------
          bis.b #BIT7, &P2DIR
          mov.w #1100, R7
Beep bis.b #BIT7, &P2OUT
         mov.w #4, R6
L1     dec.w R6
         jnz L1
         bic.b #BIT7, &P2OUT
         mov.w #4, R6
L2     dec.w R6
         jnz L2
         dec.w R7
         jnz Beep
MainLoop jmp MainLoop

;-------------------------------------------------------------------------------
; Stack Pointer definition
;-------------------------------------------------------------------------------
.global __STACK_END
.sect .stack

;-------------------------------------------------------------------------------
; Interrupt Vectors
;-------------------------------------------------------------------------------
.sect ".reset" ; MSP430 RESET Vector
.short RESET

The idea is to replicate the code in C into Assembly, which I need for my project. However, when I run this code, nothing happens. I know the wiki code is probably using a buzzer with a different processing speed but any help regarding this would be greatly appreciated. 

  • Hello Adwaya,
    many thanks for contacting us.
    Looking at your code I see at least two missing things.
    1. There is not GPIO initialization. Keep in mind the default settings of control bits might not be necessarily what you need them to be after reset or power up. E.g. all GPIOs are set to input. Thus if you want to generate signals with a GPIO, first you need to configure it for output direction.
    2. The MSP430 FRAM devices a feature of keeping the device states locked after LPMx.5 and POR is available. This means, to apply any modifications to the GPIOs, by manipulating the GPIO control bits, you need to unlock the control registers. This is done by the instruction
    PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings
    Correspondingly this needs to be done also in assembler case.

    Thus I have two generic recommendations. On one hand, I would suggest looking at the code examples in the TI Resource Explorer in CCS. You can find examples for each and every module, which demonstrate how to initialize it. You can of course find examples in assembler there.
    The other recommendation would be, if you have a working C-code example, you can easily access the resulting assembler code by viewing the disassembly. This way you can see how certain c instructions or code is translated into assembler and can integrate it into your assembler code.

    Best regards
    Peter
  • Okay I added in the PM5CTL0 &= ~LOCKLPM5 as you suggested. Now I do hear a loud tick but that's it. About your point in 1. do you mean there is no GPIO initialization?
  • Hello Adwaya,
    sorry I overlooked the bis.b #BIT7, &P2DIR instruction, as I was expecting some kind of initialization section, where you would configure all the HW for your application. Thus this is fine for the buzzer signal only.

    I think the situation you're facing currently is related to the speed of the signal generation. The click indicates the buzzer is getting the initial pulse, from setting the GPIO. But probably the toggling of the GPIO is by far too fast. I would recommend you using an oscilloscope monitoring the signal you're generating.
    Your pulse width is defined by 4 runs through the loop and decrements on registers. Register operations require just one CPU cycle. Keep the CPU frequency in mind. Audible signals need to be in the 30Hz - 16kHz range. In addition the buzzer probably is capable of operation in a significantly smaller bandwidth, maybe 100s of Hz to a few kHz.

    Best regards
    Peter
  • I don't really have access to an oscilloscope. Can you explain to me the math behind it? So if I want to produce a beep which has a note pitch of 440 (I think Hz) and a duration of 500 (uS?) then how would I do it using the CPU clock (1 MHz)?

    I found this C code online for energia which works well. I am just trying to reproduce the first beep, in assembly.
    #include "pitches.h"
    #define cc 261
    #define dd 294
    #define ee 329
    #define ff 349
    #define g 391
    #define gS 415
    #define a 440
    #define aS 455
    #define b 466
    #define cH 523
    #define cSH 554
    #define dH 587
    #define dSH 622
    #define eH 659
    #define fH 698
    #define fSH 740
    #define gH 784
    #define gSH 830
    #define aH 880

    int buzzerPin = 40;

    void beep(int note, int duration)
    {
    tone(buzzerPin, note, duration/2);
    delay(duration/2);
    noTone(buzzerPin);
    delay(duration/2 + 20);
    }
    void setup()
    {
    pinMode(buzzerPin,OUTPUT);
    }
    void loop()
    {
    beep(a, 500);
    beep(a, 500);
    beep(a, 500);
    beep(ff, 350);
    beep(cH, 150);
    beep(a, 500);
    beep(ff, 350);
    beep(cH, 150);
    beep(a, 650);

    delay(150);
    //end of first bit

    beep(eH, 500);
    beep(eH, 500);
    beep(eH, 500);
    beep(fH, 350);
    beep(cH, 150);
    beep(gS, 500);
    beep(ff, 350);
    beep(cH, 150);
    beep(a, 650);

    delay(150);
    //end of second bit...

    beep(aH, 500);
    beep(a, 300);
    beep(a, 150);
    beep(aH, 400);
    beep(gSH, 200);
    beep(gH, 200);
    beep(fSH, 125);
    beep(fH, 125);
    beep(fSH, 250);

    delay(250);

    beep(aS, 250);
    beep(dSH, 400);
    beep(dH, 200);
    beep(cSH, 200);
    beep(cH, 125);
    beep(b, 125);
    beep(cH, 250);

    delay(250);

    beep(ff, 125);
    beep(gS, 500);
    beep(ff, 375);
    beep(a, 125);
    beep(cH, 500);
    beep(a, 375);
    beep(cH, 125);
    beep(eH, 650);


    beep(aH, 500);
    beep(a, 300);
    beep(a, 150);
    beep(aH, 400);
    beep(gSH, 200);
    beep(gH, 200);
    beep(fSH, 125);
    beep(fH, 125);
    beep(fSH, 250);

    delay(250);

    beep(aS, 250);
    beep(dSH, 400);
    beep(dH, 200);
    beep(cSH, 200);
    beep(cH, 125);
    beep(b, 125);
    beep(cH, 250);

    delay(250);

    beep(ff, 250);
    beep(gS, 500);
    beep(ff, 375);
    beep(cH, 125);
    beep(a, 500);
    beep(ff, 375);
    beep(cH, 125);
    beep(a, 650);
    //end of the song
    //end of the song
    }
  • Hi Adwaya,
    I would recommend you implementing this with a Timer based PWMs, instead of a CPU based PWM. There you can easily perform the calculations without measuring something with an oscilloscope. Here is a code example with 1MHz CPU clock and 2 PWMs with 75/25 duty cycle. You can easily modify it to 50/50. The TACCR1/2 needs to be 1/2 of TACCR0.
    The tone change would be just changing the TA0CCR0 to desired value, e.g using another Timer interrupt. For 440Hz with 1MHz SMCLK the CCR0 needs to be 2273d.
    Keep in mind when changing the tone, means TACCR0, you need to adjust the TACCR1/2 too, to maintain the 50% duty cycle.
    For generating a regular Timer interrupt for the switching between tones, please look into the code examples in the TI Resource Explorer.

    Best regards
    Peter

    ;******************************************************************************
    ; MSP430FR69x Demo - Timer0_A3, PWM TA0.1-2, Up Mode, DCO SMCLK
    ;
    ; Description: This program generates two PWM outputs on P1.0,P1.1 using
    ; Timer0_A configured for up mode. The value in CCR0, 1000-1, defines the PWM
    ; period and the values in CCR1 and CCR2 the PWM duty cycles. Using ~1MHz
    ; SMCLK as TACLK, the timer period is ~1ms with a 75% duty cycle on P1.0
    ; and 25% on P1.1.
    ; ACLK = n/a, SMCLK = MCLK = TACLK = 1MHz
    ;
    ;
    ; MSP430FR6989
    ; ---------------
    ; /|\| |
    ; | | |
    ; --|RST |
    ; | |
    ; | P1.0/TA0.1|--> CCR1 - 75% PWM
    ; | P1.1/TA0.2|--> CCR2 - 25% PWM
    ;
    ; E. Chen
    ; Texas Instruments Inc.
    ; April 2014
    ; Built with Code Composer Studio V6.0
    ;******************************************************************************
    ;-------------------------------------------------------------------------------
    .cdecls C,LIST,"msp430.h" ; Include device header file
    ;-------------------------------------------------------------------------------
    .def RESET ; Export program entry-point to
    ; make it known to linker.
    ;-------------------------------------------------------------------------------
    .global _main
    .global __STACK_END
    .sect .stack ; Make stack linker segment ?known?

    .text ; Assemble to Flash memory
    .retain ; Ensure current section gets linked
    .retainrefs

    _main
    RESET mov.w #__STACK_END,SP ; Initialize stackpointer
    StopWDT mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT
    SetupGPIO bis.b #BIT0+BIT1,&P1DIR ; P1.0 and P1.1 output
    bis.b #BIT0+BIT1,&P1SEL0 ; P1.0 and P1.1 options select

    UnlockGPIO bic.w #LOCKLPM5,&PM5CTL0 ; Disable the GPIO power-on default
    ; high-impedance mode to activate
    ; previously configured port settings

    mov.b #CSKEY_H,&CSCTL0_H ; Unlock CS registers

    mov.w #SELA__VLOCLK+SELS__DCOCLK+SELM__DCOCLK,&CSCTL2 ; Set ACLK=VLO SMCLK=DCO
    mov.w #DIVA__8+DIVS__8+DIVM__8,&CSCTL3 ; Set all dividers
    clr.b &CSCTL0_H ; Lock CS registers

    mov.w #1000-1,&TA0CCR0 ; PWM period
    mov.w #OUTMOD_7,&TA0CCTL1 ; CCR1 reset/set
    mov.w #750,&TA0CCR1 ; CCR1 PWM duty cycle
    mov.w #OUTMOD_7,&TA0CCTL2 ; CCR2 reset/set
    mov.w #250,&TA0CCR2 ; CCR2 PWM duty cycle
    mov.w #TASSEL__SMCLK+MC__UP+TACLR,&TA0CTL ; SMCLK, up mode, clear TAR

    Mainloop bis.w #LPM0,SR ; Enter LPM0
    nop ; for debug

    ;------------------------------------------------------------------------------
    ; Interrupt Vectors
    ;------------------------------------------------------------------------------
    .sect ".reset" ; MSP430 RESET Vector
    .short RESET ;
    .end
  • Thanks for all this it really helped! Just one last question. How did you come up with the number 2273d?
  • Hello Adwaya,
    the value results from the following considerations:
    1. You're clocking the device with 1MHz.
    2. Thus also the SMCLK is 1MHz.
    3. SMCLK is used for the Timer to generate the PWM.
    4. To create 440Hz from 1MHz clock, you need to set the Timer CCR to a value which reflects the timing derived from 1MHz >> 1MHz/440Hz = 2272.72.

    If this completes the resolution of your problem please confirm it by clicking on "this resolved my issue". Many thanks in advance.

    Best regards
    Peter

**Attention** This is a public forum