Configure MCU to wake up from STOP2 only on specific ADC channel input

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Configure MCU to wake up from STOP2 only on specific ADC channel input

1,354 Views
akshaykul89
Contributor III

I am working on S32K144 MCU EVB and currently consuming N channels of ADC0. Scenario I am looking for is as below :

1] Keep reading all channels of ADC0. 

2] If digital value of channel 2 goes below certain threshold then move to STOP2 power mode.

3] BEFORE moving to STOP2 disable interrupts from other ADC channels and just monitor channel 2 (put a greater than HW configuration).

4] I want ADC0 to trigger an interrupt and exit STOP2 mode only if channel 2 value is greater than threshold value.

Problem is, I am properly able to read all channels of ADC0 and able to find step 2 i.e. able to move in STOP2 state. BUT as soon as MCU moves to STOP2 it comes out of it due to ADC interrupt. I tried to apply hardware comparison before moving to STOP2 state. Configured channel 2 after that. ADC0 is NOT in continuous mode and SW trigger is used.

Please shed some light on how I can only enable 2nd channel to generate interrupt  before moving to STOP2 and disable other ADC channels. This will be a great help.

7 Replies

1,063 Views
danielmartynek
NXP TechSupport
NXP TechSupport

Hi,
If you use SW triggers, only a write to SC1A[ADCH] can trigger a conversion. So, you don’t need to worry about other channels.
But you can’t initiate a new conversion while in STOP2 because the CPU is halted.
You write that you get an interrupt, what is the result of the conversion? Just to see if the HW compare function is working.
What is the state of MISCTRL0[STOP2_MONITOR] after the wakeup?

Regards,
Daniel

1,063 Views
akshaykul89
Contributor III

Hello Daniel,

Sorry for delayed response.Thanks a lot for your reply on this post. There is some additional information. I am using freertos. After move investigation, I found, MCU is properly moving in to STOP2 but coming out of it because of some other interrupt and NOT ADC interrupt. 

Before going to STOP2 , as I have applied a HW configuration , ideally it keeps on monitoring that particular channel.

Now the next quest is, who brings MCU out of STOP2 state ? Do I need to disable some additioanl interrupts before moving to STOP2 ? for example SysTick. 

Another observation about SysTick is, it does not work with SDK (S32DS_ARM_v2.0\S32DS\S32SDK_S32K14x_EAR_0.8.6)  INT_SYS_DisableIRQ API. I suspect some issue with SDK.

I am not so sure about additional interrupts that needs to be disabled.Is there any possible way to identify all those interrupts bringing MCU out of STOP2 and disable them one by one in source code? Please share your thoughts over it. 

Thanks in advance.

 

Regards,

Akshay K.

0 Kudos

1,063 Views
danielmartynek
NXP TechSupport
NXP TechSupport

Hello Akshay,

As per the Cortex™-M4 Devices Generic User Guide

pastedImage_1.png

And based on my testing, SysTick is stopped in STOP2 and can't wake up.

Also, SysTick is not listed in Section 7.3.1 AWIC stop and VLPS wake-up sources, S32K1xx RM, rev.9.

However, if a debugger is connected, the SysTick is running.

Can you try without the debugger?

Regards,

Daniel 

1,063 Views
akshaykul89
Contributor III

Hello Daniel,

"...And based on my testing, SysTick is stopped in STOP2 and can't wake up...." , I have slightly different observation. Please find below code,

static void prvReadADC0DataTask( void *pvParameters )
{
    uint16_t adcMax; // ADC resolution, used in user value calculation for now.
    status_t retV = STATUS_SUCCESS; /* Variable used for status of changing mode */

    /* Casting pvParameters to void because it is unused */
    (void)pvParameters;

    /* Infinite loop
    * Wait for ADC conversion complete interrupt,
    * then process and send the result to user.
    */
while(1)
{
    char msg[255] = { 0 }; // Buffer to hold printable string

    /*
    * ADC0 is software triggered, hence configuring new channel to
    * ADC0 will automatically trigger next conversion.
    * As soon as next conversion is complete, it will get in to
    * ADC0 ADC_IRQHandler funtion.
    * Go to ADC0 ADC_IRQHandler function for more details.*/

    /* And convert it to string */
    print(headerStrPOT1);
    floatToStr(&adcValuePOT1, msg, 5);
    print(msg);
    print(" V\r\n");

    print(headerStrPOT2);
    floatToStr(&adcValuePOT2, msg, 5);
    print(msg);
    print(" V\r\n");

    print(headerStrOBPOT);
    floatToStr(&adcValueOBPOT, msg, 5);
    print(msg);
    print(" V\r\n");

    if((OBDThreshold >= adcValueOBPOT) && (true == isDataUpdatedFirst))
    {
        print((const char*)"**Critically low OBPOT value, it's below threshold level...\r\n");

        xTimerStop(xADC0StartReadTimer,mainADC0_READ_TIMER_PERIOD_MS); // Stop Timer

        vPortSuppressTicksAndSleep(1);
        myStopSysTick();

        adConv1_ConvConfig0.continuousConvEnable = true;
        ADC_DRV_ConfigConverter(INST_ADC0, &adConv1_ConvConfig0);
        ADC_DRV_ConfigHwCompare(INST_ADC0, &adConv1_HwCompConfig0); // Apply hardware compare limits
        curADCChannel = adConv1_OB_POT_ChnConfig6.channel;
        ADC_DRV_ConfigChan(INST_ADC0, 0UL, &adConv1_OB_POT_ChnConfig6);

        print((const char*)"**Switching to STOP2 Power Mode\r\n");

        /* Set power mode to STOP2 */
        retV = POWER_SYS_SetMode(STOP2,                         POWER_MANAGER_POLICY_FORCIBLE);//POWER_MANAGER_POLICY_AGREEMENT);
        if (retV == STATUS_SUCCESS)
        {
            //vPortSetupTimerInterrupt();

            myStartSysTick();

            adConv1_ConvConfig0.continuousConvEnable = false;
            ADC_DRV_ConfigConverter(INST_ADC0, &adConv1_ConvConfig0);

            adConv1_HwCompConfig0.compareEnable = false; // disable comparator
            ADC_DRV_ConfigHwCompare(INST_ADC0, &adConv1_HwCompConfig0);

            xTimerStart(xADC0StartReadTimer,mainADC0_READ_TIMER_PERIOD_MS); // reset timer to start from beginning
            print((const char*)"Switched out of STOP2 mode successfully\r\n");
        }
        else
        {
            print((const char*)"Switched out of STOP2 mode unsuccessfully\r\n");
        }
    }
delayCycles(0x7FFFFF);
}
}

