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

Lowest power mode for an external interrupt with nRF51822?

Our system will awake from an external accelerometer interrupt, so I would need a code fragment which shuts down S110 soft device (and radio of course) and also all the nRF51822 peripherals, as well as RAM retention. Even the real time clock is not needed. The CPU only needs to awake by the external interrupt. My related questions are:

  1. What is the needed code to do that, can I still use sd_app_evt_wait()?
  2. What should I expect as the current consumption in that state?
  3. Further, what is the code to get the system up and running again?
  • Hi Jarmo,

    The chip supports a very low power (~300nA) "system off" mode from which it can be woken using a transition on a pin. In this mode, the clock does not run. You first have to configure the "SENSE" flag for the pin you wish to use to wake the processor. For instance, the following configures a pin to watch for a low-to-high transition:

    NRF_GPIO->PIN_CNF[pin_number] =
            (NRF_GPIO->PIN_CNF[pin_number] &
             ~GPIO_PIN_CNF_SENSE_Msk) |
            (GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos);
    

    Typically you use this along with the "PORT" event, which can be used to respond to transitions on a pin with "SENSE" enabled.

    When using the SoftDevice, you can then enter system off using:

    sd_power_system_off()
    

    This function does not return. When the processor wakes up, it is by a reset (the reset reason register will match "POWER_RESETREAS_OFF_Msk"). If you need to treat this case separately, therefore, you should have the following test early in your startup code:

    uint32_t reset_reason;
    (void)sd_power_reset_reason_get(&reset_reason);
    (void)sd_power_reset_reason_clr(0xffffffff);
    if(POWER_RESETREAS_OFF_Msk & reset_reason)
    {
        /* Handle special-case wake-up by accelerometer */
    }
    

    Alternately, if you don't need current consumption quite this low, you can just turn off all peripherals but leave the 32kHz oscillator running. You just continue to use sd_app_evt_wait as usual. You can get current consumption of ~3uA with this method. Note, however, that there's not a single function to do this, you need to write your peripheral drivers with this mind, such that they are not running except when necessary. For peripherals controlled by the stack (e.g. radio), you just need to disable any active behaviour (disconnect, stop advertising) and the stack will do the rest.

  • Thanks, that sounds like it could be one possible solution for me :) However, I think I could also live with 3 uA, so what are the "commands" to shut down soft device, radio, twi- and spi-units, uart, rtc and finally also RAM retention, before calling sd_app_evt_wait()? The device won't need to respond to anything before getting an interrupt from accelerometer. The idea is that a "hit" (movement) switches it into "running" state for a few minutes, before it goes back to sleep.

  • Hi Jarmo,

    Like I said, there aren't a consistent set of commands to shut down each peripheral. You need to read the documentation for each peripheral (in the nRF51 manual) and make sure they are not running to achieve the 3uA usage in "normal" sleep. For instance, for UART you need to stop the transmitter and receiver using the tasks STOPRX and STOPTX. You should call these in the peripheral driver whenever you are done receiving or transmitting, respectively. Obviously exactly when you do this will depend on how you intend to use the interface.

  • Thanks for comments! Although I don't quite understand why there is no "consistent set of commands". For UART, I was earlier instructed to use those STOPRX and STOPTX and that was it, works fine! What about for TWI and SPI? They cannot be much more complicated. Of course, I can start reading documentation as you suggested, but I hoped that asking here would give me a quick shortcut :)

  • Hi Jarmo, For most applications, the device will spend most of its time asleep (i.e. in sd_app_evt_wait). Taking the UART as an example, a well-written application will go to sleep during the transmission of each character if it has nothing else to do. So if you simply call STOPRX and STOPTX each time you reach "sd_app_evt_wait" in your main loop, with no consideration to what the UART is being used for, you will probably end up with an unusable UART. Instead, the UART driver should be written such that it calls STOPRX and STOPTX whenever it is done receiving or transmitting, respectively. Similar arguments go for other drivers. It is also worth mentioning that the different peripherals are not consistent in how they stop. For instance, the TWI peripheral has a "STOPPED" event that you need to wait for after calling the STOP task. The UART has no equivalent "STOPPED" event.

Related