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.

Compiler/MSP432P401R: Problem with MultiChannel ADC

Part Number: MSP432P401R

Tool/software: TI C/C++ Compiler

I am trying to read in 2 signals through the ADC pins. Whenever I run the code, only the first ADC pin value is stored. During debugging, I found out that the registers ADC14MEM0 and ADC14MEM1 change values but the change is only reflected in the variable that stores the value of ADC14MEM0.

Also I dont know if this is useful or not but the voltage values being read in are from a pair of analog proximity sensors that are powered with 3.3V from the Microcontroller.

Below is my code setup;

/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

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

#include <string.h>

static uint16_t resultsBuffer[2];

int main(void)
{
    /* Halting WDT  */
    MAP_WDT_A_holdTimer();
    MAP_Interrupt_enableSleepOnIsrExit();

    /* Zero-filling buffer */
    memset(resultsBuffer, 0x00, 2);

    //![Simple REF Example]
    /* Setting reference voltage to 2.5  and enabling reference */
   // MAP_REF_A_setReferenceVoltage(REF_A_VREF2_5V);
    MAP_REF_A_enableReferenceVoltage();
    //![Simple REF Example]

    /* Initializing ADC (MCLK/1/1) */
    MAP_ADC14_enableModule();
    MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
            0);

    /* Configuring GPIOs for Analog In */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,
            GPIO_PIN5 | GPIO_PIN4, GPIO_TERTIARY_MODULE_FUNCTION);



    /* Configuring ADC Memory (ADC_MEM0 - ADC_MEM7 (A0 - A7)  with no repeat)
     * with internal 2.5v reference */
    MAP_ADC14_configureMultiSequenceMode(ADC_MEM0, ADC_MEM1, true);
    MAP_ADC14_configureConversionMemory(ADC_MEM0,
            ADC_VREFPOS_AVCC_VREFNEG_VSS,
            ADC_INPUT_A0, false);
    MAP_ADC14_configureConversionMemory(ADC_MEM1,
            ADC_VREFPOS_AVCC_VREFNEG_VSS,
            ADC_INPUT_A1, false);


    /* Enabling the interrupt when a conversion on channel 7 (end of sequence)
     *  is complete and enabling conversions */
    MAP_ADC14_enableInterrupt(ADC_INT1);

    /* Enabling Interrupts */
    MAP_Interrupt_enableInterrupt(INT_ADC14);
    MAP_Interrupt_enableMaster();

    /* Setting up the sample timer to automatically step through the sequence
     * convert.
     */
    MAP_ADC14_enableSampleTimer(ADC_AUTOMATIC_ITERATION);
    //ADC14_setSampleHoldTime(ADC_PULSE_WIDTH_64, ADC_PULSE_WIDTH_64);

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

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

/* This interrupt is fired whenever a conversion is completed and placed in
 * ADC_MEM7. This signals the end of conversion and the results array is
 * grabbed and placed in resultsBuffer */
