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

Power optimization for LTE and BLE application on Thingy 91

Hi,

I am building an application for Thingy:91, currently using SDK 1.3.0. The application is supposed to collect data using BLE and forward it with LTE to the MQTT broker. I am currently trying to figure out the best solution for power management to obtain the lowest power consumption. From what I read on the forum, usually this issue comes down to whether or not use the deep sleep or not (because waking up from deep sleep and reattaching to network may burn a lot of power). The choice here seems to be case-specific, which is why I want to present my case and ask for advice.

In my applicaiton the device is going to be used most likely few times a day, for a few minute long session of collecting data from BLE devices and forwarding it to the broker. Between those sessions there are going to be few hour long breaks with no required activity on the device. The nRF52 application is based on connectivity bridge application, I modified it to automatically connect to some BLE devices, get the data and send it over UART to nRF91 chip. On nRF91 application I have a thread that initiates and maintains the MQTT connection, and another thread for processing data received on UART and building MQTT messages.

So, I would like to keep the device in the lowest possible power consumption mode for few hours, then wake it up (both 91 and 52 chips) by pressing the button, perform all tasks and go to sleep/idle again.

My questions are:

1. While researching this topic on forum I have run into few terms that refer to power modes, like: system ON and system OFF, sleep and deep sleep or idle mode. I am not sure what is the difference and where could I find some information about it. Also then what are differences between: k_sleep(), k_cpu_idle(), __WFI(), and sd_app_evt_wait()?

2. What happens with the power state/consumption, when a thread is waiting on k_sem_take() or k_fifo_get()?

3. What would be the best strategy for power saving on nRF52 chip, considering that the application is mainly based on Connectivity Bridge? I only need to scan and connect to devices during those few minute long active sessions. Between them the BLE and all other peripherals can be inactive. I guess in that case it makes more sense to put the device into deep sleep mode.

