nrf desktop - how to add soft power off

Hi,

I'm using nRF Connect v2.1.0.

How can I add a soft power off to nrf_desktop with a gpio interrupt wakeup? It looks like all of the demo hardware uses disconnecting switches, where I have a dedicated GPIO input with a momentary button for powering on/off.

I used the simple button example to add power button detection to board.c, and I used the code from the system_off example to shut it down from within my button callback, but it just reboots and turns right back on. I also tried creating and submitting a power_down_event to send to the power manager (I tried both "power_down_event" and "force_power_down_event"), with the same result. I also tried calling the turn_board_off() function that was already in board.c, which didn't do much.

I thought maybe it was failing because I was shutting down from within my button ISR so I added a worker function that I kick off with k_work_reschedule from the ISR, and then submit the powerdown event from the worker function, but I get the same result. It turns off and right back on.

Thanks,

Glen

Parents
  • Hi Glen, 

    You can read the RESETREAS register at address 0x40000400 to know what trigger wakeup/reset. Most likely it would be wake up from system off. 

    Could you try testing what I did on a Dev Kit ? From what I could see when testing with the DK it worked fine, the device enter deep sleep until I pressed on Button 3 or 4. 

    Have you checked if P0.24 and P0.25 is not connected to anything pulling it down ? 

    How do you configure your GPIO_INPUT in device tree? Did you use any pull up /down internally/externally ? 

    If you can test on a devkit and if it work as expected, then it must be something in the difference in the hardware causing the issue. 

  • Hi Hung,

    I've continued to work on this and I've made some progress, but simply turning the device off and on is proving to me much harder than we imagined.

    The primary thing keeping it from going to sleep is the custom motion sensor that I added. I've just turned that off for the time being and I did get it to go to sleep - I'll figure out how to disable it for sleep mode, but now I'm fighting a related issue I'm hoping you can help me with.

    Our device has a full keyboard including a power button, and we want to use the power button to turn on and off, not every key on the keyboard. Right now, no matter what I do, I haven't been able to keep the other keys on the keyboard from waking the device up.

    I decided to just accept my failure to disable the wakeup interrupt for the row/column stuff and put in some code that would go immediately back to sleep when a button was pressed other than the power button - but that doesn't work either. When it's powered off and I press one of the normal keyboard buttons, the device wakes up, but my is_button_event() check doesn't get called. What's up with that?

    static bool app_event_handler(const struct app_event_header *aeh)
    {
    	static bool initialized;
    
    	if (is_button_event(aeh)) 
       {
          // Check to see if a keyboard button other than the power button has been pressed while we're off.
          // If so, go back to off mode.
    		if (m_keyboard_is_on == false)
          {
             k_work_reschedule(&worker, K_MSEC(20));	// This fires off a worker task that calls force_power_down
             return true;
          }
          return false;
    	}
    }	
    
    APP_EVENT_LISTENER(MODULE, app_event_handler);
    APP_EVENT_SUBSCRIBE_FIRST(MODULE, button_event);

    Instead it's hitting this part of that same app_event_handler as if it's starting up from scratch - which may make sense if 

    force_power_down takes it to it's in PM_STATE_SOFT_OFF:

    	if (is_module_state_event(aeh)) {
    		const struct module_state_event *event = cast_module_state_event(aeh);
    
    		if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
    			__ASSERT_NO_MSG(!initialized);
    			initialized = true;
    
    			turn_board_on();
    

    I asked my customer if they were OK with using the power button to go to sleep and any key to wake up, and they said no - so I have to find a way to solve this problem. Any ideas?

    I have a partial solution going, but it's not great. I am forcing it into PM_STATE_SOFT_OFF and then when I get into main the very first thing I do it check to see if the button is still held, and only allow the device to power up if so (if not I jump back to SOFT_OFF), but it takes about a second to boot up from that state, so you have to hold down the power button for a second to get it to power up and the LEDs on the board flash on briefly during the boot process, so you can see a flicker every time you press a wrong button that shouldn't wake it up.

    Thanks for your help,

    Glen

  • Here's the current state of things. I have gotten pretty decent power-off behavior with this code, and a check first-thing in main() to see if they are holding down the power button for my wakeup (if not then I jump straight back to PM_STATE_SOFT_OFF):

       force_power_down();		// This puts the device into the suspended state
       k_sleep(K_MSEC(1200));  // Wait longer than 1 second to make sure the system gets the power off event, which it checks for every 1 second
       pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0}); // Force a hard off where the interrupt wakeup resets the processor

    With the >1s delay, the system has time to send the force power down event around and get itself set up for sleep, and then the pm_state_force seems to do a good job of fully shutting it down.

    Now my only issue is that it takes so long to wake up from PM_STATE_SOFT_OFF that in order to determine that it was the power button that woke us up that I have to hold the power button for about a second to get it to successfully turn on. This might be acceptable - we'll see what the customer says.

    I would still love it if I could get all interrupt sources except for my power button line disabled (power button is on its own pin... it's not in the keyboard matrix), but so far I've been unsuccessful at that.

  • Hello Glen, and sorry about the wait.

    Hung is on parental leave at the moment, so I'll be taking over this case. 

    I'm actually also finding it difficult getting only certain buttons to wake-up the board. CAF is doing a lot automatically, and can be a bit confusing at times. I've contacted the relevant R&D team to hear what they would recommend. I'll let you know once I hear from them.

    Regards,

    Elfving

  • Hello again, and hope you've had a good weekend.

    I had a talk with the R&D team responsible for nRF Desktop. It seems that the issue is that the CAF buttons module is being used, and it does not have selective wake up implemented at this point - any button press would wake up the system (see the callback_ctrl function implementation to check how GPIO interrupts are set up). You can also check how CAF buttons reacts on power down and wake up events and check the power management events documentation for further details (CAF buttons docCAF power management events). 

    If we want to allow waking up the system only by a given subset of buttons, we would need to slightly modify the implementation of CAF buttons module and add configuration for the subset of buttons.

    The team now has this on their to-do list, though I am not able to say anything about at what time they'll be able to finish this. (Though due to the summer vacation etc you should expect some delay).

    Glen M said:

    Now my only issue is that it takes so long to wake up from PM_STATE_SOFT_OFF that in order to determine that it was the power button that woke us up that I have to hold the power button for about a second to get it to successfully turn on. This might be acceptable - we'll see what the customer says.

    Hopefully this will be an acceptable workaround for both you and your customer in the meantime. 

    Regards,

    Elfving

  • Thanks Elfving - if I wanted to fiddle with the CAF buttons files myself, is there a way to make a local copy in my project and have the library use my version - or would I need to edit the files in the Zephyr library?

Reply Children
Related