This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to do a low power sleep without interrupts?

I'm trying to do a low power sleep of 1s directly after a device reset, i.e. in Reset_Handler().

During this stage, my application does not allow any interrupts.

So my question: how to do it actually?

Current attempt is as follows:

extern "C" void Reset_Handler_Delay( void )
{
    NRF_POWER->TASKS_LOWPWR = 1;

    //
    // enable clock as Internal 32KHz oscillator
    //
    NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_RC << CLOCK_LFCLKSRC_SRC_Pos);
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_LFCLKSTART    = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
    }
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;

    NRF_RTC1->TASKS_STOP  = 1;
    NRF_RTC1->TASKS_CLEAR = 1;
    NRF_RTC1->PRESCALER   = 0;
    NRF_RTC1->INTENCLR    = 0xffffffffUL;
    NRF_RTC1->EVTENCLR    = 0xffffffffUL;
    NRF_RTC1->INTENSET    = RTC_INTENSET_COMPARE3_Msk;         // TODO CC[0] and [1] are not working
    NRF_RTC1->EVTENSET    = RTC_EVTENSET_COMPARE3_Msk;
    NRF_RTC1->EVENTS_COMPARE[3] = 0;
    NRF_RTC1->CC[3] = NRF_RTC1->COUNTER + (1000 * 32768UL) / 1000UL;
    NRF_RTC1->TASKS_START = 1;
    __SEV();
    while ( !NRF_RTC1->EVENTS_COMPARE[3]) {
        __WFE();
    }

    NRF_RTC1->TASKS_STOP = 1;
    NRF_RTC1->TASKS_CLEAR = 1;
    NRF_RTC1->INTENCLR = 0xffffffffUL;
    NRF_RTC1->EVTENCLR = 0xffffffffUL;
    NRF_CLOCK->TASKS_LFCLKSTOP = 1;
}   // Reset_Handler_Delay

Without the __WFE() is is working (with high current of course), with __WFE() included, the loop hangs.

Thanks for suggestions.

Hardy

Parents
  • Hi,

    Try setting the SEVONPEND flag at the start of your Reset_Handler_Delay() function.

    SCB->SCR |= SCB_SCR_SEVONPEND_Msk; 

    Clear the flag at the end of your Reset_Handler_Delay() function.

    SCB->SCR &= ~(1UL << SCB_SCR_SEVONPEND_Pos);

    Some more information about this can be found in this post.

  • Hi Sigurd,

    thanks for the suggestion.  Unfortunately it does not help, the MCU still stucks...

    Current code:

    extern "C" void Reset_Handler_Delay( void )
    {
        NRF_POWER->TASKS_LOWPWR = 1;
    
        //
        // enable clock as Internal 32KHz oscillator
        //
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_RC << CLOCK_LFCLKSRC_SRC_Pos);
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_LFCLKSTART    = 1;
        while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
        }
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    
        //
        // Start HF oscillator -> current consumption increases
        //
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART    = 1;
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
        }
    
        SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
    
    #if 0
        NRF_RTC1->TASKS_STOP  = 1;
        NRF_RTC1->TASKS_CLEAR = 1;
        NRF_RTC1->PRESCALER   = 0;
        NRF_RTC1->INTENCLR    = 0xffffffffUL;
        NRF_RTC1->EVTENCLR    = 0xffffffffUL;
        NRF_RTC1->INTENSET    = RTC_INTENSET_COMPARE3_Msk;         // TODO CC[0] and [1] are not working
        NRF_RTC1->EVTENSET    = RTC_EVTENSET_COMPARE3_Msk;
        NRF_RTC1->EVENTS_COMPARE[3] = 0;
        NRF_RTC1->CC[3] = NRF_RTC1->COUNTER + (1000 * 32768UL) / 1000UL;
        NRF_RTC1->TASKS_START = 1;
        while ( !NRF_RTC1->EVENTS_COMPARE[3]) {
            __WFE();
        }
    
        NRF_RTC1->TASKS_STOP = 1;
        NRF_RTC1->TASKS_CLEAR = 1;
        NRF_RTC1->INTENCLR = 0xffffffffUL;
        NRF_RTC1->EVTENCLR = 0xffffffffUL;
        NRF_CLOCK->TASKS_LFCLKSTOP = 1;
    #endif
    
    #if 1
        NRF_TIMER0->MODE = 0;
        NRF_TIMER0->BITMODE = 3;
        NRF_TIMER0->CC[0] = 1000;
        NRF_TIMER0->PRESCALER = 10;
        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
        NRF_TIMER0->TASKS_START = 1;
        while ( !NRF_TIMER0->EVENTS_COMPARE[0]) {
            __WFE();
        }
    #endif
    
        SCB->SCR &= ~(1UL << SCB_SCR_SEVONPEND_Pos);
    }   // Reset_Handler_Delay
    

    Neither loop (RTC/TIMER) terminates if __WFE() is contained.  Both terminate if __WFE() is removed.

    Any idea why?  Is there anything more required to generate an SEV?