4. If the device is going to be used 3-4 times a day, does it make sense to use the deep sleep (considering high current during attaching to network procedure after wake up), or just the PSM on the modem would be enough (and all threads would be waiting on either k_sem_take or k_fifo_get?

Thanks for help.

Parents
  • Hi!

    1. While researching this topic on forum I have run into few terms that refer to power modes, like: system ON and system OFF, sleep and deep sleep or idle mode. I am not sure what is the difference and where could I find some information about it. Also then what are differences between: k_sleep(), k_cpu_idle(), __WFI(), and sd_app_evt_wait()?

    So the first two functions you mention (k_sleep() and k_cpu_idle) are a part of the Zephyr RTOS in NCS.

    k_sleep(k_timeout_t timeout) puts the current thread to sleep (i.e makes it unready) for a specified amount of time. This prevents it from executing for that amount of time and ready threads of all priorities are then allowed to execute. However, there is no guarantee that threads whose priority is lower than that of the sleeping thread will actually be scheduled before the sleeping thread becomes ready once again.

    k_cpu_idle() makes the CPU idle until an event wakes it up again. When the device is in an idle state and Zephyr's System Power Management is enabled, you can configure the device to go into one of the supported power states, which can be divided into two categories: Sleep State and Deep Sleep State. 

    System ON and system OFF are defined in the PS for the nRF9160. In system OFF mode, everything is powered down except for the reset and wakeup functions. Only a DETECT signal from the GPIO peripheral, a reset or the start of a debug session will wake the system up. When the device wakes up, a system reset is performed.

    In system ON mode, we have the sub-modes constant latency and low power mode. In low power mode, the system will leave the mode when any activity occurs and then return to this mode after. In constant latency mode, the CPU wakeup latency is constant and kept at a minimum, so you have a predictable latency.

    The PS also describes which registers need to be set to enable these modes. However, we recommend using Zephyr's functions instead of setting the registers directly. 

    So for instance calling k_cpu_idle() in a thread will force the system into system ON IDLE mode which prevents other threads from doing work, until an event, typically an interrupt, wakes it up again.

    Please note that using this function directly isn't recommended (Zephyr: CPU Idling: Suggested Uses) because the Zephyr kernel will spawn the idle thread automatically during system initialization, which takes care of activating the power management support when there is no other work to do (Zephyr: System Threads). The idle thread is run automatically by the scheduler when no other work is scheduled, which then puts the system in system ON IDLE mode. 

    sys_pm_force_power_state will force usage of the given power state, so sys_pm_force_power_state(SYS_POWER_STATE_DEEP_SLEEP_1); will force the system to go into system OFF mode when k_sleep is called. The NFC: System OFF sample in NCS has a function showing how to do this (NCS: NFC Samples: System Off, line 133-155). 

    The next two functions you mention (__WFI() and sd_app_evt_wait()) are part of the nRF5 SDK and the SoftDevice API respectively, so you won't use those in your application.

    But in short __WFI() allows the CPU to enter sleep mode, and will only wake up as a result of an interrupt request if the associated interrupt is enabled in the NVIC. As opposed to __WFE() which puts the CPU into sleep mode, and will wake up as a result of any interrupt request. 

    sd_app_evt_wait() is just Nordic's wrapper around __WFE(), with some added internal state-saving mechanisms and safeties that keep the CPU awake and ready if some timing-critical radio operation is about to occur.

    2. What happens with the power state/consumption, when a thread is waiting on k_sem_take() or k_fifo_get()?

    If all threads are blocked, the scheduler will run the idle thread which puts the CPU into system ON IDLE mode until a thread can run again.

    3. What would be the best strategy for power saving on nRF52 chip, considering that the application is mainly based on Connectivity Bridge? I only need to scan and connect to devices during those few minute long active sessions. Between them the BLE and all other peripherals can be inactive. I guess in that case it makes more sense to put the device into deep sleep mode.

    The Connectivity Bridge is a low power application, so there aren't any modifications needed there. However, I'm sceptical to your saying the app is mainly based on the Connectivity Bridge, considering you have added BLE functionality, correct? So the power consumption of the app will depend entirely on how you implemented this. 

    The Zephyr: Bluetooth: HCI UART sample is an implementation of the Zephyr Bluetooth controller that can run on the nRF52840. You could take a look at that sample for instance. 

    4. If the device is going to be used 3-4 times a day, does it make sense to use the deep sleep (considering high current during attaching to network procedure after wake up), or just the PSM on the modem would be enough (and all threads would be waiting on either k_sem_take or k_fifo_get?

    I think you should use system ON IDLE mode along with PSM for the modem. So, just ensuring all threads are asleep (or blocked) will allow the device to go into system ON idle mode. 

    Let me know if you have any more questions!

    Best regards,

    Heidi

  • Hi Heidi,

    Thank you for such a thorough answer! It's a very valuable summary of all the information regarding power management, which is spread all over the forum. I believe now I know enough to manage power properly on the nRF9160 on Thingy.

    Regarding the second application,

    However, I'm sceptical to your saying the app is mainly based on the Connectivity Bridge, considering you have added BLE functionality, correct? So the power consumption of the app will depend entirely on how you implemented thi

    What I meant by "based on connectivity bridge", is that it consists of all the same modules, events and event-driven architecture. I only modified the ble_handler, so that it scans for BLE devices with specified MAC addresses, gets data from them when they are reachable and forwards the data via UART to nRF9160, where I can send it with LTE to the server. So once started, the application scans continuously, if any of listed devices is reachable it connects to it, gets data and disconnects and starts scanning again. What I would like to do is to put it to sleep between those scanning sessions, if no devices are reachable for, say, 2 minutes. The whole procedure would be:

    1. Power on Thingy, both chips go to sleep with maximum power saving.

    2. Wake up both chips by the button (I believe the button interrupt goes only to 91 chip, so the 52 won't wake up from it. My plan was to send a message via UART from nRF9160 to nRF52840 in order to wake up nRF52840 by a UART interrupt, after the button was pressed).

    3. nRF52840 scans for BLE devices, gets data and forwards to nRF9160 via UART. nRF9160 sends data via LTE to the server.

    4. When no new BLE devices appeared for 2 minutes, put both chips back to sleep. Repeat from point 2.

    On nRF9160 I have a main thread that spawns other two threads. One of those two is waiting for semaphore, the other for a new element in queue. In that case using k_cpu_idle() on main thread would be acceptable?

    I believe the continuous BLE scanning will take some energy, which is why I want to put nRF52840 to sleep or some other power saving as well. If I understand correctly how Connectivity Bridge works, all those modules are handled in one thread, right? In that case, according to the CPU Idling documentation you mentioned, it is acceptable to use k_cpu_idle() - especially because I need to wake up by interrupt, so k_sleep() won't work for me.

     

  • Hi!

    Gmaciek said:
    I believe the button interrupt goes only to 91 chip, so the 52 won't wake up from it

     Yes, depending on how you configure the GPIOTE interrupt, the 52 will not be woken up by a button interrupt.

    Gmaciek said:
    My plan was to send a message via UART from nRF9160 to nRF52840 in order to wake up nRF52840 by a UART interrupt, after the button was pressed

     As long as you haven't put the device into system OFF mode (which I wouldn't recommend), this should work. 

    Gmaciek said:
    In that case using k_cpu_idle() on main thread would be acceptable?

     Again, Zephyr does not recommend using k_cpu_idle() directly. If all the threads are idle (i.e waiting for a semaphore or a new element in the queue), the idle thread will execute and activate the board's power management support.

     

    Gmaciek said:
    If I understand correctly how Connectivity Bridge works, all those modules are handled in one thread, right? In that case, according to the CPU Idling documentation you mentioned, it is acceptable to use k_cpu_idle() - especially because I need to wake up by interrupt, so k_sleep() won't work for me.

    Yes, in this case, I think you might want to use k_cpu_idle(). This will then force the device into system ON IDLE mode so no other threads can do any work until the interrupt from the nRF9160 is received. 

  • All right, that's all I need to know (I hope).

    Thanks a lot!

Reply Children
No Data
Related