void myStopSysTick()
{
    __asm volatile( "cpsid i" );
    portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
    __asm volatile( "cpsie i" );
}

void myStartSysTick()
{
    /* Restart SysTick. */
    __asm volatile( "cpsid i" );
    portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
    __asm volatile( "cpsie i" );
}

Sequence is as below ,

1. prvReadADC0DataTask task prints values of 3 ADC0 channels having POT connected to them.

2. If value of OB POT goes below defined threshold, then systick will be stopped with

        vPortSuppressTicksAndSleep(1);
        myStopSysTick();

3. Configure OB POT ADC channel to trigger an interrupt when it's value goes above threshold. (HW compare enabled)

4. Move to STOP2 by calling POWER_SYS_SetMode.   ---> Successful here

5. As OB POT adjusted to be above threshold, MCU comes in RUN mode.

6. Do mentioned stuff on successful exit of STOP2. ex. start ADC channel read timer, start myStartSysTick

7. Go to step 2. 

Observation :

MCU does not move to stay in STOP2 second time onwards. I am wondering, why does it work with stopping SysTick in first attempt and does not work second time onwards. 

This is little bit confusing for me. 

Regards,

Akshay K.

0 Kudos

1,063 Views
danielmartynek
NXP TechSupport
NXP TechSupport

Hello Akshay,

Do you use the SDK FreeRTOS driver or your own implementation?

Again, have you tried running the code stand-alone?

Thanks,

Daniel

0 Kudos

1,063 Views
akshaykul89
Contributor III

Hello Daniel, 

Q.Do you use the SDK FreeRTOS driver or your own implementation?

-- At first, I tried using SDK FreeRTOS driver function vPortSuppressTicksAndSleep to reconfigure new SysTick. It wasn't much helpful. As per my understanding it was allowing SysTick to be delayed by just 349 msec based on this 

ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;

Next to that, I created two functions to stop SysTick and re enable it :

 void myStopSysTick() 

 void myStartSysTick()

Q. Again, have you tried running the code stand-alone?

Yes, I powered on EVB with USB supply from my Laptop. While debugging, I used OpenSDA debugger port and run in normal mode (release image) otherwise. I believe, running code in stand-alone refers to release image mode. Please correct me, if I am missing something.

 

Your inputs are really guiding me through this. Thank you.

Regards,

Akshay K.

0 Kudos

1,063 Views
akshaykul89
Contributor III

Hello Daniel,

I finally made it through. It is working now. This is what I did,

1. When value at specific ADC channel went below threshold value, then I stopped SysTick with     portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;

2. Disabled ADC0 interrupt.

3. Enabled ADC0 for continuous conversion.

4. Applied hardware configuration on ADC0 to generate ADC0 interrupt only when ADC0 channel value is above specific threshold.

5.Configured specific ADC0 channel.

6. Enabled ADC0 interrupt.

7. Entered in STOP2.

8. As soon as ADC0 channel input goes above threshold ADC0 interrupt wakes up MCU.

9. Disable ADC0 interrupt.

10. Start systick with vPortSetupTimerInterrupt.

11. Call ADC_DRV_Reset on ADC0

12. Call ADC_DRV_ConfigConverter on ADC0

13. Enable ADC0 interrupt.

After all these changes, if ADC channel value goes below threshold then MCU enters in STOP2 and stays in same power mode until value at that particular channel is not above threshold.

Solution found!!!..

Thanks a lot for your inputs, they really helped me.

Regards,

Akshay K.