void ADC14_IRQHandler(void)
{
    uint64_t status;

    status = MAP_ADC14_getEnabledInterruptStatus();
    MAP_ADC14_clearInterruptFlag(status);

    if(status & ADC_INT1)
    {
        MAP_ADC14_getMultiSequenceResult(resultsBuffer);
    }
}


  • Last I heard there was a bug in the ROM version of MAP_ADC14_getMultiSequenceResult:

    e2e.ti.com/.../2383657

    There are a couple of suggested workaround in that post.
  • Which version of the SDK are you using? You can find the latest here:

    www.ti.com/.../SIMPLELINK-MSP432-SDK

    In the change log you can see the update for the API (MSP432DVR-464):
    dev.ti.com/.../changelog.html

    Please let me know if you have the latest SDK and are still seeing an issue.

    Regards,
    Chris
  • Bruce,
    Thank you! That fixed the problem
  • I was able to get that problem solved but I ran into another problem. Whenever the code runs I noticed it never gets to the forever loop (while(1)). I set up an LED to turn on in the forever loop but it never turns on. I could only get the LED to turn on in the ADC interrupt
  • Akin,
    At the beginning of the program you use the API, MAP_Interrupt_enableSleepOnIsrExit(); This means that when the device exits the ISR it returns to sleep mode and not active, and therefor the super loop is never re-entered once the device enters sleep (lpm0).

    Chris
  • Chris,
    I removed it and still have the same problem
  • Do you know how long it takes to make the two measurements compared with how long it takes to enter, execute, and exit the ISR?

    Chris
  • static uint16_t resultsBuffer[3];
    uint16_t DirNav[2];
    
    
    int main(void)
    {
        /* Halting WDT  */
        MAP_WDT_A_holdTimer();
        MAP_Interrupt_disableSleepOnIsrExit();
    
       // MAP_Interrupt_enableSleepOnIsrExit();
    
        /* Zero-filling buffer */
        resultsBuffer[0] = 0;
        resultsBuffer[1] = 0;
        resultsBuffer[2] = 0;
    
        DirNav[0] = 0; //decides whether or not to halt
        DirNav[1] = 0;	//decides which side to turn to
    
        MAP_REF_A_enableReferenceVoltage();
    
        /* Initializing ADC (MCLK/1/1) */
        MAP_ADC14_enableModule();
        MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
                0);
    
        /* Configuring GPIOs (1.0 out), (5.5 A0) */
            MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
            MAP_GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN1);
            MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
    
    
        /* Configuring GPIOs for Analog In */
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,
                GPIO_PIN5 | GPIO_PIN4, GPIO_TERTIARY_MODULE_FUNCTION);
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4,
                GPIO_PIN7, GPIO_TERTIARY_MODULE_FUNCTION);
    
        /* Configuring ADC Memory with repeat)*/
        MAP_ADC14_configureMultiSequenceMode(ADC_MEM0, ADC_MEM6, true);
        MAP_ADC14_configureConversionMemory(ADC_MEM0,
                ADC_VREFPOS_AVCC_VREFNEG_VSS,
                ADC_INPUT_A0, false);
        MAP_ADC14_configureConversionMemory(ADC_MEM1,
                ADC_VREFPOS_AVCC_VREFNEG_VSS,
                ADC_INPUT_A1, false);
        MAP_ADC14_configureConversionMemory(ADC_MEM6,
                    ADC_VREFPOS_AVCC_VREFNEG_VSS,
                    ADC_INPUT_A6, false);
    
        MAP_ADC14_setComparatorWindowValue(ADC_COMP_WINDOW0, 5000, 5000);
        MAP_ADC14_enableComparatorWindow(ADC_MEM0, ADC_COMP_WINDOW0);
        MAP_ADC14_enableComparatorWindow(ADC_MEM1, ADC_COMP_WINDOW0);
        MAP_ADC14_enableInterrupt(ADC_HI_INT | ADC_LO_INT);
        MAP_ADC14_clearInterruptFlag(ADC_HI_INT | ADC_LO_INT);
    
        /* Enabling the interrupt when a conversion on channel 7 (end of sequence)
         *  is complete and enabling conversions */
        MAP_ADC14_enableInterrupt(ADC_INT6);
    
        /* Enabling Interrupts */
        MAP_Interrupt_enableInterrupt(INT_ADC14);
        MAP_Interrupt_enableMaster();
    
        /* Setting up the sample timer to automatically step through the sequence
         * convert.*/
        MAP_ADC14_enableSampleTimer(ADC_AUTOMATIC_ITERATION);
        //ADC14_setSampleHoldTime(ADC_PULSE_WIDTH_64, ADC_PULSE_WIDTH_64);
    
        /* Triggering the start of the sample */
        MAP_ADC14_enableConversion();
        MAP_ADC14_toggleConversionTrigger();
    
        /* Going to sleep */
        //MAP_Interrupt_disableSleepOnIsrExit();
        while (1)
        {
        	if(DirNav[0] == 0)
        		MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
        	else if(DirNav[0] == 1)
        		MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);
        	MAP_PCM_gotoLPM0();
    
        	//__no_operation();
        }
    }
    
    
    void ADC14_IRQHandler(void)
    {
        uint64_t status;
    
        status = MAP_ADC14_getEnabledInterruptStatus();
        MAP_ADC14_clearInterruptFlag(status);
        MAP_ADC14_clearInterruptFlag(ADC_HI_INT | ADC_LO_INT);
    
        if(status & ADC_HI_INT)
        {
        	DirNav[0] = 1;
        	MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN1);
            resultsBuffer[0] = MAP_ADC14_getResult(ADC_MEM0);
            resultsBuffer[1] = MAP_ADC14_getResult(ADC_MEM1);
            resultsBuffer[2] = MAP_ADC14_getResult(ADC_MEM6);
        }
    
        else {
        	DirNav[0] = 0;
        	MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN1);
        	resultsBuffer[0] = 0;
        	resultsBuffer[1] = 0;
        	resultsBuffer[2] = 0;
        }
    }

    I dont know how to determine that.

    The Code I have below sets up two leds to be triggered by the ADC Interrupt. One within the interrupt and second one in the while loop but only the one in the interrupt triggers the LED.

  • No, I dont know how to determine that.
  • You can reuse these functions:

    MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);

    and measure how long the pulse width is on P1.0.

    Also, in your code you are actually measuring 7 channels, Channel 0 through Channel 6. It might be better to change it to channels 0 through 2 and have the input 6 go to memory location 2. You can learn about the APIs here: dev.ti.com/.../group__adc14__api.html

    Regards,
    Chris
  • > MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,

    I'm pretty sure MCLK is stopped in LPM0, and SLAU356G sec 20.2.1.1 seems to suggest that a request from the ADC14 won't start it (MCLK_EN).

    Try using SMCLK or MODCLK instead.
  • You are running conversions continuously (CONSEQ=3,MSC=1). Each conversion uses SHT=0 (4 MCLKs) sample time + 16 MCLKs conversion time = 20 MCLKs total. There are 7x of them, or 140 MCLKs.

    Your ISR appears to take about 360 MCLKs, which means that by the time it finishes another conversion is complete, so the ISR is constantly running. (I'm pretty sure this is what Chris Sterzik was getting at.) You're also fetching results while the ADC is running, which can give inconsistent results in a real application.

    You might get away with using a slower ADC clock or an ADC_DIVIDER > 2.

    I suggest you instead switch to single-sequence (CONSEQ=1, i.e. MultiSequenceMode(false)) and start a new conversion each time through the while() loop in main.
  • I found the problem. I had to divide down the clock. I guess I was sampling too fast

**Attention** This is a public forum