Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

802.15.4 sys_sleep_request_ms does not work

Hi all,

I'm using NRF SDK v17.0.2 and IEEE 802.15.4 stack library. I want to implement sleeping device. I think I should use sys_sleep_request_ms function to make the device go to sleep but calling it does nothing. If I use  sys_sleep_approver_register to register callbacks for SYS_EVENT_FALLING_ASLEEP and SYS_EVENT_WAKE_UP events (and call sys_sleep_approve in SYS_EVENT_FALLING_ASLEEP event) I see that the callback are called but the SYS_EVENT_WAKE_UP event is emitted immediately after SYS_EVENT_FALLING_ASLEEP event.

So I digged deeper and dissassembled the components/802_15_4/raw/802_15_4_lib_gcc.a library (and all other variants of this library ) to see if there are any calls to wfi or wfe instructions and to my supprise there are none.

This is the dissassembly of the hal_sleep function:

00000000 <hal_sleep>:
   0:	2000      	movs	r0, #0
   2:	4770      	bx	lr

It looks like this function is just returning value 0, what would translate to UNKNOWN_INTERRUPT enum. Do I need to override this function (it is not declared extern so I don't think so) ?

So my question is this library supports sleeping devices ? I would imagine that this library would allow me to implement a device that would wakeup from sleep before the beacon arrival, then go to sleep after the beacon if no data tranfers are pending. Is that possible with this library ?

Nest regards,

Marek Czerski

  • Hi Edvin,

    Thanks for the response. I cannot reply directly to Your last message because there is no reply button so I just reply to myself.

    I did what You suggested (calling __WFE()) and it does work. But I have an issue with the current consumption. It is much larger than expected and is aroung 400uA. I expect it to be less that 10uA. The isolated test case is below:

    static void clock_init(void)
    {
        ret_code_t err_code = nrf_drv_clock_init();
        ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_MODULE_ALREADY_INITIALIZED));
    
        nrf_drv_clock_hfclk_request(NULL);
        while (!nrf_drv_clock_hfclk_is_running())
        {
            // spin lock
        }
    
        nrf_drv_clock_lfclk_request(NULL);
        while (!nrf_drv_clock_lfclk_is_running())
        {
            // spin lock
        }
    }
    
    static void sleep()
    {
        nrf_drv_clock_hfclk_release();
        __SEV();
        __WFE();
        __WFE();
        nrf_drv_clock_hfclk_request(NULL);
        while (!nrf_drv_clock_hfclk_is_running())
        {
            // spin lock
        }
    }
    
    int main(void)
    {
        static uint8_t __ALIGN(ALIGN_VALUE) m_heap[CONFIG_POOL_SIZE];
        static const size_t m_heap_size = CONFIG_POOL_SIZE;
        ral_irq_handler_import();
        clock_init();
        sys_init(m_heap, m_heap_size);
        sleep();
    }

    To be sure that the issue is related to the 802.15.4 library i tested the case where sleep was called just before sys_init and the result was that the current consumption was at around 3uA which is what I would expect.

    So obviously the sys_init call enables some hardware that consumes 400uA of current and I'm not able to figure out what it is. I know that I should disable all the peripherials for low current consumption in sleap mode, but I do not know which peripherials are enabled by the sys_init call.

    I suspect the RADIO and TIMER0 peripherials but disabling them explicitly before sleep does not change the current consumption.

    To disable radio and timer I did:

    NRF_RADIO->TASKS_DISABLE = 1;
    TIMER0->TASK_STOP = 1;

    So the question is, what do I need to disable to get low current consumption in SYSTEM ON sleep ?

    Best regards,

    Marek Czerski

  • rozpruwacz said:
    I cannot reply directly to Your last message because there is no reply button so I just reply to myself.

     It happens from time to time. Try to reload the page until it shows up if it happens again.

    So it could be a couple of different things causing the higher current consumption.

    802.15.4 is used in Thread and Zigbee, and the downside with this is that the proper nodes have to always be listening, keeping the radio in RX mode. However, this would draw a lot more than 400µA (roughly 5-10 mA), so I don't think that is what you are seeing.

    Please note that calling TIMER0->TASK_STOP doesn't stop the actual clock that you requested using nrf_drv_clock_hfclk_request().

    I see that you release the hfclk as well, but is it requested from elsewhere in your project? You can try to debug nrf_drv_clock_hfclk_release() to see whether or not this line is true or false:

    m_clock_cb.hfclk_requests

    and whether hfclk_stop() is called.

    Is your lfclk running when you enter sleep? For both of the clocks you can check the registers directly using 

    NRF_CLOCK->HFCLKSTAT;

    NRF_CLOCK->LFCLKSTAT;

    (see links for register description)

    What HW are you running this on? DKs or custom boards? Does it have an LFXTAL? If it is a custom board, you need to check the XTALs' electrical specification to see how much current it draws.

    Another possibility is other peripherals. Are you using anything else? UART for logging or the application? If so, you can try to disable this as well, and set the pins in the disconnected input state. Basically, an output may draw current if it needs to hold a pin high or low while it is in sleep.

    Best regards,

    Edvin

  • I see that you release the hfclk as well, but is it requested from elsewhere in your project? You can try to debug nrf_drv_clock_hfclk_release() to see whether or not this line is true or false:

    No other part of the code is requesting the hf clock. I checked also that nrf_drv_clock_hfclk_release actually stops the hf clock and it does.

    Is your lfclk running when you enter sleep?

    Yes it runs in sleep. I added code to disable it after Your suggestion but it not changed the current consumption during sleep.

    For both of the clocks you can check the registers directly using 

    I checked both registers values just before __WFE call and those are the values:

    HFCLKSTAT = 65536
    LFCLKSTAT = 0

    I'm not sure if the HFCLKSTAT is correct. As I understand, the value 65536 (0x10000) means that the hfclk runs from internal high frequency oscillator. Before call to nrf_drv_clock_hfclk_release the value is 0x10001 which means that the hfclk runs from external oscillator. Should the value of HFCLKSTAT be 0 ? If yes, then maybe in debug mode it can't be 0 to allow debug interface to work ?

    What HW are you running this on? DKs or custom boards? Does it have an LFXTAL?

    I'm using nrf52840 dongle board (pca10059).

    Another possibility is other peripherals. Are you using anything else? UART for logging or the application?

    No other peripherials. No logs, no uart.

    I'm pretty sure that the high current consumption is caused by the sys_init call because if I call sleep just before sys_init I get 3uA, if I call sleep just after sys_init I get 400uA.

  • >HFCLKSTAT = 65536

    Yes, that means HFCLKSTAT = 0x00010000, meaning that STATE = not running, SRC = XTAL.

    I haven't tried to measure the current consumtion on the dongle before. How do you measure it? Is the dongle connected to a computer via the USB?

    How do you wake up from the sleep? I see that you use sys_sleep_request_ms(10000); Do you wake up after 10 seconds, or do you wake on a button press or something?

    The reason I ask is because if none of the clocks are running, and you wake up after 10 seconds, it means it is using nrf_delay_ms(), which doesn't really allow the device to go to sleep.

    BR,
    Edvin

  • How do you wake up from the sleep? I see that you use sys_sleep_request_ms(10000); Do you wake up after 10 seconds, or do you wake on a button press or something?

    No. I am working now with a minimal example that only goes sleep after calling sys_init. No wake up.

    This is the exact and only code I'm running:

    #include "sys_init.h"
    #include "sys_utils.h"
    #include "nrf_drv_clock.h"
    #include "802_15_4_config.h"
    #include "ral_irq_handlers.h"
    
    
    static void clock_init(void)
    {
        ret_code_t err_code = nrf_drv_clock_init();
        ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_MODULE_ALREADY_INITIALIZED));
    
        nrf_drv_clock_hfclk_request(NULL);
        while (!nrf_drv_clock_hfclk_is_running())
        {}
    
        nrf_drv_clock_lfclk_request(NULL);
        while (!nrf_drv_clock_lfclk_is_running())
        {}
    }
    
    int main(void)
    {
        static uint8_t __ALIGN(ALIGN_VALUE) m_heap[CONFIG_POOL_SIZE];
        static const size_t m_heap_size = CONFIG_POOL_SIZE;
        ral_irq_handler_import();
        clock_init();
        sys_init(m_heap, m_heap_size);
        nrf_drv_clock_hfclk_release();
        nrf_drv_clock_lfclk_release();
        while(1) {
            __WFE();
        }
    }
    

    IF I COMMENT OUT THE sys_init CALL THE CURRENT CONSUMPTION IS 3uA.

    How do you measure it? Is the dongle connected to a computer via the USB?

    I power the board with 3.3V through OUT ping (which is the VDD CPU pin).

    I measure the current with multimeter beetween power source and OUT pin.

Related