frohro

Members
  • Content count

    3
  • Joined

  • Last visited

About frohro

  • Rank
    Noob Class

Profile Information

  • Location
    United States
  • Github
    https://github.com/frohro/DirectConversionVNA
  1. Hi All, I got no replies, but thought I should put the answer here for anyone else who finds this and needs it. It appears that setting the interrupt priority is important. Here is some working (for me) code: /* * ------------------------------------------- * 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) { // 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; /* 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_A0_BASE, &upModeConfig); /* Configuring TIMER_A3 in CCR1 */ Timer_A_initCompare(TIMER_A0_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_SOURCE1, 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_A0_BASE, TIMER_A_UP_MODE); //Hwi_enable(); return 1; } void ADC14_IRQHandler(void) { uint64_t status; static int i = 0; status = ADC14_getEnabledInterruptStatus(); ADC14_clearInterruptFlag(status); 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]; GPIO_toggleOutputOnPin(GPIO_PORT_P5, GPIO_PIN5); if (i!=SAMPLE_LENGTH) { i++; ADC14_enableConversion(); } else { i=0; doneADC = true; ADC14_enableConversion(); } } } The header and .ino are similar to the above. Rob
  2. Hi, I'm trying to do a timerA initiated multiple channel conversion with the ADC14 in an MSP432. It seems that TI-RTOS wants to use all the TimerA modules. I believe this because I see the TAxR value stop. I also made a simple timer routine to blink the LED in the TA0 ISR, and it works sometimes and not others. I notice that there doesn't seem to be any drivers for TI-RTOS for the timers, and no example code for doing a multichannel convert triggered by TimerAx. I have bare metal code for driverlib that works perfectly, but when I put it into Energia, I get no interrupts, as the timer is stopped. I can fight with TI-RTOS, and keep starting the timer in my loop(), but of course it isn't sampling at the rate I want then. I am wondering if perhaps I change the Times_NumberofTimerDevices to be one less, if I could use TimerA3. What do you all think? See for example Timer.c below: /* * 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); } And if you think this might be worth pursuing, I'd really like a pointer on how to rebuild the stuff to make this work. Thanks, Rob
  3. Hi All, I need to make ADC14 measurements in the multi mode at a sample rate of 8 kHz, but would like to use Energia's Serial and I2C functions. I have a stand alone driverlib routine that works fine, and Energia code that works fine with the Serial, and I2C, however, I am having difficulty integrating them. I noticed that the ADC14CTL0 register is changed from what my routine called in setup() did. I started reading the code in Energia/emt/src/ti/runtime/wiring/msp432/, and it appears that I may need to modify it to make this work, but before I go hacking, I want advice. Is there a good way to get Energia to leave the ADC14 to me, or is there a way to use Energia's ADC14 routines to do multi conversions at 8 kHz? I'm enclosing my code in case it is of use: 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 the C file to run the ADC14: /* * ------------------------------------------- * 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; 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 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, Rob