NCS: button press event configuration takes too much current

Dear Support Team,

I realized that the callback on button press event takes about 11 µA, as reported by PPK2 & nRF52-DK with the code summarized below.

Indeed, the current absorption switches from ~8 µA to ~19 µA when the button callback is configured.

Any help ?

thank you, Paolo

main.c

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/pm/device.h>

#define BUTTON_NODE						DT_NODELABEL(button)
static const struct gpio_dt_spec		button_spec = GPIO_DT_SPEC_GET(BUTTON_NODE, gpios);
static struct gpio_callback			button_cb;

static void button_pressed_callback(const struct device	*gpiob,
												struct gpio_callback *cb,
												gpio_port_pins_t		pins)
{
	LOG_INF("user button pressed");
}

int main(void)
{
	while (1)
	{
		// user button
		gpio_pin_configure_dt(&button_spec, GPIO_INPUT);
		gpio_pin_interrupt_configure_dt(&button_spec, GPIO_INT_EDGE_FALLING);
		gpio_init_callback(&button_cb, button_pressed_callback, BIT(button_spec.pin));
		gpio_add_callback_dt(&button_spec, &button_cb);

		k_msleep(5000);

		gpio_remove_callback_dt(&button_spec, &button_cb);
		gpio_pin_interrupt_configure_dt(&button_spec, GPIO_INT_DISABLE);

		k_msleep(5000);
	}

	return 0;
}

board.overlay

