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/MSP430FR2676: scanning 2 channel ADC and Multiple Timers sources interrupt based.

Part Number: MSP430FR2676
Other Parts Discussed in Thread: MSP430FR2433,

Tool/software: Code Composer Studio

Hello,

         I would like to know how to setup the following,

1] How to set up 3 timer source interrupt based, one for battery monitoring, second one for creating a delay, third one for pwm for buzzer.

2] How to setup 2 adc channels (A0,A1) in Sequence-of-channels / Repeat-sequence-of-channels.

I know to setup for a single timer and single ADC channel. Are there any examples for these?

  • Hi Gourav,

    Gourav H said:

     I would like to know how to setup the following,

    1] How to set up 3 timer source interrupt based, one for battery monitoring, second one for creating a delay, third one for pwm for buzzer.

    2] How to setup 2 adc channels (A0,A1) in Sequence-of-channels / Repeat-sequence-of-channels.

    I know to setup for a single timer and single ADC channel. Are there any examples for these?

    Let me see if I can find something that does what you are looking for, but let me make sure I understand what you want to do.

    1. Timer interrupt for battery monitoring - This can be any timer that generates an interrupt at some fixed rate.  In the ISR you can determine if/when you want to read the battery.

    2. What PWM frequency are you planning to use? or maybe a better question is what are you going to use the PWM for?

    3. For the A/D, will one of the A/D channels going to be used to measure battery voltage and the other channel to read some other voltage, in sequence?

  • Hello Dennis, 

              A0 channel is for checking the accelerometer output and A1 channel is used for battery management.

    • The Accelerometer is gives some voltage when enable pin of this is made high. For the Accelerometer the adc is scanned continuously when a particular event occurs and enable pin is high. On next event Accelerometer is disabled by making enable pin low.
    • For Battery Management the adc channel must be scanned continuously with some delay in between say some 3 sec interval.

    I think for this we need a timer.

    OR

    both can also be read in sequence continuously and when it crosses a certain threshold voltage (for both the channels A0 and A1) perform a task 

     Timer is used for

    1. Creating a delay in the code .
    2. Buzzer, by varying pwm to create different pattern of sounds on a particular event.
  • Hi Gourav,

    The attached example code demonstrates how to use Timer1 as a "tick" timer that can be used to trigger events, such as reading the battery and accelerometer at two different rates.  Keep in mind this could also be done with two individual timers as well.  This is example only uses one timer.

    If after going through the example you have questions, please feel free to ask.

    The other timer, Timer0 is used to generate the frequency for the buzzer.

    Note: these are all based on several example code projects for the MSP430FR2433 found in the Resource explorer, and because this is the same family as FR2676 these will work.  You just need to make sure you setup your project for the FR2676.

    /* --COPYRIGHT--,BSD_EX
     * Copyright (c) 2014, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     *******************************************************************************
     * 
     *                       MSP430 CODE EXAMPLE DISCLAIMER
     *
     * MSP430 code examples are self-contained low-level programs that typically
     * demonstrate a single peripheral function or device feature in a highly
     * concise manner. For this the code may rely on the device's power-on default
     * register values and settings such as the clock configuration and care must
     * be taken when combining code from several examples to avoid potential side
     * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
     * for an API functional library-approach to peripheral configuration.
     *
     * --/COPYRIGHT--*/
    //******************************************************************************
    //  MSP430FR243x Demo - Timer0_A3, Toggle P1.0, CCR0 Up Mode ISR, DCO SMCLK
    //
    //  Description: Toggle P1.0 using software and TA_0 ISR. Timer0_A is
    //  configured for up mode, thus the timer overflows when TAR counts
    //  to CCR0. In this example, CCR0 is loaded with 50000.
    //  ACLK = n/a, MCLK = SMCLK = TACLK = default DCO ~1MHz
    //
    //
    //           MSP430FR2433
    //         ---------------
    //     /|\|               |
    //      | |               |
    //      --|RST            |
    //        |               |
    //        |           P1.0|-->LED
    //
    //
    //  Wei Zhao
    //  Texas Instruments Inc.
    //  Jan 2014
    //  Built with IAR Embedded Workbench v6.20 & Code Composer Studio v6.0.1
    //******************************************************************************
    #include <msp430.h>
    #include <stdbool.h>
    #include <stdint.h>
    
    // DEFINE DELAY VALUES BASED ON 10MSEC TICK RATE
    #define DELAY_3SEC          300
    #define DELAY_100MSEC       1
    
    // FOR DEBUGGING ONLY
    #define DEBUG1_SET_PIN(y)                  P1OUT |= (1 << (y))
    #define DEBUG1_CLR_PIN(y)                  P1OUT &= ~(1 << (y))
    #define DEBUG1_TGL_PIN(y)                  P1OUT ^= (1 << (y))
    #define DEBUG2_SET_PIN(y)                  P2OUT |= (1 << (y))
    #define DEBUG2_CLR_PIN(y)                  P2OUT &= ~(1 << (y))
    #define DEBUG2_TGL_PIN(y)                  P2OUT ^= (1 << (y))
    
    // GLOBAL VARIABLES
    uint16_t tickCountBattery = 0;
    uint16_t tickCountAccelerometer = 0;
    uint16_t ADCResult_ch7 = 0;
    uint16_t ADCResult_ch6 = 0;
    
    bool gBatteryTimeout = false;               // INDICATES WHEN TIME TO MEASURE BATTERY
    bool gBatteryADCMeasure = false;            // INDICATES WHEN ADC IS MEASURING BATTERY
    bool gBatteryADCResult = false;             // INDICATES WHEN ADC HAS BATTERY RESULTS
    bool gAccelerometerTimeout = false;         // INDICATES WHEN TIME TO MEASURE ACCELEROMETER
    bool gAccelerometerADCMeasure = false;      // INDICATES WHEN ADC IS MEASURING ACCELEROMETER
    bool gAccelerometerADCResult = false;       // INDICATES WHEN WHEN ADC HAS ACCELEROMETER RESULTS
    
    
    //===============================================================================================
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;   // Stop WDT
    
        /*
         * CONFIGURE GPIO
         * ALWAYS GOOD PRACTICE TO SET ALL IO AS OUTPUT AND DRIVE LOW
         * TO PREVENT PINS FROM FLOATING AND DRAWING EXTRA CURRENT
         * THIS IS PARTICULARLY IMPORTANT FOR BATTERY POWERED DEVICES
         */
        P1OUT = 0x00;
        P1DIR = 0xFF;
        P1SEL0 = 0;
        P1SEL1 = BIT1; // SELECT ALT FUNCTION FOR P1.1 = TA1.1 OUTPUT
    
        P2OUT = 0x00;
        P2DIR = 0xFF;
    
        P3OUT = 0x00;
        P3DIR = 0xFF;
        
        // Configure ADC A6,7 pins
         SYSCFG2 |= ADCPCTL6 | ADCPCTL7;    // A6 = BATTERY, A7 = ACCELEROMETER
    
        PM5CTL0 &= ~LOCKLPM5;       // Disable the GPIO power-on default
                                    // high-impedance mode to activate
                                    // previously configured port settings
        // GPIO CONFIGURATION DONE
    
        /*
         * CONFIGURE CLOCK SYSTEM
         * MSP RUNS @ 1MHZ (DEFAULT) WITHOUT ANY CONFIGURATION
         * IF WANT MSP TO RUN @ 8MHZ - CONSIDER COPY/PASTE FROM EXAMPLE msp430fr243x_CS_01.c
         * DON'T FORGET TO SET SMCLK = 1MHZ ELSE TIMING VALUE WILL ALL BE WRONG
         */
        // ************* OPTIONAL - USER TO ADD **************
        //
        // CLOCK SYSTEM CONFIGURATION DONE
    
        /*
         * CONFIGURE ADC
         * THIS DEMO MSP RUNS FROM +3.3LDO (MSP430FR2433 LAUNCHPAD) AND WE USE DVCC AS VREF
         * IF MSP IS POWERED DIRECTLY FROM BATTERY (NOT FROM LDO) AND WANT TO MEASURE VBATT,
         * CONSIDER EXAMPLE msp430fr243x_adc10_05 CONFIGURATION
    
         */
        // Configure ADC10 FOR SINGLE CHANNEL, SINGLE CONVERSION
        ADCCTL0 |= ADCSHT_2 | ADCON;                              // ADCON, S&H=16 ADC clks
        ADCCTL1 |= ADCSHP;                                        // ADCCLK = MODOSC; sampling timer
        ADCCTL2 |= ADCRES;                                        // 10-bit conversion results
        ADCIE |= ADCIE0;                                          // Enable ADC conv complete interrupt
        ADCMCTL0 |= ADCSREF_0;                                    // VREF=VDD, NOTE: A6,A7 are selected later when ready to measure
        //ADC CONFIGURATION DONE
    
    
        /*
         * CONFIGURE TIMERS
         * FOR THIS DEMO WE MODIFIED EXAMPLE - msp430fr243x_ta0_01
         * USE TIMER1_A0 AS TICK COUNTER
         * USE TIMER0_A0 FOR FREQUENCY GENERATION (OUTPUT ON P1.1)
         */
    
        // USER TIMER1 TO GENERATE TIMING TICKS FOR DELAYS
        TA1CCTL0 |= CCIE;                       // TACCR0 interrupt enabled
        TA1CCR0 = 10000;                        // 10Hz (10msec) based on 1MHz SMCLK
        TA1CTL = (TASSEL__SMCLK | TACLR);       // SMCLK, UP mode, Generate IRQ when TA1R = TA1CCR0
        TA1CTL |= MC__UP;                       // START TIMER
    
        // USER TIMER0 TO GENERATE FREQUENCY ON OUTPUT PIN
        // BASED ON 1MHZ SMCLK CAN GENERATE FROM 8HZ TO 176.5KHZ
        TA0CCTL0 = 0;            //
        TA0CCTL1 = (OUTMOD_4);                  // OUTPUT MODE = TOGGLE
        TA0CCR0 = 65535;
        TA0CCR1 = 32768;
        TA0CTL = (TASSEL__SMCLK | TACLR);       // SMCLK, UP mode
        TA0CTL |= MC__UP;                       // START TIMER
        // TIMER CONFIGURATION DONE
    
        while(1)
        {
            // ENTER SLEEP WHEN NOTHING TO DO
            DEBUG2_CLR_PIN(7);  // SHOW WE ARE GOING TO SLEEP
    
            __bis_SR_register(LPM0_bits | GIE);          // Enter LPM0 w/ interrupt
    
            // WE ARE HERE BECAUSE OF EITHER TIMER OR ADC INTERRUPT WOKE CPU
            // WHEN AWAKE - CHECK OUR FLAGS
            // BEST TO PERFORM THESE TASKS HERE IN BACKGROUND, NOT IN THE ISR
            DEBUG2_SET_PIN(7);  // SHOW WE ARE AWAKE AND RUNNING
    
            if(gAccelerometerTimeout == true)  // next highest priority
            {
                DEBUG1_SET_PIN(2);
    
                gAccelerometerTimeout = false;
    
                // CHECK IF ADC IS BUSY
                while(ADCCTL1 & ADCBUSY);
    
                // DISABLE A6 AND ENABLE A7
                ADCMCTL0 &= ~(ADCENC);          // Must first disable ADC before switching channels
    
                ADCMCTL0 &= ~(ADCINCH_6);
                ADCMCTL0 |= ADCINCH_7;
    
                ADCCTL0 |= ADCENC | ADCSC;     // Sampling and conversion start
    
                gAccelerometerADCMeasure = true;
    
                while(ADCCTL1 & ADCBUSY)
                {
                __bis_SR_register(LPM0_bits | GIE);          // Enter LPM0 w/ interrupt
                };
    
                // CALCULATE ACCELEROMETER VOLTAGE
                _no_operation();
    
            }
    
            if(gBatteryTimeout == true)
            {
                DEBUG1_TGL_PIN(0);
              //  DEBUG1_SET_PIN(3);
    
                gBatteryTimeout = false;
    
                // CHECK IF ADC IS BUSY
                while(ADCCTL1 & ADCBUSY);
    
                //DISABLE A7 AND ENABLE A6
                ADCMCTL0 &= ~(ADCENC);          // Must first disable ADC before switching channels
    
                ADCMCTL0 &= ~(ADCINCH_7);
                ADCMCTL0 |= ADCINCH_6;
    
                ADCCTL0 |= ADCENC | ADCSC;     // Sampling and conversion start
    
                gBatteryADCMeasure = true;
    
                while(ADCCTL1 & ADCBUSY)
                {
                __bis_SR_register(LPM0_bits | GIE);          // Enter LPM0 w/ interrupt
                };
    
                // CALCULATE BATTERY VOLTAGE
                _no_operation();
            }
    
        };
    }
    //=======================================================================
    // Timer1 A0 interrupt service routine
    // Handles TA1CCR0 CCIFG
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER1_A0_VECTOR
    __interrupt void Timer1_A0 (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER1_A0_VECTOR))) Timer_A (void)
    #else
    #error Compiler not supported!
    #endif
    {
    
        if(++tickCountAccelerometer == DELAY_100MSEC)
        {
            gAccelerometerTimeout = true;
            tickCountAccelerometer = 0;
        }
        if(++tickCountBattery == DELAY_3SEC)
        {
           gBatteryTimeout = true;
           tickCountBattery = 0;
        }
    
        // come out of sleep on reti
        __bic_SR_register_on_exit(LPM0_bits);
    }
    
    //=======================================================================
    // Timer1 A1 interrupt service routine
    // Handles TAIFG AND TA1CCR1 THRU TA1CCR6 CCIFG
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER1_A1_VECTOR
    __interrupt void Timer1_A1 (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER1_A1_VECTOR))) Timer_A (void)
    #else
    #error Compiler not supported!
    #endif
    {
        // TO CHANGE FREQUENCY ON THE FLY MODIFY TA0CCR0 AND TA0CCR1 IN ISR
        // NOTE: TIMERA DOES NOT HAVE COMPARE LATCH
        switch(__even_in_range(TA1IV,TA1IV_TAIFG))
        {
            case TA1IV_NONE:
                break;                               // No interrupt
            case TA1IV_TACCR1:
                //CHANGE HERE
                break;                               // CCR1 not used
            case TA1IV_TACCR2:
                break;                               // CCR2 not used
            case TA1IV_TAIFG:
                break;
            default:
                break;
        }
    }
    #if 0
    //=======================================================================
    // Timer0 A0 interrupt service routine
    // Handles TA0CCR0 CCIFG
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer0_A0 (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer_A (void)
    #else
    #error Compiler not supported!
    #endif
    {
         // go back to sleep on reti
        __bis_SR_register_on_exit(LPM0_bits);
    }
    
    //=======================================================================
    // Timer1 A1 interrupt service routine
    // Handles TAIFG AND TA0CCR1 THRU TA0CCR6 CCIFG
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void Timer0_A1 (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(TIMER0_A1_VECTOR))) Timer_A (void)
    #else
    #error Compiler not supported!
    #endif
    {
        switch(__even_in_range(TA0IV,TA0IV_TAIFG))
        {
            case TA0IV_NONE:
                break;                               // No interrupt
            case TA0IV_TACCR1:
                break;                               // CCR1 not used
            case TA0IV_TACCR2:
                break;                               // CCR2 not used
            case TA0IV_TAIFG:
                break;
            default:
                break;
        }
    }
    #endif
    // ADC interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC_VECTOR
    __interrupt void ADC_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
        switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
        {
            case ADCIV_NONE:
                break;
            case ADCIV_ADCOVIFG:
                break;
            case ADCIV_ADCTOVIFG:
                break;
            case ADCIV_ADCHIIFG:
                break;
            case ADCIV_ADCLOIFG:
                break;
            case ADCIV_ADCINIFG:
                break;
            case ADCIV_ADCIFG:
                if(gAccelerometerADCMeasure == true)
                {
                    ADCResult_ch7 = ADCMEM0;
                    gAccelerometerADCMeasure = false;
                    gAccelerometerADCResult = true;
                    DEBUG1_CLR_PIN(2);
                }
                else if(gBatteryADCMeasure == true)
                {
                    ADCResult_ch6 = ADCMEM0;
                    gBatteryADCMeasure = false;
                    gBatteryADCResult = true;
                    DEBUG1_CLR_PIN(3);
    
                }
    
                // come out of sleep on reti
                __bic_SR_register_on_exit(LPM0_bits);
                break;
            default:
                break;
        }
    }
    

  • Hi Dennis,

    I have some doubts on the code that you have provided.

    1. As per the user guide for msp430fr2676tpt, ADCPCTL0 to ADCPCTL7 are defined in msp430fr2676.h. I have checked that they are undefined so the line //SYSCFG2 |= ADCPCTL6 | ADCPCTL7;    // A6 = BATTERY, A7 = ACCELEROMETER //generates an error.
    2. The switching of adc channels can also be done in timer tick event of Timer1 A0 interrupt service routine?? . 
    3. what is the significance of the DEBUG MACROS?? Are they used to check whether the mcu is lmp0 mode ,or to indicate the adc data of the accelerometer and battery is ready.
    4. I want to integrate this with captivate touch with 12 self capios buttons  in which lpm3 and wale on proximity is used , How does the mcu enters and exits the lpm0 and lpm3.

  • Hi Gourav,

    Gourav H said:
    As per the user guide for msp430fr2676tpt, ADCPCTL0 to ADCPCTL7 are defined in msp430fr2676.h. I have checked that they are undefined so the line //SYSCFG2 |= ADCPCTL6 | ADCPCTL7;    // A6 = BATTERY, A7 = ACCELEROMETER //generates an error.

    I did this on MSP430FR2433, so you will have to pick the analog channels you need.

    Gourav H said:
    The switching of adc channels can also be done in timer tick event of Timer1 A0 interrupt service routine?? . 

    Yes.  I was showing only one way to do it.  Typically you want to spend least amount of time in ISR (foreground) and do the work in the main loop (background).

    Gourav H said:
    what is the significance of the DEBUG MACROS?? Are they used to check whether the mcu is lmp0 mode ,or to indicate the adc data of the accelerometer and battery is ready.

    I use the debug macros to simplify setting, clearing or toggling an IO pin so I can monitor with my logic probe to ensure the timing is correct and everything is working as expected.  You can delete them.

    Gourav H said:
    I want to integrate this with captivate touch with 12 self capios buttons  in which lpm3 and wale on proximity is used , How does the mcu enters and exits the lpm0 and lpm3

    If you have created a project using the Captivate design center you will see in the main loop that after the call to CAPT_appHanlder(), the device is put into LPM0 or LPM3.  It depends if you configured the project to run with UART (must use LPM0) or all other configurations use LPM3.  Reason is when using UART, it takes too long (10uS) for the clocks to startup from LPM3 and you will miss one or more bits sent by the HOST (or PC), especially at higher baud rates.  When using LPM0, only CPU stops, all clocks remain running.  That is why recommend use LPM0 if using UART.

  • Hi Dennis,

               

    Dennis Lehman said:
    Reason is when using UART, it takes too long (10uS) for the clocks to startup from LPM3 and you will miss one or more bits sent by the HOST (or PC), especially at higher baud rates.  When using LPM0, only CPU stops, all clocks remain running.  That is why recommend use LPM0 if using UART.

    The msp430fr2676 acts as a Host in my application which is interfaced with cc3220 through uart with 9600 baud rate and this application is battery powered so to achieve Low power is a must (ie LPM3). Is it ok with 9600 baud rate?? OR how lower should be the baud rate so that the bits don't miss in LPM3 ?? 

    What about the SPI and I2C do these also have some issue using LPM3??  I have configured the project in LPM3 (ie  in CAPT_appSleep()) and the rest in LPM0 when using timer/adc/spi/i2c/uart.

  • Hi Gourav,

    UART is clocked by the device itself and only data on the TX/RX lines with the configured baud rate. So if the receiver's clock is not ready, may be a wrong frequency or even is starting up, when the data comes from the line, it will get error for the clock beat. It is no matter with the baud rate you configured. You should make sure the clock of UART module is ready when data comes from the line.

    SPI and I2C are another cases which the clock is sourced by the line of CLK/SCL. So that it should be okay for SPI and I2C even the device clock is not ready when data starts on the line.

**Attention** This is a public forum