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.

RTOS/MSP432P401R: Why are my interrupts not able to fire the ISR fast enough?

Part Number: MSP432P401R

Tool/software: TI-RTOS

Hi All,

I have a driverlib project without TI-RTOS that works properly to make multi channel ADC14 measurements initiated by TimerA0 at 8 KHz.  However, when I try and integrate this project into Energia (based on TI-RTOS) the interrupts only get fired at 1000 Hz.   At first I thought that Energia was fiddling with the clock speed setting an extra divide by 8 somewhere, but I can't find it in the CS, or TimerA sections.  If I set the CCR1 so that the number of counts is less, I get no interrupts at all.  I have four channels to convert, and note that if I change the interrupt to fire after the first conversion instead of the last, that the interrupts fire four times as fast, so it is as if the conversions were taking a very long time (1/4000 of a second).  I'm looking for tips on how to debug this:

  1. Is there a good way to measure the speed of SMCLK?
  2. Is there a way to measure MCLK?
  3. Is there a way of finding out what is making the interrupts not able to fire?  Perhaps there is another interrupt with higher priority.
  4. What would cause the ADC14 to be so slow?

I have three files: the .ino, the .c and .h:  They are supplied below:

// The .ino file.
extern "C"{
#include <copy2_adc14.h>
};


// most launchpads have a red LED
#define LED RED_LED

//see pins_energia.h for more LED definitions
//#define LED GREEN_LED

// the setup routine runs once when you press reset:
void setup() {
  Serial.begin(115200);
  // initialize the digital pin as an output.
  //pinMode(LED, OUTPUT);
  adc14_();
  //delay(500);
  //MAP_ADC14_enableConversion();
  startSampling();
}

// the loop routine runs over and over again forever:
void loop() {
    static int i=0;
    Serial.print(i++);
  Serial.println("Hello!");
    //digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  //delay(1000);               // wait for a second
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

And the header file:

/*
 * adc14_.h
 *
 *  Created on: May 12, 2017
 *      Author: frohro
 */

#ifndef COPY2_ADC14_H_
#define COPY2_ADC14_H_

/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include <ti/sysbios/family/arm/m3/Hwi.h>

/* Standard Includes */
#include <stdint.h>

#include <stdbool.h>
#define SMCLK_FREQ 24000000
#define SAMPLE_FREQ 8000
//Timer_A Continuous Mode Configuration Parameter
const Timer_A_UpModeConfig upModeConfig = // This DOES work
{
        TIMER_A_CLOCKSOURCE_SMCLK,           // SM Clock Source
        TIMER_A_CLOCKSOURCE_DIVIDER_1,       // SMCLK/1 = 24MHz
        (SMCLK_FREQ/SAMPLE_FREQ),
        TIMER_A_TAIE_INTERRUPT_DISABLE,      // Disable Timer ISR
        TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE, // Disable CCR0
        TIMER_A_DO_CLEAR                     // Clear Counter
};

/* Timer_A Compare Configuration Parameter */
const Timer_A_CompareModeConfig compareConfig =
{
        TIMER_A_CAPTURECOMPARE_REGISTER_1,          // Use CCR1
        TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,   // Disable CCR interrupt
        TIMER_A_OUTPUTMODE_SET_RESET,               // Toggle output but
        (SMCLK_FREQ/SAMPLE_FREQ)                    // Should be 8 kHz sample rate
};

/* Statics */
static volatile uint_fast16_t resultsBuffer[UINT8_MAX];
static volatile uint8_t resPos;

int adc14_(void);
void ADC14_IRQHandler(void);
void startSampling(void);




#endif /* COPY2_ADC14_H_ */

and lastly the C file:

/*
 * -------------------------------------------
 *    MSP432 DriverLib - v4_00_00_11
 * -------------------------------------------
 *
 * --COPYRIGHT--,BSD,BSD
 * Copyright (c) 2017, 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.
 * --/COPYRIGHT--*/
 /* MSP432 ADC14 - Multiple Channel Sample without Repeat
 *
 * Description: In this code example, the feature of being able to scan multiple
 * ADC channels is demonstrated by the user a the DriverLib APIs.  Conversion
 * memory registers ADC_MEM0 - ADC_MEM3 are configured to read conversion
 * results from A6, A12, A10, A8 respectively. Conversion is enabled and then sampling is
 * toggled using a software toggle. Repeat mode is not enabled and sampling only
 * occurs once (and it is expected that the user pauses the debugger to observe
 * the results). Once the final sample has been taken, the interrupt for
 * ADC_MEM3 is triggered and the result is stored in the resultsBuffer buffer.
 *
 *                MSP432P401
 *             ------------------
 *         /|\|                  |
 *          | |                  |
 *          --|RST         P4.7  |<--- A6 (Analog Input, Measured, Real)
 *            |            P4.1  |<--- A12 (Analog Input, Measured, Imaginary)
 *            |            P4.3  |<--- A10 (Analog Input, Reference Real)
 *            |            P4.5  |<--- A8 (Analog Input, Reference Imaginary)
 *            |                  |
 *            |                  |
 *
 *            4.1, 4.3, 4.5, 4.7 are the eventual pins needed.
 *
 * Author: Timothy Logan
 * This was modified by Rob Frohne to do multiple ADC at 8 kHz sample rate.
 ******************************************************************************/
#include <copy2_adc14.h>
#define NUMBER_TIMER_CAPTURES       20
#define SAMPLE_LENGTH 128

/*
static volatile uint_fast16_t timerAcaptureValues[NUMBER_TIMER_CAPTURES];
static volatile uint32_t timerAcapturePointer = 0;
*/

uint16_t refRe[SAMPLE_LENGTH];
uint16_t refIm[SAMPLE_LENGTH];
uint16_t measRe[SAMPLE_LENGTH];
uint16_t measIm[SAMPLE_LENGTH];
extern volatile bool doneADC;
bool sendMeasurement = false;
int numberFrequenciestoMeasure, frequencyIndex;
float  refSum, measSum;
volatile bool doneADC = false;
//void TA0_N_IRQHandler(void);

int adc14_(void)
{
    /* Halting WDT  */
    WDT_A_holdTimer();
    Hwi_Params params;

    // Register interrupt
    Hwi_Params_init(&params);
    Hwi_create(INT_ADC14, ADC14_IRQHandler, &params, 0);
    //Hwi_create(INT_TA0_N, TA0_N_IRQHandler, &params, 0);
    //Interrupt_enableSleepOnIsrExit();
    resPos = 0;
    // Set to Vcore1
    PCM_setCoreVoltageLevel(PCM_VCORE1);

    // Set to use DCDC
    //PCM_setPowerState(PCM_AM_DCDC_VCORE1);

    // Initializes Clock System
    /*  These commented out because we need the Energia clock setup.  The
     *  data structures for the timer are adjusted accordingly.  The time
     *  between conversions may be four times as much as we had with these
     *  parameters below, but this seems like the easiest way to make everything
     *  play together for now. */
    //FlashCtl_setWaitState( FLASH_BANK0, 2);
    //FlashCtl_setWaitState( FLASH_BANK1, 2);
    PCM_setPowerState( PCM_AM_DCDC_VCORE1 );
    CS_setDCOCenteredFrequency( CS_DCO_FREQUENCY_24 );
    CS_setDCOFrequency(24000000);
    CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );;
    CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );


    /* Initializing ADC (MCLK/1/1) */
    ADC14_enableModule();
    ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
                         0);

    // Configuring debugging pins as output for debugging...
    GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5);
    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);

    //Configuring GPIOs for Analog In
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4,
        GPIO_PIN1 | GPIO_PIN3 | GPIO_PIN5 | GPIO_PIN7, GPIO_TERTIARY_MODULE_FUNCTION);

    // Configuring ADC Memory (ADC_MEM0 - ADC_MEM3 (A6, A12, A10, A8)  with no repeat)
    // with internal 2.5v reference
    ADC14_configureMultiSequenceMode(ADC_MEM0, ADC_MEM3, true); // No repeat mode.
    ADC14_configureConversionMemory(ADC_MEM0,
                                        ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                        ADC_INPUT_A6, ADC_NONDIFFERENTIAL_INPUTS);
    ADC14_configureConversionMemory(ADC_MEM1,
                                        ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                        ADC_INPUT_A12, ADC_NONDIFFERENTIAL_INPUTS);
    ADC14_configureConversionMemory(ADC_MEM2,
                                        ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                        ADC_INPUT_A10, ADC_NONDIFFERENTIAL_INPUTS);
    ADC14_configureConversionMemory(ADC_MEM3,
                                        ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                        ADC_INPUT_A8, ADC_NONDIFFERENTIAL_INPUTS);

    /* Configuring Timer_A*/
    Timer_A_configureUpMode(TIMER_A0_BASE, &upModeConfig);

    /* Configuring Timer_A0 in CCR1 */
    Timer_A_initCompare(TIMER_A0_BASE, &compareConfig);

    /* Configuring the sample trigger to be sourced from Timer_A0  and setting it
     * to automatic iteration after it is triggered*/
    ADC14_setSampleHoldTrigger(ADC_TRIGGER_SOURCE1, false);

    /* Enabling the interrupt when a conversion on channel 3 is complete*/
    ADC14_enableInterrupt(ADC_INT3);
    //ADC14_enableConversion(); // Not needed because we enable it in .ino.

    /* Enabling Interrupts */
    Interrupt_enableInterrupt(INT_ADC14);
    Interrupt_enableMaster();

    /* Starting the Timer */
    Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_UP_MODE);

    /* Going to sleep */
  /*      while (1)
    {
        PCM_gotoLPM0();
    }*/
    return 1;
}