/ {
	inputs {
		compatible = "gpio-keys";
		button: button {
			gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
		};
	};
};

  • Hi Paolo,

    Sorry, I haven't had time to look at your case. We are entering our summer vacation period where we have less staffing than usual. I''ll try to get you help as soon as I can.

    Best regards,

    Raoul

  • Hi Paolo,

    The increased current consumption you are seeing is correct. Your interrupt is configured to occur on a rising edge, which means that the GPIOTE (GPIO Tasks and Events) peripheral is enabled. Using GPIOTE increases the sleep current consumption - this scenario in the nRF52840 shows it well:

    https://infocenter.nordicsemi.com/topic/ps_nrf52840/_tmp/nrf52840/autodita/CURRENT/parameters.i_sleep.html?cp=5_0_0_4_1_0_0

    Look at "System ON, full 256 kB RAM retention, wake on GPIOTE input (event mode)". It approximately matches your measurement.

    Switching to level detection instead of edge detection, will improve things. Please look at the following case:  NCS Low Power Button Press/Release Detection

    Best regards,

    Raoul

  • Hi Raoul,

    You must know that I'm porting to NCS an application written with SDK v17.1.0, and the increased current consumption after gpiote configuration was not present before.

    Pls find attached the source code of a testapp, under SDK v17, with gpiote configuration and the current consumption reported from PPK2 as a zip file. Same board, same processor: delta current in this scenario is less than 1 µA  !!!!

    Let me know,

    thank you, Paolo

    #include <nrf.h>
    #include <nrf_log.h>
    #include <nrf_log_ctrl.h>
    #include <nrf_log_default_backends.h>
    
    #include <nrf_drv_gpiote.h>
    
    #include <app_timer.h>
    #include <nrf_sdh.h>
    #include <nrf_sdh_ble.h>
    
    
    #define BTN_USER_PIN			11
    #define SIGNAL_PIN				12
    
    APP_TIMER_DEF(m_timer_id);
    
    #define APP_TIMER_INTERVAL		APP_TIMER_TICKS(5000)
    
    
    //	----------------------------------------------------------------------------
    	static void power_manage(void)
    //	----------------------------------------------------------------------------
    {
    	uint32_t err_code = sd_app_evt_wait();
    	APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Callback function for asserts in the SoftDevice.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyze
     *		  how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num   Line number of the failing ASSERT call.
     * @param[in] file_name  File name of the failing ASSERT call.
     */
    //	---------------------------------------------------------------------------
    	void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    //	---------------------------------------------------------------------------
    {
    	app_error_handler(0xDEADBEEF, line_num, p_file_name);
    }
    
    /**
      * @brief  This function handles Hard Fault exception.
      * @param  None
      * @retval None
      */
    void HardFault_Handler(void)
    {
    	/* Sistem Reset when Hard Fault exception occurs */
    	sd_nvic_SystemReset();
    }
    
    //	---------------------------------------------------------------------------
    	static void log_init(void)
    //	---------------------------------------------------------------------------
    {
    	APP_ERROR_CHECK( NRF_LOG_INIT(app_timer_cnt_get) );
    	NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    //	---------------------------------------------------------------------------
    	static void gpiote_event_handler(nrf_drv_gpiote_pin_t		pin,
    												nrf_gpiote_polarity_t	action)
    //	---------------------------------------------------------------------------
    {
    	switch (pin)
    	{
    		case BTN_USER_PIN:
    			NRF_LOG_INFO("button pressed!");
    			break;
    	}
    }
    
    //	---------------------------------------------------------------------------
    	void timer_handler(void *p_context)
    //	---------------------------------------------------------------------------
    {
    	UNUSED_PARAMETER(p_context);
    	
    	static int mode = 0;
    	mode = 1 - mode;
    
    	if (mode)
    	{
    		// enable
    		nrf_gpio_pin_clear(SIGNAL_PIN);
    		nrf_drv_gpiote_in_config_t btn_user_pin = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);
    		int err_code = nrf_drv_gpiote_in_init(BTN_USER_PIN, &btn_user_pin, gpiote_event_handler);
    		APP_ERROR_CHECK(err_code);
    		nrf_drv_gpiote_in_event_enable(BTN_USER_PIN, true);
    	}
    	else
    	{
    		// disable
    		nrf_gpio_pin_set(SIGNAL_PIN);
    		nrf_drv_gpiote_in_event_disable(BTN_USER_PIN);
    		nrf_drv_gpiote_in_uninit(BTN_USER_PIN);
    	}
    }
    
    //	----------------------------------------------------------------------------
    	void timer_init(void)
    //	----------------------------------------------------------------------------
    {
    	NRF_LOG_INFO("timer_init()");
    
    	// Initialize timer module
    	uint32_t err_code = app_timer_init();
    	APP_ERROR_CHECK(err_code);
    }
    
    //	----------------------------------------------------------------------------
    	void timers_config(void)
    //	----------------------------------------------------------------------------
    {
    	NRF_LOG_INFO("timers_config()");
    
    	// Create System timer
    	uint32_t err_code = app_timer_create(&m_timer_id,
    													 APP_TIMER_MODE_REPEATED,
    													 timer_handler);
    	APP_ERROR_CHECK(err_code);
    
    	// Start System timer
    	err_code = app_timer_start(m_timer_id,
    										APP_TIMER_INTERVAL,
    										NULL);
    	APP_ERROR_CHECK(err_code);
    }
    
    //	---------------------------------------------------------------------------
    	void ble_stack_init(void)
    //	---------------------------------------------------------------------------
    {
    	NRF_LOG_INFO("ble_stack_init()");
    	
    	uint32_t err_code = nrf_sdh_enable_request();
    	APP_ERROR_CHECK(err_code);
    
    	// Configure the BLE stack using the default settings.
    	// Fetch the start address of the application RAM.
    	uint32_t ram_start = 0;
    	err_code = nrf_sdh_ble_default_cfg_set(1, &ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	// Enable BLE stack.
    	err_code = nrf_sdh_ble_enable(&ram_start);
    	APP_ERROR_CHECK(err_code);
    }
    
    //	---------------------------------------------------------------------------
    	int main(void)
    //	---------------------------------------------------------------------------
    {
    	log_init();
    	timer_init();
    	timers_config();
    	ble_stack_init();
    
    	int err_code = nrf_drv_gpiote_init();
    	APP_ERROR_CHECK(err_code);
    
    	nrf_gpio_cfg_output(SIGNAL_PIN);
    
    	for (;;)
    	{
    		power_manage();
    	}
    }
    

    gpiote on sdk17 (nRF52-DK).ppk..7z

  • Hi Paolo, thank you for sharing.

    I'll have to hand this over to a colleague, who will continue the case shortly. Sorry for the inconvenience - as mentioned, the summer weeks are busier than usual.

    Best regards,

    Raoul

  • Hi,

    Can you set the sense-edge-mask property in the board overlay file for the GPIO, like this?

    &gpio0 {
    	sense-edge-mask = <0x800>; /* 1 << 11 for P0.11 */
    };

    This should make sure that the pin interrupt is configured using GPIOTE PORT event and not the higher current/accuracy GPIOTE IN event.

    Best regards,
    Jørgen

Related