This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

To identify, adjust sleep period of sample app threads?

Hello Devzone Community,

My name is Ted, and I am continuing my effort to configure a Zephyr based, Nordic aws_iot sample app based firmware to run and support nRF9160 lowest specified power consumption. I am in the process of putting all application threads to sleep, so that Zephyr's idle thread can put the application processor into a low power sleep mode. Nordic Power Profiler waveforms of measured current draw, however, indicate that I've failed in this. Some part of the overall firmware binary appears to be yet running. Lowest average current I achieve is ~190 microamps.

My Devzone account doesn't permit me to upload photos, but here is a link to two captures from Nordic's power profile which I took earlier today.  My apology that I must include an external link here and not the images directly:

wiki.neelanurseries.com/.../20220311

The first one shows a general pattern of current regularly spiking from a few microamps to around three milliamps.  The zoomed capture shows the ten millisecond spikes, a more distinct fast spike and a more blunted longer duration one.

These are taken during a 45 second period when all my application threads are sleeping -- for 45 seconds -- and LTE modem is turned off, and GPIOs to hardware enable points of our board are also turned off, effectively powering down the hardware outside the nRF9160.

From these waveforms I observe that some ARM processor activity appears to be consuming current every ten milliseconds. But though I have put my app threads into a nearly minute long sleep period, and have searched for the sleep periods set on aws_iot sample app threads, I cannot see any firmware configured device or service that is configured to run every ten milliseconds.

This work is based on Nordic's aws_iot sample app, as it appears in ncs v1.6.1. The sample app creates three or four Zephyr threads. Zephyr itself creates a  thread for `int main()` and an idle thread. Work of my own adds a few more threads at run time. These latest threads I can readily put to sleep for minutes or even hours, with a call to k_sleep() in a given thread's effective main function.

I have enabled Zephyr's thread_analyzer feature, and can observe simple reporting at run time of the threads of this firmware. Here is a typical Zephyr output I can see via a serial connection, and using a simple CLI to invoke a handful of commands:

Excerpt 1: Zephyr thread summary report

```1) 'thread_accelerometer' stack size 2048 bytes, stack used 960 bytes, 46%
2) 'thread_dev_work' stack size 3072 bytes, stack used 1504 bytes, 48%
3) 'thread_simple_cli' stack size 4096 bytes, stack used 1768 bytes, 43%
4) 'thread_led' stack size 512 bytes, stack used 136 bytes, 26%
5) 'download_client' stack size 4096 bytes, stack used 104 bytes, 2%
6) 'at_cmd_socket_thread' stack size 1472 bytes, stack used 688 bytes, 46%
7) 'time_thread' stack size 1024 bytes, stack used 728 bytes, 71%
8) 'connection_poll_thread' stack size 3072 bytes, stack used 296 bytes, 9%
9) '0x20015ab0' stack size 1024 bytes, stack used 168 bytes, 16%
10) 'sysworkq' stack size 2048 bytes, stack used 168 bytes, 8%
11) 'idle 00' stack size 320 bytes, stack used 56 bytes, 17%```


Here I modify the report to annotate each thread's origin, which affects how easily or not I can adjust a thread's sleep time:

Excerpt 2:

```1) 'thread_accelerometer' . . . home authored application
2) 'thread_dev_work' . . . home authored application
3) 'thread_simple_cli' . . . home authored application
4) 'thread_led' . . . home authored application
5) 'download_client' . . . aws_iot sample app
6) 'at_cmd_socket_thread' . . . aws_iot sample app
7) 'time_thread' . . . aws_iot sample app
8) 'connection_poll_thread' . . . aws_iot sample app
9) '0x20015ab0' . . . ?, not known
10) 'sysworkq' . . . Zephyr 2.6.0
11) 'idle 00' . . . Zephyr 2.6.0```


So far I have been able to track down in Zephyr's dwt.h library header file that the time thread has a default sleep period of 3600 seconds. Tracing thread 'at_cmd_socket_thread' which is implemented in ncs/nrf/subsys/net/lib/aws_iot/src/aws_iot.c I cannot tell what this thread's effective sleep period is.

Question (1): Can a Devzone team member or community member help me identify where this thread's sleep time is realized?

I have yet to find the implementation details for thread 'download_client', 'connection_poll_thread' and '0x20015ab0'. The last of these threads I have concern for. It is not named, and so I cannot be sure whether it is a Zephyr construct or a Nordic sample app construct. This unnamed thread has shown in the thread analyzer report since I enabled Zephyr's analyzer.


Question (2): is static code analysis the only way to learn "who" in the Zephyr and other source codes is creating the unnamed thread?

Until I can identify the unnamed thread, I won't know whether I can cleanly properly adjust its sleep period. If it is a kernel thread, my app space firmware won't automatically have privileges to make any changes to a kernel thread. I believe there are some extra steps to be able to do so, if that is even possible.

I recognize also that I cannot simply change sleep times of the aws_iot sample app threads, and expect celular level and MQTT client-broker connections to continue to function. I'll need to study and find a way to cleanly close connections before putting such threads to sleep.

Thanks ahead of time to all who can shed some light and help on these deep sleep and nRF9160 power saving questions!

