CAF: Latch register for all button GPIOS are set when wakeup from deep sleep by single button press, making it impossible to know which button that did the wakeup

I used the Common Application Framework preview sample, with the following additions at end of prj.conf:

# Power management
CONFIG_PM_POLICY_APP=y
CONFIG_CAF_POWER_MANAGER=y
CONFIG_CAF_POWER_MANAGER_TIMEOUT=10
CONFIG_CAF_BUTTONS_PM_EVENTS=y
CONFIG_CAF_LEDS_PM_EVENTS=y

NCS 1.9.1 was used

The nrf52840dk then enters deep sleep after 10 seconds.

When I then perform a button wakeup, by clicking one of the DK buttons, then the GPIO LATCH bits for all 4 buttons are set.

I would expect that only the LATCH bit is set corresponding to the button that was pressed.

Since the LATCH bit is set for all four buttons, this makes it impossible to see the cause of wakeup.

Could this be a bug in the CAF Buttons module?

BTW: This issue was discovered when looking at the case in devzone.nordicsemi.com/.../how-to-detect-gpio-interrupt-source-from-deep-sleep , but using CAF and ncs instead

Parents
  • Seems to be a problem only when debugger is active.

    But to get the real button wakeup source, the latch can be read and cleared in

    PRE_KERNEL_1 hook before main() as shown in attached modified main.c

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    #include <event_manager.h>
    #include <device.h>
    
    #define MODULE main
    #include <caf/events/module_state_event.h>
    
    #include <logging/log.h>
    LOG_MODULE_REGISTER(MODULE);
    
    static volatile uint32_t g_wakeup_latch;
    static volatile uint32_t g_wakeup_latch_after_clear;
    
    static int detect_wakeup_latch(const struct device *dev)
    {
    	ARG_UNUSED(dev);
    
    	g_wakeup_latch = NRF_P0->LATCH;
    	// Reconfigure the button pins to reset condition before trying to clear the latch
    	NRF_P0->PIN_CNF[11] = 0x00000002;
    	NRF_P0->PIN_CNF[12] = 0x00000002;
    	NRF_P0->PIN_CNF[24] = 0x00000002;
    	NRF_P0->PIN_CNF[25] = 0x00000002;
    	NRF_P0->LATCH = NRF_P0->LATCH; // clear the latch
    	
    	// 3 dummy reads (needed according to errata)
    	(void)NRF_P0->LATCH;
    	(void)NRF_P0->LATCH;
    	(void)NRF_P0->LATCH;
    
    	g_wakeup_latch_after_clear = NRF_P0->LATCH;
    
    	return 0;
    }
    
    SYS_INIT(detect_wakeup_latch, PRE_KERNEL_1, 0);
    
    void main(void)
    {
    	LOG_INF("NRF_P0->LATCH, at wakeup = 0x%08x, after clear = 0x%08x", g_wakeup_latch, g_wakeup_latch_after_clear);
    
    	if (event_manager_init()) {
    		LOG_ERR("Event manager not initialized");
    	} else {
    		module_set_state(MODULE_STATE_READY);
    	}
    }
    

    Please note that the original issue is still present if running with debugger.

Reply
  • Seems to be a problem only when debugger is active.

    But to get the real button wakeup source, the latch can be read and cleared in

    PRE_KERNEL_1 hook before main() as shown in attached modified main.c

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    #include <event_manager.h>
    #include <device.h>
    
    #define MODULE main
    #include <caf/events/module_state_event.h>
    
    #include <logging/log.h>
    LOG_MODULE_REGISTER(MODULE);
    
    static volatile uint32_t g_wakeup_latch;
    static volatile uint32_t g_wakeup_latch_after_clear;
    
    static int detect_wakeup_latch(const struct device *dev)
    {
    	ARG_UNUSED(dev);
    
    	g_wakeup_latch = NRF_P0->LATCH;
    	// Reconfigure the button pins to reset condition before trying to clear the latch
    	NRF_P0->PIN_CNF[11] = 0x00000002;
    	NRF_P0->PIN_CNF[12] = 0x00000002;
    	NRF_P0->PIN_CNF[24] = 0x00000002;
    	NRF_P0->PIN_CNF[25] = 0x00000002;
    	NRF_P0->LATCH = NRF_P0->LATCH; // clear the latch
    	
    	// 3 dummy reads (needed according to errata)
    	(void)NRF_P0->LATCH;
    	(void)NRF_P0->LATCH;
    	(void)NRF_P0->LATCH;
    
    	g_wakeup_latch_after_clear = NRF_P0->LATCH;
    
    	return 0;
    }
    
    SYS_INIT(detect_wakeup_latch, PRE_KERNEL_1, 0);
    
    void main(void)
    {
    	LOG_INF("NRF_P0->LATCH, at wakeup = 0x%08x, after clear = 0x%08x", g_wakeup_latch, g_wakeup_latch_after_clear);
    
    	if (event_manager_init()) {
    		LOG_ERR("Event manager not initialized");
    	} else {
    		module_set_state(MODULE_STATE_READY);
    	}
    }
    

    Please note that the original issue is still present if running with debugger.

Children
Related