void ADC14_IRQHandler(void)
{
    uint64_t status;
    static int i = 0;
    //GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
    status = ADC14_getEnabledInterruptStatus();
    ADC14_clearInterruptFlag(status);
    GPIO_toggleOutputOnPin(GPIO_PORT_P5, GPIO_PIN5);
    ADC14_disableConversion();

    if(status & ADC_INT3)
    {
        //ADC14_disableConversion();
        doneADC = false;
        ADC14_getMultiSequenceResult(resultsBuffer);
        measRe[i] = resultsBuffer[0];
        measIm[i] = resultsBuffer[1];
        refRe[i] = resultsBuffer[2];
        refIm[i] = resultsBuffer[3];
        //i=(i+1)%SAMPLE_LENGTH;

        if (i!=SAMPLE_LENGTH)
        {
            i++;
            //ADC14_enableConversion();
        }
        else
        {
            i=0;
            doneADC = true;
            //ADC14_enableConversion();
        }
    }
    ADC14_enableConversion();
}

/*void TA0_N_IRQHandler(void)
{
    uint32_t jj;

    Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
            TIMER_A_CAPTURECOMPARE_REGISTER_1);

    timerAcaptureValues[timerAcapturePointer++] =
            Timer_A_getCaptureCompareCount(TIMER_A0_BASE,
                                             TIMER_A_CAPTURECOMPARE_REGISTER_1);

    if (timerAcapturePointer >= NUMBER_TIMER_CAPTURES)
    {
        while (1)
        {
            GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
            for(jj=0;jj<10000;jj++);
        }
    }
}*/

void startSampling(void)
{
    ADC14_enableConversion();  // It is a mystery why I need to do this
    // instead of just calling ADC14_enableConversion()
    // from the .ino file!
}

Thanks for the tips!