- Ted

  • Thank you Didrik,

    Your mention of the separate power supply, I believe nRF9160 datasheet names it VDD_GPIO or similar, reminds me of a related question:  what is or are the correct Zephyr 2.6.0 GPIO configuration to assign to nRF9160 general purpose I/O port pins,

    (a)  when I/O pin acts as a chip select line to external device, which itself is powered off (at ground state)

    (b)  when I/O pin in wake mode receives interrupts from external device,

    To be clear, during active wake times of nRF9160 + external circuit + firmware, I will configure I/O pins for their normal input or output uses, and set pull-ups and pull-downs as needed.  But to enter deep sleep mode and avoid unintended "bleed" currents to and from nRF9160 GPIOs, I expect I must in some cases change pin configurations at run time or "on the fly".  Is my understanding in this correct?

    Kindly tell me whether this question group is best to open in a new Devzone ticket.

    I ask this I/O config question, due to modest progress with my team's custom 9160-based board.  My latest efforts to modify project firmware to emulate the settings and action of your low power hello_world have gotten me to sub-one-hundred uA current draw.  It is true my custom board differs from the nRF9160DK kit.  In particular, I can only measure total board current, I don't have a break out solder bridge or test points pair to look only at nRF9160 VDD current use.  But this measure-all-board-current is good.  I need to bring total board current down to very close to nRF9160 advertised lowest current for battery life requirements.

    The code I run is also still different code with respect to attached low-power code samples.  In my firmware project I've commented out everything I may reasonably disable.  Given custom board however I wrote and use custom board files (dts, yaml).  These depart from your shared hello_world sample apps.

    So I am trying to adapt my firmware as near as possible to your hello_world configuration settings and run time functionality.  I no longer see any periodic ~25Hz to ~33Hz current pulsing, just small steady current in tens of microamps.  I suspect GPIO mis-configuration.

    As always thank you, Didrik.  Once I solve our low current conundrums I will share a practical summary of steps taken plus what works.

    - Ted

    ( p.s.:  I have tested three different Zephyr GPIO pin configurations, which I set in code sequence to enter my custom firmware into deep sleep mode.  These configurations include (1) GPIO_INPUT with weak pull-down enabled, (2) GPIO_OUTPUT with output set low, (3) GPIO_DISCONNECTED.  These settings I apply to pins which are connected to external sensors, FETs, memory which are themselves at that point powered down.  I actually see more current consumption on our custom board when I attempt these settings, than when making no explicit GPIO configuration at all. Strange.  I am now working through one and a few pins' settings at a time and building a table of current measurement results, to narrow down whether one or a few pins are contributing the additional currents.  But there are many combinations of configurations possible, and pins to configure, which motivate my latest questions! )

  • tedhavelka said:
    I no longer see any periodic ~25Hz to ~33Hz current pulsing

    That's great!

    tedhavelka said:
    Kindly tell me whether this question group is best to open in a new Devzone ticket

    They are a bit outside of my area of expertise and given that we found the rouge thread (and you no longer see the current pulsing), I think those questions are best answered in a new ticket.

    tedhavelka said:
    As always thank you, Didrik

    You're welcome.

    Best regards,

    Didrik

  • Hello Didrik,

    Regarding nRF9160 GPIO settings I will open a new Devzone ticket.  Thank you for helping me to track down the rogue thread, a run-time result of ncs v1.6.1 aws_iot sample app calling at_configure() ncs API routine in its main.c source file.

    By the way I notice that in ncs v1.9.1 aws_iot main.c there is no longer any call anywhere to at_configure().

    As for the attached low power examples, I only want to note that I've yet to obtain approximate 3uA deep sleep current readings.  The first of the five versions of attached hello_world I could build and run, but draws about 3mA on nRF9160DK board rev 1.0.0 (known issue there you note and link to an errata sheet).  The later attached projects I cannot build.  A modified version I tried to adapt, and eventually in Devzone post 86265 draws too little current for me to trust, about 46nA.  Have further testing to perform, and I may open a new ticket on the low power sample app question too.

    Thank you again for the detailed help and your patience Didrik.  Stay safe,

    - Ted

  • Hello Didrik,

    Will you please mark this Devzone post as answered?  I strayed from the original threads question at points, but the answers for tracking down the mystery thread in my aws_iot sample based app are here.  Plus the related Zephyr thread debugging questions have also been answered.  Following Håkon's instructions for gdb server and gdb in each their own terminal window provides me run time inspection of Zephyr 2.6.0 threads in a custom app.

    Thanks,

    - Ted

  • tedhavelka said:
    Thank you for helping me to track down the rogue thread, a run-time result of ncs v1.6.1 aws_iot sample app calling at_configure() ncs API routine in its main.c source file.

    No, the at_configure() isn't involved. The problem is the at_host library, which runs in the background and don't interract directly with the application.

    tedhavelka said:
    By the way I notice that in ncs v1.9.1 aws_iot main.c there is no longer any call anywhere to at_configure()

    Yes, we have reworked the AT command interface, so the at_cmd() and at_notif() libraries no longer is needed.

    Instead, you can use the AT command interface in the modem_lib directly: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/nrfxlib/nrf_modem/doc/at_interface.html

    tedhavelka said:
    Will you please mark this Devzone post as answered?

    I'll see if I can find some usefull answers to mark as verified.

    Best regards,

    Didrik

Related