Reply
  • Hi Sigurd,

    thanks for the suggestion.  Unfortunately it does not help, the MCU still stucks...

    Current code:

    extern "C" void Reset_Handler_Delay( void )
    {
        NRF_POWER->TASKS_LOWPWR = 1;
    
        //
        // enable clock as Internal 32KHz oscillator
        //
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_RC << CLOCK_LFCLKSRC_SRC_Pos);
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_LFCLKSTART    = 1;
        while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
        }
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    
        //
        // Start HF oscillator -> current consumption increases
        //
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART    = 1;
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
        }
    
        SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
    
    #if 0
        NRF_RTC1->TASKS_STOP  = 1;
        NRF_RTC1->TASKS_CLEAR = 1;
        NRF_RTC1->PRESCALER   = 0;
        NRF_RTC1->INTENCLR    = 0xffffffffUL;
        NRF_RTC1->EVTENCLR    = 0xffffffffUL;
        NRF_RTC1->INTENSET    = RTC_INTENSET_COMPARE3_Msk;         // TODO CC[0] and [1] are not working
        NRF_RTC1->EVTENSET    = RTC_EVTENSET_COMPARE3_Msk;
        NRF_RTC1->EVENTS_COMPARE[3] = 0;
        NRF_RTC1->CC[3] = NRF_RTC1->COUNTER + (1000 * 32768UL) / 1000UL;
        NRF_RTC1->TASKS_START = 1;
        while ( !NRF_RTC1->EVENTS_COMPARE[3]) {
            __WFE();
        }
    
        NRF_RTC1->TASKS_STOP = 1;
        NRF_RTC1->TASKS_CLEAR = 1;
        NRF_RTC1->INTENCLR = 0xffffffffUL;
        NRF_RTC1->EVTENCLR = 0xffffffffUL;
        NRF_CLOCK->TASKS_LFCLKSTOP = 1;
    #endif
    
    #if 1
        NRF_TIMER0->MODE = 0;
        NRF_TIMER0->BITMODE = 3;
        NRF_TIMER0->CC[0] = 1000;
        NRF_TIMER0->PRESCALER = 10;
        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
        NRF_TIMER0->TASKS_START = 1;
        while ( !NRF_TIMER0->EVENTS_COMPARE[0]) {
            __WFE();
        }
    #endif
    
        SCB->SCR &= ~(1UL << SCB_SCR_SEVONPEND_Pos);
    }   // Reset_Handler_Delay
    

    Neither loop (RTC/TIMER) terminates if __WFE() is contained.  Both terminate if __WFE() is removed.

    Any idea why?  Is there anything more required to generate an SEV?

Children
  • This works fine here:

    void Reset_Handler_Delay( void )
    {
       NRF_POWER->TASKS_LOWPWR = 1;
       SCB->SCR |= SCB_SCR_SEVONPEND_Msk; 
    
        //
        // enable clock as Internal 32KHz oscillator
        //
        NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_RC << CLOCK_LFCLKSRC_SRC_Pos);
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_LFCLKSTART    = 1;
        while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
        }
        NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    
        NRF_RTC1->TASKS_STOP  = 1;
        NRF_RTC1->TASKS_CLEAR = 1;
        NRF_RTC1->PRESCALER   = 0;
        NRF_RTC1->INTENCLR    = 0xffffffffUL;
        NRF_RTC1->EVTENCLR    = 0xffffffffUL;
        NRF_RTC1->INTENSET    = RTC_INTENSET_COMPARE3_Msk;         // TODO CC[0] and [1] are not working
        NRF_RTC1->EVTENSET    = RTC_EVTENSET_COMPARE3_Msk;
        NRF_RTC1->EVENTS_COMPARE[3] = 0;
        NRF_RTC1->CC[3] = NRF_RTC1->COUNTER + (1000 * 32768UL) / 1000UL;
        NRF_RTC1->TASKS_START = 1;
        __SEV();
        while ( !NRF_RTC1->EVENTS_COMPARE[3]) {
            __WFE();
        }
    
        NRF_RTC1->TASKS_STOP = 1;
        NRF_RTC1->TASKS_CLEAR = 1;
        NRF_RTC1->INTENCLR = 0xffffffffUL;
        NRF_RTC1->EVTENCLR = 0xffffffffUL;
        NRF_CLOCK->TASKS_LFCLKSTOP = 1;
        
        
        SCB->SCR &= ~(1UL << SCB_SCR_SEVONPEND_Pos);
        
        
    }   // Reset_Handler_Delay

    How does your Reset_Handler look like ?

    What toolchain / IDE are you using ?

    If you are using Keil, have you made any changes in arm_startup_nrf52.s ?

  • Almost no changes to startup_nrf52.s...

    Nevertheless I've found my culprit: it's the Jlink adapter!  When I'm disconnecting it, device will start.  When it's connected, __WFE() waits forever.

    Whats wrong with that?

  • I'm not able to recreate this behavior.

    Is this a custom board or the nRF52-DK?

    What toolchain / IDE are you using ?

    What kind of Jlink adapter is this?

  • What is the value of SCB->SCR register and SCB->CCR register before you enter __WFE?

    You could also try to use nrfjprog, and call nrfjprog --run, in case the CPU is somehow halted.

Related