HERE is the fix for this problem. It has been reported before (by others) with no reply. I hope that this fix or its equivalent will be incorporated into the next SDK release so that others will avoid having to debug and fix this themselves.
File: app_button.c
* Button depression (press & release) for shorter than the debounce timeout, * will cancel the debounce of any other buttons that are in progress. * Root Cause: * Debounce timer is mistakenly stopped uppon the detection of a * glitch while other button debounce is active. * Function: * gpiote_event_handler()
static void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { uint32_t err_code; uint32_t pin_mask = 1 << pin; NRF_LOG_DEBUG("gpiote_event_handler:"); // Start detection timer. If timer is already running, the detection period is restarted. // NOTE: Using the p_context parameter of app_timer_start() to transfer the pin states to the // timeout handler (by casting event_pins_mask into the equally sized void * p_context // parameter). if (!(m_pin_transition & pin_mask)) { // First edge for button err_code = app_timer_stop(m_detection_delay_timer_id); if (err_code != NRF_SUCCESS) { // The impact in app_button of the app_timer queue running full is losing a button press. // The current implementation ensures that the system will continue working as normal. return; } if (nrf_drv_gpiote_in_is_set(pin)) { m_pin_state |= pin_mask; } else { m_pin_state &= ~(pin_mask); } m_pin_transition |= (pin_mask); NRF_LOG_DEBUG("app_timer_stop/start:"); err_code = app_timer_start(m_detection_delay_timer_id, m_detection_delay, NULL); if (err_code != NRF_SUCCESS) { // The impact in app_button of the app_timer queue running full is losing a button press. // The current implementation ensures that the system will continue working as normal. } } else { // Second edge for button // press shorter than debounce time ... ignore m_pin_transition &= ~pin_mask; // If no other pending debounce edges, stop timer if (m_pin_transition == 0) { NRF_LOG_DEBUG("app_timer_stop:"); (void)app_timer_stop(m_detection_delay_timer_id); } } }