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.

MSP432P401R: Why Does Enabling INT_ADC14 with Input on P5.5 Prevent INT_PORT1 (Sw1 & Sw2) Interrupt From Firing?

Part Number: MSP432P401R

TI Devs,

This may be something basic I have just missed in combing over the Datasheet, Driverlib User's Guide and Tech Reference. I have a simple ADC14 example that uses a potentiometer on a breadboard feeding the input back to the MSP432 on P5.5 that is then used to set CCR1 compare value on TIMER_AO setting the PWM that controls the P2.0 red LED. Works perfectly, but I adjust +5 on the ADC result to ensure CCR1 is set to CCR0 + 1 to fully turn the LED off. To add to this example I wanted to use Switch1 and Switch2 (P1.1 and 1.4) to turn the TIMER_A0 PWM on/off either by stop/starting TIMER_A0 or by setting CCR1 to CCR0 + 1.

The problem is this. When the ADC interrupt is active (INT_ADC14) the interrupt for PORT1 (INT_PORT1) will not fire. (I added output on the P1.0 LED just to have a simple visual). If I don't enable INT_ADC14 until I'm within INT_PORT1, it fires just fine the first time and then doesn't fire after INT_ADC14 is enabled. That leads me to believe I have either overlooked some constraint on how ADC operates, or there is something funny on input with P5.5 (default pin for A0) which shows "reserved" next to the pinout in the User's Guide diagram??

The code is minimal and is included below:

#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

#include <stdint.h>
#include <stdbool.h>

#define TA0_PWMPERIOD  0x7f         /*   127  */
#define TA0_DUTYCYCLE  0x3f         /*    63  */

static volatile uint16_t adcResult;
static volatile uint16_t adcPWMPeriod;

/* TimerA0 UpMode Configuration Parameter for PWM */
Timer_A_UpModeConfig TimerA0_PWMConfig =
{
    TIMER_A_CLOCKSOURCE_ACLK,                   /* clockSource */
    TIMER_A_CLOCKSOURCE_DIVIDER_1,              /* clockSourceDivider */
    TA0_PWMPERIOD,                              /* timerPeriod */
    TIMER_A_TAIE_INTERRUPT_DISABLE,             /* timerInterruptEnable_TAIE */
    TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE,        /* captureCompareInterruptEnable_CCR0_CCIE */
    TIMER_A_DO_CLEAR                            /* timerClear */
};

/* TimerA0 PWM with CCR1 */
Timer_A_CompareModeConfig compareConfigA01 =
{
     TIMER_A_CAPTURECOMPARE_REGISTER_1,         /* compareRegister */
     TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE,  /* compareInterruptEnable */
     TIMER_A_OUTPUTMODE_TOGGLE_RESET,           /* compareOutputMode */
     TA0_DUTYCYCLE                              /* compareOutputMode */
};

/* Port mapper configuration register (See Table 13-1 Tech Reference, Pg 702)
 * Timer_A0 CCR1 mapped to take the PWM output for the RGB LED (red) and P2.4.
 */
const uint8_t port_mapping[] =
{
    PM_TA0CCR1A, PM_NONE, PM_NONE, PM_NONE, PM_NONE, PM_NONE, PM_NONE, PM_NONE
};

int main(void)
{
    /* Stop Watchdog  */
    MAP_WDT_A_holdTimer();

    /* Enabling the FPU for floating point operation */
    MAP_FPU_enableModule();
    MAP_FPU_enableLazyStacking();

    /** NOTE
     *  With adc and P5.5 as input all other interrupts disabled while INT_ADC14
     *  is enabled.
     */
    /* Configuring P1.0 as output (trend temp increasing - on / decreasing - blinking) */
   MAP_GPIO_setAsOutputPin (GPIO_PORT_P1, GPIO_PIN0);
   MAP_GPIO_setOutputLowOnPin (GPIO_PORT_P1, GPIO_PIN0);

    /* Configure P1.1 (switch_1) and P1.4 (switch2) as input with pull-up */
   MAP_GPIO_clearInterruptFlag (GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
   MAP_GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);

    /* Configure Port1 Interrupt for both Pin1 and Pin4 and enable interrupt */
   MAP_GPIO_enableInterrupt (GPIO_PORT_P1, GPIO_PIN1 | GPIO_PIN4);
   MAP_Interrupt_enableInterrupt (INT_PORT1);

    /* Initialize main clock to 3MHz */
    MAP_CS_setDCOCenteredFrequency (CS_DCO_FREQUENCY_3);

     /* Remapping TA1CCR1 output pin to P2.0 (red LED of LED2) and P2.4 PWM */
    MAP_PMAP_configurePorts ((const uint8_t *) port_mapping,
                             PMAP_P2MAP,
                             1,
                             PMAP_DISABLE_RECONFIGURATION);

    /* Set pin P2.0 as output pin */
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin (GPIO_PORT_P2,
                                                     GPIO_PIN0,
                                                     GPIO_PRIMARY_MODULE_FUNCTION);

    /* start PWM on TimerA_0 with CCR0 & CCR1 interrupts enabled */
    MAP_Timer_A_configureUpMode (TIMER_A0_BASE, &TimerA0_PWMConfig);
    MAP_Timer_A_initCompare (TIMER_A0_BASE, &compareConfigA01);

    /* Initializing ADC (MCLK/1/1) with temperature sensor routed */
    MAP_ADC14_enableModule();
    MAP_ADC14_initModule (ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
                            ADC_NOROUTE);

    /* Setting up GPIO pins as analog inputs (and references) */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin (GPIO_PORT_P5, GPIO_PIN5,
                                                    GPIO_TERTIARY_MODULE_FUNCTION);

    /*  Configuring ADC Memory (ADC_MEM0 and 3.3v reference) in repeat
     *  mode).
     */
    MAP_ADC14_configureSingleSampleMode (ADC_MEM0, true);
    MAP_ADC14_configureConversionMemory (ADC_MEM0, ADC_VREFPOS_AVCC_VREFNEG_VSS,
                                         ADC_INPUT_A0, ADC_NONDIFFERENTIAL_INPUTS);

    /* Configuring the sample/hold time for 192 (default 4) */
    // MAP_ADC14_setSampleHoldTime (ADC_PULSE_WIDTH_192,ADC_PULSE_WIDTH_192);

    /* Enabling sample timer in auto iteration mode and interrupts*/
    MAP_ADC14_enableSampleTimer (ADC_AUTOMATIC_ITERATION);
    MAP_ADC14_enableInterrupt (ADC_INT0);

    MAP_Interrupt_enableInterrupt (INT_ADC14);

    MAP_Interrupt_enableSleepOnIsrExit();

    MAP_Interrupt_enableMaster();

    /* Starting the Timer_A0 in up mode generatig PWM */
    MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);

    /* Triggering the start of the sample */
    MAP_ADC14_enableConversion();
    MAP_ADC14_toggleConversionTrigger();

    while(1)
    {
        // MAP_PCM_gotoLPM0();
        MAP_PCM_gotoLPM3();
    }
}