Rob

  • Hello,

    Thanks for posting to the forum! We are looking into the matter and trying to get your request to the right team. We will get back to you in time.

    Best regards,

    David
  • Thanks David,
    I have looked more closely, and it appears that the TI-RTOS (Energia) seems to be changing the setup that I do in the .ino. At this point I'm not sure when. I'm trying to figure out how to make it so Energia doesn't initialize stuff I don't need, like the ADC. I may need to modify the Energia wiring_analog.c, and other stuff in Energia/emt/src/ti/runtime/wiring/msp432/ or maybe some other Energia source, or perhaps ditch the idea of using Energia, but I'm not giving up quickly.

    Thanks!

    Rob

  • Rob,


    Can you help us understand what your purpose behind using Energia in this case is? Why not work with CCS in this case? Just curious!

  • Hi Evan,

    I am actually using Code Composer Studio with the Energia stuff and in general it works nicely.  When I use the word Energia, I mean the runtime code, not the IDE.  I am not using driverlib single threaded bare metal code.  Below is a little explanation of my thoughts regarding the choice between these two options.

    My engineering electronics students are designing vector network analyzer booster packs for the MSP432 Launchpads.  The analyzers communicate serially with a host PC, and include a programmable (via I2C) oscillator, as well as needing the ADC and GPIO.  The class is not about software, but designing hardware, so I'm doing the software for them.  Of course they will have to do some messing with the software, but I wanted to make that as easy as possible.  Last year we did a somewhat similar project, and I found that the most difficult part of the software design was getting the I2C communications with a fancy Versaclock oscillator running without bugs, and some of the students used a different oscillator (a TI one), so that they had to work way too hard on the software side of things.  Because we were using these oscillators as swept signal generators, with two outputs 90 degrees out of phase, there was a lot of oscillator setup required. Most people using these type of oscillators just program them once with manufacturer provided PC software, and with that they are done with it.  This year all the students decided on an Si5351 programmable oscillator instead of the Versaclock or the other TI oscillator, and I found a nice Arduino Library with all the features I needed for the Si5351.  At first I was just going to use the library as example code to develop my own driverlib bare metal software like I did last year, but then I realized that Energia existed, and so I tried it, and it just worked very nicely with the I2C library I found for the Si5351, as did the serial communications with a host PC.  I decided to try bolting my previously developed bare metal ADC14 code on to Energia.  I was kind of hoping that since the only thing I wasn't doing the Energia way was the ADC14, that there would be little interference.  It also seemed like it would be a very nice thing in general to be able to use mostly Energia libraries and only where Energia didn't provide the performance needed, would you have to bolt on some driverlib code.  I've been reading the core runtime code for Energia, and still think this would be nice.  There are some things, however, that I know now that might have discouraged me from this path.  They are:

    • You can only use multithreaded (MT) projects.  Even though there is a button in Code Composer Studio that makes it look like you can disable multi-threading, on the MSP432, you cannot.  (It would have been nice if instead of just being checked, the Code Composer Studio button had been grayed out as well, because this would not have misled me.)  This may be a problem, because I read in the MT Energia code lots of places where interrupts are disabled for thread safety.
    • The timers seem to be used a lot in the Energia code.  I figured that some would be used, but with eight different timer triggers for the ADC14, I figured that I could find one that would work, and I need to finish exploring this, because it is still a possibility.
    • I still haven't found anyone else who has done this kind of thing.  It would have been easier, if someone else had pioneered this idea, but at least the source code for the MT Energia there.

    At this point, I'm not ready to ditch, and go with the bare metal solution, because it still looks doable to me.  If I can make it so the only thing that is disabled by bolting on my ADC14 code is the AnalogXXX() functions of Energia, it would make the software more friendly to my students.  They could do anything they like the Arduino way, except using the AnalogXXX() functions.   Wouldn't that be nice!

    Thanks for all the assistance!

    Rob

  • Hi All,

    Here is a little more information I have been able to tease out by testing today.  

    • I have tried TimerA0, TimerA1, and TimerA2, and TimerA3.  I can't get it to work with any of them.
    • I note that TAxR stops incrementing at what appear to be random times, usually less than 500 counts at 12 MHz.
    • I have stopped the program at random times, and once ended up in Timer.c, where it appears that TI-RTOS uses all the timers if it wants.  I'm wondering about setting Timer_numTimerDevices to be one less than it is, and trying to use TimerA3 to trigger my ADC14 ISR.
    • I have a simple timer example that works intermittently.  It seems to be work more of the time than the ADC14 routine I posted above, so there may be other issues than just the timer.  It is posted below:
    /*
      Blink
      The basic Energia example.
      Turns on an LED on for one second, then off for one second, repeatedly.
      Change the LED define to blink other LEDs.
      
      Hardware Required:
      * LaunchPad with an LED
      
      This example code is in the public domain.
    */
    extern "C"{
    #include "ta_up.h"
    };
    // most launchpads have a red LED
    #define LED RED_LED
    
    //see pins_energia.h for more LED definitions
    //#define LED GREEN_LED
      
    // the setup routine runs once when you press reset:
    void setup() {                
      // initialize the digital pin as an output.
      pinMode(LED, OUTPUT);
      ta_up_main();
    }
    
    // the loop routine runs over and over again forever:
    void loop() {
      //digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);               // wait for a second
      digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);               // wait for a second
    }
    

    and the header file:

    /*
     * ta_up.h
     *
     *  Created on: May 3, 2017
     *      Author: frohro
     */
    
    #ifndef TA_UP_H_
    #define TA_UP_H_
    
    #include <ti/sysbios/family/arm/m3/Hwi.h>
    int ta_up_main(void);
    
    #endif /* TA_UP_H_ */
    

    and lastly the C file:

    /*
     * ta_up.c
     *
     *  Created on: May 3, 2017
     *      Author: frohro
     */
    
    /*
     * -------------------------------------------
     *    MSP432 DriverLib - v4_00_00_11
     * -------------------------------------------
     *
     * --COPYRIGHT--,BSD,BSD
     * Copyright (c) 2017, 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.
     * --/COPYRIGHT--*/
    /*******************************************************************************
     * MSP432 PWM TA1.1-2, Up/Down Mode, 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 0x2DC6 which makes the LED
     * toggle every half a second..
     * ACLK = n/a, MCLK = SMCLK = default DCO ~1MHz
     * TACLK = SMCLK/64
     *
     *         MSP432P401
     *      -------------------
     *  /|\|                   |
     *   | |                   |
     *   --|RST                |
     *     |                   |
     *     |               P1.0|-->LED
     *     |                   |
     *
     * Author: Timothy Logan
    *******************************************************************************/
    /* DriverLib Includes */
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    #include "ta_up.h"
    
    void TA1_0_IRQHandler(void)
    {
        GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
        GPIO_toggleOutputOnPin(GPIO_PORT_P5, GPIO_PIN5);
        Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE,
                TIMER_A_CAPTURECOMPARE_REGISTER_0);
    }
    
    
    /* Application Defines  */
    #define TIMER_PERIOD    0x2DC6
    
    /* Timer_A UpMode Configuration Parameter */
    const Timer_A_UpModeConfig upConfig =
    {
            TIMER_A_CLOCKSOURCE_SMCLK,              // SMCLK Clock Source
            TIMER_A_CLOCKSOURCE_DIVIDER_64,          // SMCLK/1 = 3MHz
            TIMER_PERIOD,                           // 5000 tick period
            TIMER_A_TAIE_INTERRUPT_DISABLE,         // Disable Timer interrupt
            TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE ,    // Enable CCR0 interrupt
            TIMER_A_DO_CLEAR                        // Clear value
    };
    
    int ta_up_main(void)
    {
        Hwi_Params params;
    
        /* Stop WDT  */
        WDT_A_holdTimer();
    
        // Register interrupt
        Hwi_Params_init(&params);
        Hwi_create(INT_TA1_0, TA1_0_IRQHandler, &params, 0);
    
        /* Configuring P1.0 as output */
        GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
        GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
        GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5);
            GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    
        /* Configuring Timer_A1 for Up Mode */
        Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);
    
        /* Enabling interrupts and starting the timer */
        Interrupt_enableSleepOnIsrExit();
        Interrupt_enableInterrupt(INT_TA1_0);
        Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);
    
        /* Enabling MASTER interrupts */
        Interrupt_enableMaster();
    
        /* Sleeping when not in use */
        //while (1)
        {
            //PCM_gotoLPM0();
        }
        return 1;
    }

    And here is Timer.h from the TI-RTOS for your reference:

    /*
     * Copyright (c) 2014-2016, 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.
     */
    /*
     *  ======== Timer.c ========
     *
     */
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/Assert.h>
    #include <xdc/runtime/Startup.h>
    #include <xdc/runtime/Types.h>
    
    #include <ti/sysbios/BIOS.h>
    
    #include <ti/sysbios/family/arm/m3/Hwi.h>
    #include <ti/sysbios/family/arm/msp432/ClockFreqs.h>
    
    /* TODO: move this peripheral register definition to catalog? */
    typedef volatile struct ti_catalog_msp432_peripherals_timers_TimerRegs {
        UInt16 control;
        UInt16 cctl_0;
        UInt16 cctl_1;
        UInt16 cctl_2;
        UInt16 cctl_3;
        UInt16 cctl_4;
        UInt16 cctl_5;
        UInt16 cctl_6;
        UInt16 count;
        UInt16 cc_compare_0;
        UInt16 cc_compare_1;
        UInt16 cc_compare_2;
        UInt16 cc_compare_3;
        UInt16 cc_compare_4;
        UInt16 cc_compare_5;
        UInt16 cc_compare_6;
        UInt16 expansion;
        UInt16 reserved[6];
        UInt16 vector;
    } ti_catalog_msp432_peripherals_timers_TimerRegs;
    
    #include "package/internal/Timer.xdc.h"
    
    #define MC           0x0020        /* mode, control = continous up counting */
    #define TxCLR        0x0004        /* clear timer counter */
    #define CCIE         0x0010        /* compare interrupt enable */
    #define CCIFG        0x0001        /* compare interrupt pending flag */
    #define TSSEL        0x0100        /* source select = ACLK */
    #define ID_MASK      0x00C0        /* input divider bit mask */
    
    #define TIMER_CONTROL_START           MC
    #define TIMER_CONTROL_CLEAR           TxCLR
    #define TIMER_CONTROL_DEFAULT         TSSEL
    #define TIMER_COMPARE_INTR_ENABLE     CCIE
    #define TIMER_COMPARE_INTR_PENDING    CCIFG
    
    #define TIMER_DELETED       0
    #define BAD_TIMER_ID        1
    #define NO_TIMER_AVAIL      2
    #define NO_HWI_OBJ          3
    #define BAD_PERIOD          4
    
    #define READ_LATENCY                    10   /* # MCLK cycles to allow for
                                                    back-to-back read of count */
    
    #define SYS_PERI_HALTCTL_REG    0xE004300C   /* peripheral halt control reg */
    #define REG(x)  (*((volatile unsigned *)(x)))
    
    /*
     *  ======== Timer_getAvailMask ========
     */
    UInt Timer_getAvailMask()
    {
        return (Timer_module->availMask);
    }
    
    /*
     *  ======== Timer_getNumTimers ========
     *  Get number of timer peripherals available on the device.
     */
    UInt Timer_getNumTimers()
    {
        return (Timer_numTimerDevices);
    }
    
    /*
     *  ======== Timer_getStatus ========
     *  Get the FREE/INUSE status of the timer.
     */
    Timer_Status Timer_getStatus(UInt timerId)
    {
        Assert_isTrue(timerId < Timer_numTimerDevices, NULL);
    
        if (Timer_module->availMask & (0x1 << timerId)) {
            return (Timer_Status_FREE);
        }
        else {
            return (Timer_Status_INUSE);
        }
    }
    
    /*
     *  ======== Timer_getMaxTicks ========
     */
    UInt32 Timer_getMaxTicks(Timer_Object *obj)
    {
        return (0x0000FFFF / obj->period);
    }
    
    /*
     *  ======== Timer_setAvailMask ========
     */
    Bool Timer_setAvailMask(UInt mask)
    {
        UInt i;
        UInt key;
        UInt tmpMask;
    
        key = Hwi_disable();
        tmpMask = mask;
        for (i = 0; i < Timer_numTimerDevices; i++) {
            /* Check if mask is setting any currently used timer as available */
            if ((tmpMask & 0x1) && (Timer_module->handles[i] != NULL)) {
                Hwi_restore(key);
                return (FALSE);
            }
            tmpMask = tmpMask >> 1;
        }
        Timer_module->availMask = mask;
        Hwi_restore(key);
    
        return (TRUE);
    }
    
    /*
     *  ======== Timer_setNextTick ========
     *  Program the timer's interrupt threshold for the next tick.
     */
    Void Timer_setNextTick(Timer_Object *obj, UInt32 ticks)
    {
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
        UInt32 newPeriod = obj->period * ticks;
        UInt next;
        UInt previous;
        UInt now;
    
        /* get timer base address */
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        previous = obj->prevThreshold;
    
        /* next is relative to savedCurrCount */
        next = obj->savedCurrCount + newPeriod;
    
        /* set the compare threshold for next interrupt */
        timer->cc_compare_0 = next;
    
        /*
         * MSP432 timers will only interrupt if the timer counts *to* the threshold.
         * So we must check to make sure that the threshold wasn't set too late -
         * if it was set late, the timer count will need to wrap before the next
         * interrupt is triggered.  To avoid this, after writing the next
         * interrupt threshold, we read the current count, and if the interrupt
         * threshold was set too late per the current count, we again write
         * to the timer to trigger an immediate interrupt.
         *
         * For the cases where the 'next' threshold is more than the 'previous',
         * the timer will not wrap before the next target tick interrupt.  This
         * creates three regions shown below (A, B, C), where the current 'now'
         * count will reside:
         *
         *  FFFF |                  -
         *       |                  B
         *       |<----- next       -
         *       |                  A
         *       |<----- previous   -
         *       |                  C
         *    0  |                  -
         *
         * A - 'now' is greater than equal to 'previous', and less than 'next':
         * this is the 'normal' region, where the threshold has been set before the
         * next threshold, and no adjustment is needed.
         *
         * B - 'now' is greater than equal to 'next': the threshold was set
         * late, trigger an interrupt now.
         *
         * C - 'now' is less than 'previous': the threshold was set late, trigger
         * an interrupt now.
         *
         * For the cases where the 'next' threshold is less than the 'previous',
         * the timer count is expected to wrap before the next tick interrupt.
         * This creates the three regions shown below (D, E, F), where the current
         * 'now' count will reside:
         *
         *  FFFF |                  -
         *       |                  D
         *       |<----- previous   -
         *       |                  F
         *       |<----- next       -
         *       |                  E
         *    0  |                  -
         *
         * D - 'now' is greater than equal to 'previous': this is a 'normal'
         * region, where the threshold has been set before the next threshold,
         * and no adjustment is needed.
         *
         * E - 'now' is less than 'next': this is another 'normal' region,
         * where the threshold has been set early enough, and no adjustment is
         * needed.
         *
         * F - 'now' is greater than or equal to 'next' and less than
         * 'previous': the threshold was set too late, trigger an interrupt now.
         */
    
        /* get current timer count */
        now = Timer_getCount(obj);
    
        /* if not expecting wrap thru zero ... */
        if (next > previous) {
    
            /* case "B": now is greater than or equal to next, interrupt now */
            if (now >= next) {
                timer->cctl_0 |= CCIFG;
            }
    
            /* case "C": now < previous, count has wrapped, interrupt now */
            else {
                if (now < previous) {
                    timer->cctl_0 |= CCIFG;
                }
            }
        }
    
        /* else, expecting wrapping thru zero ... */
        else {
    
            /* case F: now is between next and previous, interrupt now */
            if ((now < previous) && (now >= next)) {
                timer->cctl_0 |= CCIFG;
            }
        }
    }
    
    /*
     *  ======== Timer_Module_startup ========
     *  Calls postInit for all statically-created & constructed
     *  timers to initialize them.
     */
    Int Timer_Module_startup(Int status)
    {
        Int i;
        Timer_Object *obj;
    
        if (Timer_startupNeeded) {
            for (i = 0; i < Timer_numTimerDevices; i++) {
                obj = Timer_module->handles[i];
                /* if timer was statically created/constructed */
                if ((obj != NULL) && (obj->staticInst)) {
                    Timer_postInit(obj, NULL);
                }
            }
        }
    
        return (Startup_DONE);
    }
    
    /*
     *  ======== Timer_startup ========
     *  Here after call to main().  Called from BIOS_start().
     */
    Void Timer_startup()
    {
        Int i;
        Timer_Object *obj;
    
        if (Timer_startupNeeded) {
            for (i = 0; i < Timer_numTimerDevices; i++) {
                obj = Timer_module->handles[i];
                /* if timer was statically created/constructed */
                if ((obj != NULL) && (obj->staticInst)) {
                    if (obj->startMode == Timer_StartMode_AUTO) {
                            Timer_start(obj);
                    }
                }
            }
        }
    }
    
    /*
     *  ======== Timer_getHandle ========
     */
    Timer_Handle Timer_getHandle(UInt id)
    {
        Assert_isTrue((id < Timer_numTimerDevices), NULL);
        return (Timer_module->handles[id]);
    }
    
    /*
     *  ======== Timer_Instance_init ========
     * 1. Select timer based on id
     * 2. Mark timer as in use
     * 3. Init timer obj using params
     * 4. Create Hwi if tickFxn != NULL
     * 5. Initialize timer
     * 6. Configure timer (wrt emulation, frequency, etc.)
     * 7. Set period
     * 8. Timer_start()
     *
     */
    Int Timer_Instance_init(Timer_Object *obj, Int id, Timer_FuncPtr tickFxn, const Timer_Params *params, Error_Block *eb)
    {
        Int status;
        UInt key;
        Int i;
        Hwi_Params hwiParams;
        UInt tempId = 0xffff;
    
        if (id >= Timer_numTimerDevices) {
            if (id != Timer_ANY) {
                Error_raise(eb, Timer_E_invalidTimer, id, 0);
                return (BAD_TIMER_ID);
            }
        }
    
        key = Hwi_disable();
    
        if (id == Timer_ANY) {
            for (i = 0; i < Timer_numTimerDevices; i++) {
                if ((Timer_anyMask & (1 << i))
                    && (Timer_module->availMask & (1 << i))) {
                    Timer_module->availMask &= ~(1 << i);
                    tempId = i;
                    break;
                }
            }
        }
        else if (Timer_module->availMask & (1 << id)) {
            Timer_module->availMask &= ~(1 << id);
            tempId = id;
        }
    
        Hwi_restore(key);
    
        obj->staticInst = FALSE;
    
        if (tempId == 0xffff) {
            Error_raise(eb, Timer_E_notAvailable, id, 0);
            return (NO_TIMER_AVAIL);
        }
        else {
            obj->id = tempId;
        }
    
        if (params->clockSource == Timer_Source_ACLK) {
            obj->controlRegInit = 0x0100 | params->inputDivider;
        }
        else if (params->clockSource == Timer_Source_SMCLK) {
            obj->controlRegInit = 0x0200 | params->inputDivider;
        }
        else if (params->clockSource == Timer_Source_EXTERNAL) {
            obj->controlRegInit = 0x0000 | params->inputDivider;
        }
        else if (params->clockSource == Timer_Source_EXTERNAL_INVERTED) {
            obj->controlRegInit = 0x0300 | params->inputDivider;
        }
        else {
            return (NO_HWI_OBJ);
        }
    
        obj->runMode = params->runMode;
        obj->startMode = params->startMode;
        obj->period = params->period;
        obj->periodType = params->periodType;
        obj->arg = params->arg;
        obj->intNum = Timer_module->device[obj->id].intNum;
        obj->tickFxn = tickFxn;
        obj->prevThreshold = 0;
        obj->savedCurrCount = 0;
        obj->rollovers = 0;
        obj->synchronous = params->synchronous;
    
        if (params->extFreq.lo == 0) {
            if (params->clockSource == Timer_Source_ACLK) {
                obj->frequency.lo = ClockFreqs_ACLK;
            }
            else if (params->clockSource == Timer_Source_SMCLK) {
                obj->frequency.lo = ClockFreqs_SMCLK;
            }
        }
        else {
            obj->frequency.lo = params->extFreq.lo;
        }
        obj->frequency.hi = params->extFreq.hi;
    
        obj->inputDivider = params->inputDivider;
        obj->inputDividerExp = params->inputDividerExp;
    
        if (obj->tickFxn) {
            if (params->hwiParams) {
                Hwi_Params_copy(&hwiParams, (params->hwiParams));
            }
            else {
                Hwi_Params_init(&hwiParams);
            }
    
            hwiParams.arg = (UArg)obj->id;
    
            if (obj->runMode == Timer_RunMode_CONTINUOUS) {
                if (params->nesting == TRUE) {
                    obj->hwi = Hwi_create(obj->intNum, Timer_periodicNestStub,
                        &hwiParams, eb);
                }
                else {
                    obj->hwi = Hwi_create(obj->intNum, Timer_periodicStub,
                        &hwiParams, eb);
                }
            }
            else {
                if (params->nesting == TRUE) {
                    obj->hwi = Hwi_create(obj->intNum, Timer_oneShotNestStub,
                        &hwiParams, eb);
                }
                else {
                    obj->hwi = Hwi_create(obj->intNum, Timer_oneShotStub,
                        &hwiParams, eb);
                }
            }
    
            if (obj->hwi == NULL) {
                return (NO_HWI_OBJ);
            }
        }
        else {
            obj->hwi = NULL;
        }
    
        Timer_module->handles[obj->id] = obj;
    
        Timer_initDevice(obj);
    
        if (obj->periodType == Timer_PeriodType_MICROSECS) {
            if (!Timer_setPeriodMicroSecs(obj, obj->period)) {
                Error_raise(eb, Timer_E_cannotSupport, obj->period, 0);
                Hwi_restore(key);
                return (BAD_PERIOD);
            }
        }
    
        status = Timer_postInit(obj, eb);
    
        if (status) {
            return (status);
        }
    
        if (obj->startMode == Timer_StartMode_AUTO) {
            Timer_start(obj);
        }
    
        return (0);
    }
    
    /*
     *  ======== Timer_reconfig ========
     *
     * 1. Init obj using params
     * 2. Timer_init()
     * 3. Configure timer (wrt emulation, frequency, etc.)
     * 4. Set period
     * 5. Timer_start()
     *
     */
    Void Timer_reconfig (Timer_Object *obj, Timer_FuncPtr tickFxn, const
        Timer_Params *params, Error_Block *eb)
    {
        obj->controlRegInit = params->controlRegInit | params->inputDivider;
        obj->runMode = params->runMode;
        obj->startMode = params->startMode;
        obj->periodType = params->periodType;
        obj->prevThreshold = params->prevThreshold;
        obj->rollovers = 0;
        obj->savedCurrCount = 0;
        obj->synchronous = params->synchronous;
        obj->inputDividerExp = params->inputDividerExp;
        if (obj->periodType == Timer_PeriodType_MICROSECS) {
            if (!Timer_setPeriodMicroSecs(obj, params->period)) {
                Error_raise(eb, Timer_E_cannotSupport, params->period, 0);
            }
        }
        else {
            obj->period = params->period;
        }
    
        obj->arg = params->arg;
        obj->tickFxn = tickFxn;
    
        if (params->extFreq.lo) {                   /* (extFreq.hi is ignored) */
            obj->frequency.lo = params->extFreq.lo;
        }
    
        Timer_postInit(obj, eb);
    
        if (obj->startMode == Timer_StartMode_AUTO) {
            Timer_start(obj);
        }
    }
    
    /*
     *  ======== Timer_Instance_finalize ========
     */
    Void Timer_Instance_finalize(Timer_Object *obj, Int status)
    {
        UInt key;
    
        /* note: fall through in switch below is intentional */
        switch (status) {
            /* Timer_delete() */
            case TIMER_DELETED:
    
            /* setPeriodMicroSecs failed */
            case BAD_PERIOD:
                Timer_initDevice(obj);
                if (obj->hwi) {
                    Hwi_delete(&obj->hwi);
                }
    
            /* Hwi create failed */
            case NO_HWI_OBJ:
    
            /* timer not available */
            case NO_TIMER_AVAIL:
    
            /* invalid timer id */
            case BAD_TIMER_ID:
    
            default:
                break;
        }
    
        key = Hwi_disable();
        Timer_module->availMask |= (0x1 << obj->id);
        Timer_module->handles[obj->id] = NULL;
        Hwi_restore(key);
    }
    
    /*
     *  ======== Timer_start ========
     *
     * 1. Hwi_disable()
     * 2. Clear the counter
     * 3. Clear timer interrupt flag
     * 4. Set next compare threshold (per configured period)
     * 5. Enable timer interrupt
     * 6. Start timer
     * 7. Hwi_restore()
     *
     */
    Void Timer_start(Timer_Object *obj)
    {
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
        UInt key;
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        key = Hwi_disable();
    
        /* reset timer counts */
        timer->control |= TIMER_CONTROL_CLEAR;
    
        /* clear timer interrupt flag */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_PENDING;
    
        /* zero previous threshold */
        obj->prevThreshold = 0;
    
        /* set compare threshold for next interrupt */
        timer->cc_compare_0 = obj->period;
    
        /* enable capture/compare 0 interrupts */
        timer->cctl_0 |= TIMER_COMPARE_INTR_ENABLE;
    
        /* start timer */
        timer->control |= TIMER_CONTROL_START;
    
        Hwi_restore(key);
    }
    
    /*
     *  ======== Timer_stop ========
     *
     * 1. Stop timer
     * 2. Disable timer interrupt
     *
     */
    Void Timer_stop(Timer_Object *obj)
    {
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        /* stop timer */
        timer->control = obj->controlRegInit | obj->inputDivider;
    
        /* disable capture/compare 0 interrupts */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_ENABLE;
    
        /* clear timer interrupt flag */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_PENDING;
    }
    
    /*
     *  ======== Timer_setPeriod ========
     *
     * 1. Stop timer
     * 2. Set period value in timer obj
     *
     */
    Void Timer_setPeriod(Timer_Object *obj, UInt32 period)
    {
        Timer_stop(obj);
        obj->period = period;
    }
    
    /*
     *  ======== Timer_setPeriodMicroSecs ========
     *
     * 1. Stop timer
     * 2. Compute counts
     * 3. Set new period value in timer obj
     *
     */
    Bool Timer_setPeriodMicroSecs(Timer_Object *obj, UInt32 period)
    {
        Types_FreqHz freqHz;
        UInt32 counts;
        UInt32 freqKHz;
    
        Timer_stop(obj);
    
        Timer_getFreq(obj, &freqHz);
        freqKHz = freqHz.lo / 1000;
    
        if (Timer_checkOverflow(freqKHz, period/1000)) {
            return (FALSE);
        }
        else {
            counts = (freqKHz * period) / 1000;
            obj->period = counts;
            obj->periodType = Timer_PeriodType_COUNTS;
            return(TRUE);
        }
    }
    
    /*
     *  ======== Timer_trigger ========
     *
     *  1. stop timer
     *  2. write the period with insts
     *  3. start the timer.
     *
     */
    Void Timer_trigger(Timer_Object *obj, UInt32 insts)
    {
        UInt key;
    
        /* follow proper procedure for dynamic period change */
        key = Hwi_disable();
    
        /* Force SMCLK for sweep timer */
        obj->controlRegInit &= ~0x0100;     /* clear ACLK bit */
        obj->controlRegInit |= 0x0200;      /* enable SMCLK */
    
        Timer_stop(obj);
    
        Timer_setPeriod(obj, insts);
        Timer_start(obj);
        Hwi_restore(key);
    }
    
    /*
     *  ======== Timer_getPeriod ========
     */
    UInt32 Timer_getPeriod(Timer_Object *obj)
    {
        return(obj->period);
    }
    
    /*
     *  ======== Timer_getCount ========
     */
    UInt32 Timer_getCount(Timer_Object *obj)
    {
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
        UInt first;
        UInt second;
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        /* if timer's source clock is synchronous to CPU: only read counts once */
        if (obj->synchronous) {
            first = timer->count;
        }
    
        /* else, must do multiple reads to avoid possible spurious values */
        else {
            /* read twice, expecting equal values, or within read latency */
            do {
                first = timer->count;
                second = timer->count;
            } while ((first != second) && ((second - first) > READ_LATENCY));
        }
    
        return (((UInt32) first) & 0xffff);
    }
    
    /*
     *  ======== Timer_oneShotStub ========
     */
    Void Timer_oneShotStub(UArg arg)
    {
        Timer_Object *obj;
        obj = Timer_module->handles[(UInt)arg];
    
        /* stop the timer (and disable this interrupt source) */
        Timer_stop(obj);
    
        /* call the tick function */
        obj->tickFxn(obj->arg);
    }
    
    /*
     *  ======== Timer_oneShotNestStub ========
     */
    Void Timer_oneShotNestStub(UArg arg)
    {
        Timer_Object *obj;
        obj = Timer_module->handles[(UInt)arg];
    
        /* stop the timer (and disable this interrupt source) */
        Timer_stop(obj);
    
        /* enable interrupts to allow nesting */
        Hwi_enable();
    
        /* call the tick function */
        obj->tickFxn(obj->arg);
    
        /* disable interrupts as unwind the ISR */
        Hwi_disable();
    }
    
    /*
     *  ======== Timer_periodicStub ========
     */
    Void Timer_periodicStub(UArg arg)
    {
        Timer_Object *obj;
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
    
        obj = Timer_module->handles[(UInt)arg];
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        /* clear timer interrupt flag */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_PENDING;
    
        /* for DYNAMIC, mode latch prevThreshold and detect rollovers */
        if (obj->runMode == Timer_RunMode_DYNAMIC) {
            /*
             * If the current threshold is less than the prevThreshold
             * then a rollover has occurred.
             *
             * If the current threshold is equal to prevThreshold then the timer
             * count wrapped around and generated a new interrupt; increment
             * the rollover count to resume ticking.
             */
            if (obj->prevThreshold >= timer->cc_compare_0) {
                obj->rollovers += 1;
            }
    
            /* save previous threshold value */
            obj->prevThreshold = timer->cc_compare_0;
        }
        else {
            /* save previous threshold value */
            obj->prevThreshold = timer->cc_compare_0;
            obj->savedCurrCount = timer->cc_compare_0;
    
            /* set next interrupt threshold; interrupt now if set too late */
            Timer_setNextTick(obj, 1);
        }
    
        /* call the tick function */
        obj->tickFxn(obj->arg);
    }
    
    /*
     *  ======== Timer_periodicNestStub ========
     */
    Void Timer_periodicNestStub(UArg arg)
    {
        Timer_Object *obj;
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
    
        obj = Timer_module->handles[(UInt)arg];
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        /* clear timer interrupt flag */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_PENDING;
    
        /* for DYNAMIC, mode latch prevThreshold and detect rollovers */
        if (obj->runMode == Timer_RunMode_DYNAMIC) {
            /*
             * if the current threshold is less than the prevThreshold
             * then a rollover has occurred.
             */
            if (obj->prevThreshold > timer->cc_compare_0) {
                obj->rollovers += 1;
            }
    
            /* save previous threshold value */
            obj->prevThreshold = timer->cc_compare_0;
        }
        else {
            /* save previous threshold value */
            obj->prevThreshold = timer->cc_compare_0;
            obj->savedCurrCount = timer->cc_compare_0;
    
            /* set next interrupt threshold; interrupt now if set too late */
            Timer_setNextTick(obj, 1);
        }
    
        /* allow nesting of other interrupts ... */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_ENABLE;
        Hwi_enable();
    
        /* call the tick function */
        obj->tickFxn(obj->arg);
    
        /* disable interrupts as unwind the ISR */
        Hwi_disable();
        timer->cctl_0 |= TIMER_COMPARE_INTR_ENABLE;
    }
    
    /*
     *  ======== Timer_getExpiredCounts ========
     *
     *  This API is used by the TimestampProvider as part of retrieving a timestamp
     *  using a timer and a tick counter. It returns the expired counts since the
     *  last serviced timer interrupt.
     *
     *  This API must be called with interrupts disabled; the TimestampProvider
     *  must disable interrupts while retrieving the tick count and calling this
     *  API.
     *
     *  The TimestampProvider uses a 32-bit timer and 32-bit tick count to track
     *  the timestamp. The tick count either comes from the Clock module or is
     *  stored in the TimestampProvider's module state and incremented by an ISR
     *  when the timer expires.
     *
     *  For MSP432 we have 16-bit timers, and use a timer compare feature to
     *  trigger an interrupt upon a specific threshold count being reached.  The
     *  timer counts can rollover (going thru zero), on the way to reaching the
     *  next threshold.  We need to  accommodate this rollover as part of
     *  determining expired counts.
     *
     *  We also need to handle the case where there is a large period value used
     *  for the timer, and the timer is ticking at a fast rate (e.g., the CPU
     *  rate, via an SMCLK selection).  For this case, it is possible that
     *  interrupts are disabled before the timer reaches threshold, and then the
     *  timer reaches the threshold count and asserts an interrupt, and then
     *  continues to count upwards before it is read in this routine.  If the
     *  timer rolled past zero, then we need to know that there is an interrupt
     *  pending, otherwise we'd report a low count, versus the period plus
     *  that low count.
     *
     *  To be sure to catch the interrupt, we sample the interrupt flag, read
     *  the count, and then sample the interrupt flag again:
     *
     *      intrFlag1
     *      count
     *      intrFlag2
     *
     *  If intrFlag1 is set, then we know we've reached the period count, and
     *  need to add it to the reported counts.  If intrFlag2 is set, but
     *  intrFlag1 wasn't, we know the timer just reached threshold, and simply
     *  report the period count.
     *
     *  If neither interrupt flag is set, we can then compute the expired counts by
     *  comparing the count to the previous interrupt threshold (saved in the
     *  timer object).  If the current count is greater than or equal to the
     *  previous threshold value, then we know there has been no counter rollover,
     *  and the expired counts is simply:
     *
     *      result = count - prevThresh
     *
     *  If the current count is less than the previous threshold, then we know a
     *  counter rollover has occurred since the last ISR.  In this case, the
     *  expired counts has to include those between the previous threshold and
     *  zero, plus any counts after rolling past zero:
     *
     *      result = (0 - prevTresh) + count
     *
     *  Similar logic to compare the current count to previous threshold can
     *  be used for the case where we know intrFlag1 has been set, and we
     *  need to figure the counts to be added to the period counts.
     *
     */
    UInt32 Timer_getExpiredCounts(Timer_Object *obj)
    {
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
        UInt32 result32;
        UInt32 count32;
        UInt32 thresh32;
        UInt32 period32;
        UInt32 prev32;
        Bool intrFlag1;
        Bool intrFlag2;
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        intrFlag1 = timer->cctl_0 & TIMER_COMPARE_INTR_PENDING;
        count32 = Timer_getCount(obj) & 0xffff;
        intrFlag2 = timer->cctl_0 & TIMER_COMPARE_INTR_PENDING;
        prev32 = obj->prevThreshold & 0xffff;
    
        /* interrupt pending before read count? */
        if (intrFlag1) {
            thresh32 = timer->cc_compare_0 & 0xffff;  /* threshold for interrupt */
            period32 = Timer_getPeriod(obj) & 0xffff; /* period count */
    
            /* threshold reached; no wrap thru zero yet */
            if (count32 >= thresh32) {
                result32 = (count32 - thresh32) + period32;
            }
            /* threshold reached; count has wrapped thru zero */
            else {
                result32 = (0x10000 - thresh32) + count32 + period32;
            }
        }
    
        /* new interrupt now pending, when wasn't before read the count */
        else if (intrFlag2) {
            result32 = Timer_getPeriod(obj) & 0xffff; /* return period count */
        }
    
        /* interrupt threshold not reached; check if wrapped thru zero */
        else if (count32 >= prev32) {
            result32 = count32 - prev32;
        }
    
        /* interrupt threshold not reached; count has wrapped thru zero */
        else {
            result32 = (0x10000 - prev32) + count32;
        }
    
        return (result32);
    }
    
    /*
     *  ======== Timer_getExpiredTicks ========
     */
    UInt32 Timer_getExpiredTicks(Timer_Object *obj, UInt32 tickPeriod)
    {
        UInt32 ticks;
    
        ticks = Timer_getExpiredCounts(obj) / tickPeriod;
    
        return (ticks);
    }
    
    /*
     *  ======== Timer_getCurrentTick ========
     *  Uses 48 bits of precision.
     *  at 32.768 KHz, that's 8,589,934,592 seconds,
     *  or 272 years before tick would be miscalculated
     */
    UInt32 Timer_getCurrentTick(Timer_Object *obj, Bool saveFlag)
    {
        UInt32 rollovers;
        UInt currCount;
        UInt32 tick;
        UInt32 s1;
        UInt r;
    
        currCount = Timer_getCount(obj);
    
        rollovers = obj->rollovers;
    
        if (currCount < obj->prevThreshold) {
            rollovers += 1;
        }
    
        s1 = rollovers / obj->period;                    /* upper 32 of 48 bits */
        r = rollovers - s1 * obj->period;        /* remainder of upper division */
        tick = (((UInt32)r << 16) + currCount) / obj->period;  /* lower 16-bits */
        tick = ((UInt32)(s1 & 0xFFFF) << 16) + (tick & 0xFFFF);
    
        /* save for later use by Timer_setNextTick() */
        if (saveFlag != 0) {
            obj->savedCurrCount = tick * obj->period;
        }
    
        return (tick);
    }
    
    /*
     *  ======== Timer_getFreq ========
     */
    Void Timer_getFreq(Timer_Object *obj, Types_FreqHz *freq)
    {
        UInt divider;
    
        switch(obj->controlRegInit & ID_MASK) {
            case Timer_ID_1:
                divider = 1;
                break;
    
            case Timer_ID_2:
                divider = 2;
                break;
    
            case Timer_ID_4:
                divider = 4;
                break;
    
            default:
                divider = 8;
                break;
        }
    
        divider *= (obj->inputDividerExp + 1);
    
        freq->lo = obj->frequency.lo / divider;
        freq->hi = 0;
    }
    
    /*
     *  ======== Timer_getFunc ========
     */
    Timer_FuncPtr Timer_getFunc(Timer_Object *obj, UArg *arg)
    {
        *arg = obj->arg;
        return (obj->tickFxn);
    }
    
    /*
     *  ======== Timer_setFunc ========
     */
    Void Timer_setFunc(Timer_Object *obj, Timer_FuncPtr fxn, UArg arg)
    {
        obj->tickFxn = fxn;
        obj->arg = arg;
    }
    
    /*
     *  ======== Timer_checkOverflow ========
     */
    Bool Timer_checkOverflow(UInt32 a, UInt32 b)
    {
        return ((b > 0) && (a > Timer_MAX_PERIOD/b));
    }
    
    /* ======== Timer_initDevice ========
     *
     * 1. Stop timer (set control registers back to default value)
     * 2. Disable timer interrupt
     * 3. Clear any pending interrupt
     * 4. Clear counters
     *
     */
    Void Timer_initDevice(Timer_Object *obj)
    {
        ti_catalog_msp432_peripherals_timers_TimerRegs *timer;
        UInt key;
    
        timer = (ti_catalog_msp432_peripherals_timers_TimerRegs *)
            Timer_module->device[obj->id].baseAddr;
    
        key = Hwi_disable();
    
        /* stop timer; set default control register */
        timer->control = MC | obj->controlRegInit;
        timer->expansion = obj->inputDividerExp;
    
        /* clear timer interrupt flag */
        timer->cctl_0 &= ~TIMER_COMPARE_INTR_PENDING;
    
        /* reset timer counts */
        timer->control |= TIMER_CONTROL_CLEAR;
    
        /* freeze the timer when the CPU is halted */
        REG(SYS_PERI_HALTCTL_REG) |= 1 << obj->id;
    
        Hwi_restore(key);
    }
    
    /*
     *  ======== Timer_postInit ========
     */
    Int Timer_postInit (Timer_Object *obj, Error_Block *eb)
    {
        UInt key;
    
        key = Hwi_disable();
    
        Timer_initDevice(obj);
    
        Timer_setPeriod(obj, obj->period);
    
        Hwi_restore(key);
    
        return (0);
    }
    

    If anyone has a pointer on how to re-build TI-RTOS/Energia so I could decrease the number of timers available to TI-RTOS, I would appreciate a note.

    Thanks!

    Rob

     

  • Oops! You should comment out the Interrupt_enableSleepOnIsrExit(); in ta_up.c.

    Rob
  • Another thing I note on the original program:  If I raise the priority to anything lower than 32,  like this;

       Hwi_setPriority(INT_ADC14, 31);

    I get stuck in Hwi.c

    Void Hwi_excHandler(UInt *excStack, UInt lr)
    {
        Hwi_module->excActive[0] = TRUE;
    
        /* spin here if no exception handler is plugged */
        while (Hwi_excHandlerFunc == NULL) {
    	;
        }
    
        Hwi_excHandlerFunc(excStack, lr);
    }
    

    in the spin here if no exception is plugged location.

    Rob

  • Hi All,

    I haven't really figured out why, but at least at the moment this is working.  It seems the priority of the interrupts was one thing that helped bring it into this state.  I'm going to mark this solved for now.  Here is the code:

    extern "C"{
    #include <copy2_adc14.h>
    };
    
    // the setup routine runs once when you press reset:
    void setup() {
      Serial.begin(115200);
      adc14_();
    
      startSampling();
    }
    
    // the loop routine runs over and over again forever:
    void loop() {
        static int i=0;
        //delay(500);
        Serial.print(i++);
        Serial.print(":  ");
        Serial.print(TA3R);
        Serial.print("  ");
        Serial.println("Hello from Copy (2) of ADC14_!");
    }
    

    and the .c file:

    /*
     * -------------------------------------------
     *    MSP432 DriverLib - v4_00_00_11
     * -------------------------------------------
     *
     * --COPYRIGHT--,BSD,BSD
     * Copyright (c) 2017, 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.
     * --/COPYRIGHT--*/
     /* MSP432 ADC14 - Multiple Channel Sample without Repeat
     *
     * Description: In this code example, the feature of being able to scan multiple
     * ADC channels is demonstrated by the user a the DriverLib APIs.  Conversion
     * memory registers ADC_MEM0 - ADC_MEM3 are configured to read conversion
     * results from A6, A12, A10, A8 respectively. Conversion is enabled and then sampling is
     * toggled using a software toggle. Repeat mode is not enabled and sampling only
     * occurs once (and it is expected that the user pauses the debugger to observe
     * the results). Once the final sample has been taken, the interrupt for
     * ADC_MEM3 is triggered and the result is stored in the resultsBuffer buffer.
     *
     *                MSP432P401
     *             ------------------
     *         /|\|                  |
     *          | |                  |
     *          --|RST         P4.7  |<--- A6 (Analog Input, Measured, Real)
     *            |            P4.1  |<--- A12 (Analog Input, Measured, Imaginary)
     *            |            P4.3  |<--- A10 (Analog Input, Reference Real)
     *            |            P4.5  |<--- A8 (Analog Input, Reference Imaginary)
     *            |                  |
     *            |                  |
     *
     *            4.1, 4.3, 4.5, 4.7 are the eventual pins needed.
     *
     * Author: Timothy Logan
     * This was modified by Rob Frohne to do multiple ADC at 8 kHz sample rate.
     ******************************************************************************/
    #include <copy2_adc14.h>
    #define SAMPLE_LENGTH 128
    
    uint16_t refRe[SAMPLE_LENGTH];
    uint16_t refIm[SAMPLE_LENGTH];
    uint16_t measRe[SAMPLE_LENGTH];
    uint16_t measIm[SAMPLE_LENGTH];
    extern volatile bool doneADC;
    bool sendMeasurement = false;
    int numberFrequenciestoMeasure, frequencyIndex;
    float  refSum, measSum;
    volatile bool doneADC = false;
    
    void ADC14_IRQHandler(void);
    
    int adc14_(void)
    {
    
        /* Halting WDT  */
        WDT_A_holdTimer();
    
        // Register interrupt
        Hwi_Params params;
        Hwi_Params_init(&params);
        Hwi_create(INT_ADC14, ADC14_IRQHandler, &params, 0);
        Hwi_setPriority(INT_ADC14, 60);
    
        //Interrupt_enableSleepOnIsrExit();
        resPos = 0;
        // Set to Vcore1
    /*
        PCM_setCoreVoltageLevel(PCM_VCORE1);
    
        // Set to use DCDC
        //PCM_setPowerState(PCM_AM_DCDC_VCORE1);
    
        // Initializes Clock System
          These commented out because we need the Energia clock setup.  The
         *  data structures for the timer are adjusted accordingly.  The time
         *  between conversions may be four times as much as we had with these
         *  parameters below, but this seems like the easiest way to make everything
         *  play together for now.
        //FlashCtl_setWaitState( FLASH_BANK0, 2);
        //FlashCtl_setWaitState( FLASH_BANK1, 2);
        PCM_setPowerState( PCM_AM_DCDC_VCORE1 );
        CS_setDCOCenteredFrequency( CS_DCO_FREQUENCY_24 );
        //CS_setDCOFrequency(24000000);
        CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );;
        CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_2 );
    */
    
    
        /* Initializing ADC (MCLK/1/1) */
        ADC14_enableModule();
        ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
                             0);
    
        // Configuring debugging pins as output for debugging...
        GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5);
        GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
    
        //Configuring GPIOs for Analog In
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4,
            GPIO_PIN1 | GPIO_PIN3 | GPIO_PIN5 | GPIO_PIN7, GPIO_TERTIARY_MODULE_FUNCTION);
    
        // Configuring ADC Memory (ADC_MEM0 - ADC_MEM3 (A6, A12, A10, A8)  with no repeat)
        // with internal 2.5v reference
        ADC14_configureMultiSequenceMode(ADC_MEM0, ADC_MEM3, false); // No repeat mode.
        ADC14_configureConversionMemory(ADC_MEM0,
                                            ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                            ADC_INPUT_A6, ADC_NONDIFFERENTIAL_INPUTS);
        ADC14_configureConversionMemory(ADC_MEM1,
                                            ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                            ADC_INPUT_A12, ADC_NONDIFFERENTIAL_INPUTS);
        ADC14_configureConversionMemory(ADC_MEM2,
                                            ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                            ADC_INPUT_A10, ADC_NONDIFFERENTIAL_INPUTS);
        ADC14_configureConversionMemory(ADC_MEM3,
                                            ADC_VREFPOS_INTBUF_VREFNEG_VSS,
                                            ADC_INPUT_A8, ADC_NONDIFFERENTIAL_INPUTS);
    
        /* Configuring Timer_A*/
        Timer_A_configureUpMode(TIMER_A1_BASE, &upModeConfig);
    
        /* Configuring TIMER_A3 in CCR1 */
        Timer_A_initCompare(TIMER_A1_BASE, &compareConfig);
    
        /* Configuring the sample trigger to be sourced from TIMER_A3  and setting it
         * to automatic iteration after it is triggered*/
        ADC14_setSampleHoldTrigger(ADC_TRIGGER_SOURCE3, false);
    
        /* Setting up the sample timer to automatically step through the sequence
         * convert.
         */
        ADC14_enableSampleTimer(ADC_AUTOMATIC_ITERATION);
    
        /* Enabling the interrupt when a conversion on channel 3 is complete*/
        ADC14_enableInterrupt(ADC_INT3);
        //ADC14_enableConversion(); // Not needed because we enable it in .ino.
    
        /* Enabling Interrupts */
        Interrupt_enableInterrupt(INT_ADC14);
        Interrupt_enableMaster();
    
        /* Starting the Timer */
        Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);
        //Hwi_enable();
    
        return 1;
    }
    
    
    void ADC14_IRQHandler(void)
    {
        uint64_t status;
        static int i = 0;
        //GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
        status = ADC14_getEnabledInterruptStatus();
        ADC14_clearInterruptFlag(status);
        //GPIO_toggleOutputOnPin(GPIO_PORT_P5, GPIO_PIN5);
        ADC14_disableConversion();
    
        if(status & ADC_INT3)
        {
            //ADC14_disableConversion();
            doneADC = false;
            ADC14_getMultiSequenceResult(resultsBuffer);
            measRe[i] = resultsBuffer[0];
            measIm[i] = resultsBuffer[1];
            refRe[i] = resultsBuffer[2];
            refIm[i] = resultsBuffer[3];
            //i=(i+1)%SAMPLE_LENGTH;
            GPIO_toggleOutputOnPin(GPIO_PORT_P5, GPIO_PIN5);
            if (i!=SAMPLE_LENGTH)
            {
                i++;
                //ADC14_enableConversion();
            }
            else
            {
                i=0;
                doneADC = true;
                //ADC14_enableConversion();
            }
        }
        ADC14_enableConversion();
    }
    
    
    void startSampling(void)
    {
        //Timer_A_initCompare(TIMER_A1_BASE, &compareConfig);
        ADC14_enableConversion();  // It is a mystery why I need to do this
        // instead of just calling ADC14_enableConversion()
        // from the .ino file!
    }

    and the header:

        /*
         * adc14_.h
         *
         *  Created on: May 12, 2017
         *      Author: frohro
         */
        
        #ifndef COPY2_ADC14_H_
        #define COPY2_ADC14_H_
        
        /* DriverLib Includes */
        #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
        #include <ti/sysbios/family/arm/m3/Hwi.h>
        
        /* Standard Includes */
        #include <stdint.h>
        
        #include <stdbool.h>
        #define SMCLK_FREQ 12000000
        #define SAMPLE_FREQ 8000
        //Timer_A Continuous Mode Configuration Parameter
        const Timer_A_UpModeConfig upModeConfig = // This DOES work
        {
                TIMER_A_CLOCKSOURCE_SMCLK,           // SM Clock Source
                TIMER_A_CLOCKSOURCE_DIVIDER_1,       // SMCLK/1 = 24MHz
                (SMCLK_FREQ/SAMPLE_FREQ),
                TIMER_A_TAIE_INTERRUPT_DISABLE,      // Disable Timer ISR
                TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE, // Disable CCR0
                TIMER_A_DO_CLEAR                     // Clear Counter
        };
        
        /* Timer_A Compare Configuration Parameter */
        const Timer_A_CompareModeConfig compareConfig =
        {
                TIMER_A_CAPTURECOMPARE_REGISTER_1,          // Use CCR1
                TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,   // Disable CCR interrupt
                TIMER_A_OUTPUTMODE_SET_RESET,               // Toggle output but
                (SMCLK_FREQ/SAMPLE_FREQ)                    // Should be 8 kHz sample rate
        };
        
        /* Statics */
        static volatile uint_fast16_t resultsBuffer[UINT8_MAX];
        static volatile uint8_t resPos;
        
        int adc14_(void);
        void ADC14_IRQHandler(void);
        void startSampling(void);
        
        
        
        
        #endif /* COPY2_ADC14_H_ */

    This is all uncleaned up, but it seems to interrupt at 8 kHz which is wonderful!

    Thanks for all the assistance!

    Rob

  • Rob,

    Thanks for letting us know. I just barely had a chance to actually read these from the weekend. I was going to mention that I believe part of the problem was coming from Energia. Energia itself sets multiple tasks at the same priority which might have been part of the problem. I see that you set the priority of the Hwi in your new source code, which in my eyes could be the key to your problem now being solved. Just a guess without actually diving into debugging this.

**Attention** This is a public forum