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:
- Is there a good way to measure the speed of SMCLK?
- Is there a way to measure MCLK?
- Is there a way of finding out what is making the interrupts not able to fire? Perhaps there is another interrupt with higher priority.
- 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(¶ms); Hwi_create(INT_ADC14, ADC14_IRQHandler, ¶ms, 0); //Hwi_create(INT_TA0_N, TA0_N_IRQHandler, ¶ms, 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