nRF52840: How do I read the "Event Register"?

nRF52840, SDK 17.0.2, SD140 v7.0.1

My firmware application is happily sleeping via calls to nrf_pwr_mgmt_run(), waking up to service interrupts and do work, then going to back to sleep.

Sometimes, something happens shortly after a BLE central connects to my device- for some reason, my calls to nrf_pwr_mgmt_run() immediately return, and the nRF52840 spins in the main loop instead of sleeping. This causes a large amount of energy from the battery to be wasted doing nothing, and the product does not last as long.

I'm trying to trace down the source of what's immediately waking the nRF52840 back up, so I can fix it.

I would like to know if SoftDevice is constantly waking up my application, or if I'm calling something like app_timer_start / app_timer_stop that fires a software interrupt, which sets the event flag.

For logging purposes, how do I read the "Event Register" that WFE and SEV operate on? I don't want to set it, but I do want to read it. If it's set before I call into nrf_pwr_mgmt_run(), then I know it's something I did in my loop.

Thanks,

Charles Nicholson

Parents
  • Hello Charles,

    Like the __WFE instruction, a single call to nrf_pwr_mgmt_run() will not make the device enter sleep if the event register has been set (e.g. after servicing an ISR). This is why you will see that this function is always placed within a loop in our code examples.

    In your case, could it be an option to place the nrf_pwr_mgmt_run() function in a spinlock loop? Something like this:

    do {
        nrf_pwr_mgmt_run();
    } while (app_wakeup == false);

    where "app_wakeup" is a state flag set in your interrupt handler(s) to tell the program when to exit sleep.

    I'm trying to trace down the source of what's immediately waking the nRF52840 back up, so I can fix it.

    You can try to check which interrupt it was woken up by with this code:

        uint8_t cnt; 
        /*Send Event on Pending interrupts*/
        SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
    
        // Enter main loop.
        for (;;)
        {
            while(NRF_LOG_PROCESS());
        
            cnt=0;
    
            CRITICAL_REGION_ENTER();
            /* Call nrf_pwr_mgmt_run() repeatedly as long as there are no pending interrupts */
            do {
              nrf_pwr_mgmt_run();
              cnt++;
            } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
            
            /* Loop through the ISPR registers to check which IRQn woke the CPU */
            for (int irqn = POWER_CLOCK_IRQn; irqn <= SPIM3_IRQn; irqn++)
            {
                if (NVIC_GetPendingIRQ(irqn)) 
                {
                    NRF_LOG_INFO("IRQ pending %d", irqn);
                }
            }
    
            CRITICAL_REGION_EXIT();
            NRF_LOG_INFO("nrf_pwr_mgmt_run() was run %d times", cnt);
        }
    }

    For logging purposes, how do I read the "Event Register" that WFE and SEV operate on?

    The event register is not accessible to the CPU, unfortunately.

    Best regards,

    Vidar

  • Thanks very much for the detailed and quick response, I appreciate it!

    Best,

    Charles

Reply Children
No Data
Related