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.

MSP432E401Y: Wrong samples from 12-bit adc

Part Number: MSP432E401Y

I am trying to sample ADC on the port E, pins PE0 to PE3. I am configuring ADC as shown in the TI examples for sampling on multiple channels, I am triggering every sample by processor trigger and I use the interrupt handler functions for getting the sample when in the sample sequencer. I use sample sequencer 0 (SS0) for PE3 and PE2, SS1 for PE1 and SS2 for PE0. I get reasonable values for SS1 and SS2 but it seems to be wrong for SS0. I have configure to sample one value from PE2, read it and then trigger a new value for PE3 and read it. and this is done only once. 

I saw in errata there might be wrong values for the first two samples, so I did reset in ADC before I enable the sequencers, and I disregard the first two sampled values bu I still get the same result. Is it something specific that needs to be done here?

  • Hi Gerganna,

    Please try this code, this is normal in my side:

    // Initiate ADC
    void initADC(void)
    {
        /* Enable the clock to GPIO Port E and wait for it to be ready */
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
        while(!(MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)));
    
        /* Enable the clock to GPIO Port D and wait for it to be ready */
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
        while(!(MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD)));
    
        /* Configure PD0-PD3 as ADC input channel */
        MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);
        MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
        MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
        MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
    
        /* Configure PE0-PE3 as ADC input channel */
        MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
        MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
        MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
        MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    
        /* Enable the clock to ADC-0 and wait for it to be ready */
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        while(!(MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)));
    
        /* Enable the clock to ADC-1 and wait for it to be ready */
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
        while(!(MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC1)));
    
        /* Configure Sequencer 2 to sample the analog channel : AIN0-AIN3. The
         * end of conversion and interrupt generation is set for AIN3 */
        MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH0);
        MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 1, ADC_CTL_CH1);
        MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 2, ADC_CTL_CH2);
        MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 3, ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END);
    
        /* Configure Sequencer 2 to sample the analog channel : AIN0-AIN3. The
         * end of conversion and interrupt generation is set for AIN3 */
        MAP_ADCSequenceStepConfigure(ADC1_BASE, 2, 0, ADC_CTL_CH12);
        MAP_ADCSequenceStepConfigure(ADC1_BASE, 2, 1, ADC_CTL_CH13);
        MAP_ADCSequenceStepConfigure(ADC1_BASE, 2, 2, ADC_CTL_CH14);
        MAP_ADCSequenceStepConfigure(ADC1_BASE, 2, 3, ADC_CTL_CH15 | ADC_CTL_IE | ADC_CTL_END);
    
        /* Enable sample sequence 2 with a PWM signal trigger.  Sequencer 2
         * will do a single sample when the PWM0 generates a match for the Duty
         * Cycle */
        MAP_ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PWM2, 2); // The last '2' means priority
        MAP_ADCSequenceConfigure(ADC1_BASE, 2, ADC_TRIGGER_PWM2, 2); // The last '2' means priority
    
        /* Since sample sequence 2 is now configured, it must be enabled. */
        MAP_ADCSequenceEnable(ADC0_BASE, 2);
        MAP_ADCSequenceEnable(ADC1_BASE, 2);
    
        /* Clear the interrupt status flag before enabling. This is done to make
         * sure the interrupt flag is cleared before we sample. */
        MAP_ADCIntClear(ADC0_BASE, 2);
        MAP_ADCIntEnable(ADC0_BASE, 2);
        MAP_ADCIntClear(ADC1_BASE, 2);
        MAP_ADCIntEnable(ADC1_BASE, 2);
    
        /* Enable the Interrupt generation from the ADC-0 Sequencer */
        MAP_IntEnable(INT_ADC0SS2);
        MAP_IntEnable(INT_ADC1SS2);
    }
    
    
    // ADC0 ISR
    void ADC0SS2_IRQHandler(void)
    {
        uint32_t getIntStatus;
    
        DEBUG_PP4_H();
    
        /* Get the interrupt status from the ADC */
        getIntStatus = MAP_ADCIntStatus(ADC0_BASE, 2, true);
    
        /* If the interrupt status for Sequencer-3 is set the
         * clear the status and read the data */
        if(getIntStatus == ADC_INT_SS2)
        {
            /* Clear the ADC interrupt flag. */
            MAP_ADCIntClear(ADC0_BASE, 2);
    
            /* Read ADC Value. */
            MAP_ADCSequenceDataGet(ADC0_BASE, 2, MotorStatus.currentstate.ADC0RawData);
        }
    
        DEBUG_PP4_L();
    }
    
    // ADC1 ISR
    void ADC1SS2_IRQHandler(void)
    {
        uint32_t getIntStatus;
    
        /* Get the interrupt status from the ADC */
        getIntStatus = MAP_ADCIntStatus(ADC1_BASE, 2, true);
    
        /* If the interrupt status for Sequencer-3 is set the
         * clear the status and read the data */
        if(getIntStatus == ADC_INT_SS2)
        {
            /* Clear the ADC interrupt flag. */
            MAP_ADCIntClear(ADC1_BASE, 2);
    
            /* Read ADC Value. */
            MAP_ADCSequenceDataGet(ADC1_BASE, 2, MotorStatus.currentstate.ADC1RawData);
        }
    
    }

    Thanks!

    Best Regards

    Johnson

  • Hi Johnson,

    Thank you for your reply. I have the same sequence for the adc channels I have connected. The problem appears to originate in reading the values. As I want to trigger sampling from channel AIN0, read it and afterwards trigger a sample from AIN1 in the same step of the same sequencer. It is like the two channels are using the same spot, but I want their samples to be triggered at different times and independent of each other. So in my configuration I had, similar to yours becides: 

    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END);

    And before I read a sample I run the function for trigger:

    MAP_ADCProcessorTrigger(ADC0_BASE, 0);

    This is not working apparently. I think every time I read a value in---- void ADC0SS0_IRQHandler(void) ---  I read the sample only from the channel which is firstly configured to use this sequencer. Maybe I should use another sample sequencer for the second sampling. 

  • Hi Gerganna,

    This code is trigger by PWM, thus attach the PWM code:

    // Initiate PWM
    void initPWM(void)
    {
        /* The PWM peripheral must be enabled for use. */
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
        while(!(MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_PWM0)));
    
        /* Set the PWM clock to the system clock. */
        MAP_PWMClockSet(PWM0_BASE,PWM_SYSCLK_DIV_1);
    
        /* Enable the clock to the GPIO Port F, G and K for PWM pins */
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF));
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOG));
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOK));
    
        /* Generator 1 Pins */
        MAP_GPIOPinConfigure(GPIO_PF2_M0PWM2);
        MAP_GPIOPinConfigure(GPIO_PF3_M0PWM3);
    
        /* Generator 2 Pins */
        MAP_GPIOPinConfigure(GPIO_PG0_M0PWM4);
        MAP_GPIOPinConfigure(GPIO_PG1_M0PWM5);
    
        /* Generator 3 Pins */
        MAP_GPIOPinConfigure(GPIO_PK4_M0PWM6);
        MAP_GPIOPinConfigure(GPIO_PK5_M0PWM7);
    
        MAP_GPIOPinTypePWM(GPIO_PORTF_BASE, (GPIO_PIN_2 | GPIO_PIN_3));
        MAP_GPIOPinTypePWM(GPIO_PORTG_BASE, (GPIO_PIN_0 | GPIO_PIN_1));
        MAP_GPIOPinTypePWM(GPIO_PORTK_BASE, (GPIO_PIN_4 | GPIO_PIN_5));
    
        /* Configure the PWM0 to count up/down without synchronization.
         * Note: Enabling the dead-band generator automatically couples the 2
         * outputs from the PWM block so we don't use the PWM synchronization. */
        MAP_PWMGenConfigure(PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE_UP_DOWN | PWM_OUTPUT_MODE_SYNC_GLOBAL);
        MAP_PWMGenConfigure(PWM0_BASE, PWM_GEN_2, PWM_GEN_MODE_UP_DOWN | PWM_OUTPUT_MODE_SYNC_GLOBAL);
        MAP_PWMGenConfigure(PWM0_BASE, PWM_GEN_3, PWM_GEN_MODE_UP_DOWN | PWM_OUTPUT_MODE_SYNC_GLOBAL);
    
        /* Set the PWM period to 250Hz.  To calculate the appropriate parameter
         * use the following equation: N = (1 / f) * SysClk.  Where N is the
         * function parameter, f is the desired frequency, and SysClk is the
         * system clock frequency.
         * In this case you get: (1 / 250Hz) * 16MHz = 64000 cycles.  Note that
         * the maximum period you can set is 2^16 - 1.
         * TODO: modify this calculation to use the clock frequency that you are
         * using. */
        MAP_PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, PWM_LoadValue);
        MAP_PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, PWM_LoadValue);
        MAP_PWMGenPeriodSet(PWM0_BASE, PWM_GEN_3, PWM_LoadValue);
    
        // Clear cmpA
        MAP_PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, 0);
        MAP_PWMPulseWidthSet(PWM0_BASE, PWM_OUT_4, 0);
        MAP_PWMPulseWidthSet(PWM0_BASE, PWM_OUT_6, 0);
    
        // Configure dead time
        MAP_PWMDeadBandEnable(PWM0_BASE, PWM_GEN_1, 160, 160);
        MAP_PWMDeadBandEnable(PWM0_BASE, PWM_GEN_2, 160, 160);
        MAP_PWMDeadBandEnable(PWM0_BASE, PWM_GEN_3, 160, 160);
    
        // Tirgger for ADC
        MAP_PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_2, PWM_TR_CNT_ZERO);
    
        /* Interrupt */
        MAP_IntMasterEnable();
    
        /* This timer is in up-down mode. Interrupts will occur when the counter counts up to 0. */
        MAP_PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_1, PWM_INT_CNT_ZERO);
        MAP_IntEnable(INT_PWM0_1);
        MAP_PWMIntEnable(PWM0_BASE, PWM_INT_GEN_1);
    
        /* Enable the PWM0 output signals
         *   Bit 2 (PF2) and Bit 3 (PF3)
         *   Bit 4 (PG0) and Bit 5 (PG1)
         *   Bit 6 (PK4) and Bit 7 (PK5) */
        MAP_PWMOutputState(PWM0_BASE, (  PWM_OUT_2_BIT | PWM_OUT_3_BIT |
                                         PWM_OUT_4_BIT | PWM_OUT_5_BIT |
                                         PWM_OUT_6_BIT | PWM_OUT_7_BIT ) , true);
    
        /* Enables the counter for a PWM generator block. */
        MAP_PWMGenEnable(PWM0_BASE, PWM_GEN_1);
        MAP_PWMGenEnable(PWM0_BASE, PWM_GEN_2);
        MAP_PWMGenEnable(PWM0_BASE, PWM_GEN_3);
    
        MAP_PWMSyncTimeBase(PWM0_BASE, (PWM_GEN_1_BIT | PWM_GEN_2_BIT | PWM_GEN_3_BIT));
    
        /* Update locally */
        MAP_PWMOutputUpdateMode(PWM0_BASE, ( PWM_OUT_1_BIT | PWM_OUT_2_BIT | PWM_OUT_3_BIT), PWM_OUTPUT_MODE_SYNC_GLOBAL);
    }

    After add this code, you will find you can enter ADC interrupt and gget the correct value.

    Thanks!

    Best Regards

    Johnson

  • Hi, 

    I understand but I want to make it work with a processo trigger. I do not use PWM in my application. 
    Thank you any way.

    Regards,

    Gergana

  • Hi Gergana,

    This code just as your refernece, you can change this code to match your requirement, The ADC module should normal.

    And you can also refer to MSP432E SDK example code.

    Thanks!

    Best Regards

    Johnson

  • I have one more question. If I need to sample from 3 different analog input channels and I only need to sample once from each channel and it is at different times, I can configure only one sequencer where sampling will occur. So I will have channel 0 to step 0, channel 1 to step 1, and channel 2 to step 2.

    When I trigger sampling for analog input channel 2 can I get only samples for this channel ?  Or I need to always read values for all channels that are configured to sample in the same sample sequencer?

    I want to use only ADC0 module and Sample Sequencer 0 which has buffer for 8 samples, for example.

  • Hi Gergana,

    You can read the channel value you want directly, even if you configurate ADC to sequence mode.

    There are some buffer inside ADC module, this will store all ADC capture value.

    Thanks!

    Best Regards

    Johnson

  • Thank you! 

    Regards,

    Gergana