/** This interrupt happens whenever a conversion has been completed and placed
 *  into ADC_MEM0.
 */
void ADC14_IRQHandler(void)
{
    uint64_t status;

    status = MAP_ADC14_getEnabledInterruptStatus();
    MAP_ADC14_clearInterruptFlag (status);

    if (status & ADC_INT0)
    {
        adcResult = MAP_ADC14_getResult (ADC_MEM0);
        adcPWMPeriod = (uint_fast16_t)((float)adcResult * TA0_PWMPERIOD / 16383);

        adcPWMPeriod += 5;
        MAP_Timer_A_setCompareValue (TIMER_A0_BASE,
                                     TIMER_A_CAPTURECOMPARE_REGISTER_1, adcPWMPeriod);
                                     //v > 123 ? 128 : v);
    }

}

/*
 * Port 1 interrupt handler. This handler is called whenever switches attached
 * to P1.1 (S1) and P1.4 (S2) are pressed.
 */
void PORT1_IRQHandler(void)
{
    uint32_t status = MAP_GPIO_getEnabledInterruptStatus (GPIO_PORT_P1);
    MAP_GPIO_clearInterruptFlag (GPIO_PORT_P1, status);

    /* Handles S1 button press */
    if (status & GPIO_PIN1)
    {
#ifdef STOPTIMER
        /* start TimerA0 */
        MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);
#else
        /* set TimerA1 CCR1 value (reset to last adc value) */
        MAP_Timer_A_setCompareValue (TIMER_A0_BASE,
                                     TIMER_A_CAPTURECOMPARE_REGISTER_1,
                                     adcPWMPeriod);
        MAP_Interrupt_enableInterrupt (INT_ADC14);
#endif
        /* user P1.0 to see if the interrupt is fired */
        MAP_GPIO_setOutputLowOnPin (GPIO_PORT_P1, GPIO_PIN0);
    }
    /* Handles S2 button press */
    if (status & GPIO_PIN4)
    {
#ifdef STOPTIMER
        /* stop TimerA0 */
        MAP_Timer_A_stopTimer (TIMER_A0_BASE);
#else
        /* set TimerA1 CCR1 value (1 greater that CCR0 - PWM off) */
        MAP_Timer_A_setCompareValue (TIMER_A0_BASE,
                                     TIMER_A_CAPTURECOMPARE_REGISTER_1,
                                     TA0_PWMPERIOD + 1);
        MAP_Interrupt_disableInterrupt (INT_ADC14);
#endif
        /* user P1.0 to see if the interrupt is fired */
        MAP_GPIO_setOutputHighOnPin (GPIO_PORT_P1, GPIO_PIN0);
    }
}

Why does having INT_ADC14 enabled seem to disable all other interrupts in this example?

  • I think the reason is that the ADC IRQ takes too much time, as you calculate a float number in the IRQ. The IRQ is not finished before the next ADC interrupt happens. Then it will not enter Port IRQ, but the ADC IRQ directly. 

  • Also:

    >MAP_ADC14_initModule (ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
    ADC_NOROUTE);

    >MAP_ADC14_configureSingleSampleMode (ADC_MEM0, true);

    >MAP_ADC14_enableSampleTimer (ADC_AUTOMATIC_ITERATION);

    This runs the ADC with CONSEQ=2, MSC=1, and ADCCLK=MCLK/1, which means it is converting as fast as it can. The ISR is being triggered every 17 MCLKs, [Ref TRM (SLAU356I) Fig 22-9] and your ISR takes at least 40-50 MCLKs to run, i.e. you're converting much faster than your program can deal with.

    Consider increasing the ADC_DIVIDER_x, using DMA, and/or using a timer trigger to slow down the ADC.

  • That is the part I was missing.With the ADC value being scaled between as a floating-point, we are kinda stuck with a floating-point calculation in the ADC interrupt. Even a simple multiply by 100 would still be promoted to a floating-point calculation. Thank you for your help!

  • Hey, also Congratulations on having the Mars Helicopter using a snapdragon driving the TSM570LC43x in the little craft. Linux in space driving a TI board for flight control on Mars -- we've come a long way...

  •     MAP_ADC14_initModule (ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_4, ADC_DIVIDER_4,
                                ADC_NOROUTE);
    

    Solved All Issues. ADC_PREDIVIDER_4, ADC_DIVIDER_2 was not quite enough, but setting ADC_DIVIDER_4 did the trick.