Long Press Button Interrupt in NCS

Hi, I am working on long press button interrupt in nrf52832 device & used NCS. I am unable to detect the long press from button.below is my functionality which is I am trying to implement.
 

press for 10 sec after that call a callback function.

void long_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
   // if (gpio_pin_get_dt(&button_0)) {
    if(pins & BIT(button_0.pin)){
        LOG_INF("button pin detected");
        k_timer_start(&button_timer, K_SECONDS(10), K_NO_WAIT);
    } else {
        LOG_INF("long_press not detected");
        k_timer_stop(&button_timer);
        long_press_detected = false;  // Reset flag if button is released
    }
}

void button_timer_expiry_handler(struct k_timer *timer_id)
{
    printk("Button long-pressed for 10 seconds\n");
    long_press_detected = true;
    Reset_Flag=1;
    eeprom_write(i2c_dev,EEPROM_RESET_FLAG_ADDRESS, &Reset_Flag, 1);
    eeprom_write(i2c_dev,EEPROM_RESET_TIME_FLAG, &current_epoch_time, 4);
    guide_flag=1;
    eeprom_write(i2c_dev,EEPROM_DEVICE_GUIDE_ADDRESS,&guide_flag,1);
    reset_hardware_locally();
    //reset_hardware();
    k_msleep(1000);
    NVIC_SystemReset();
    // Add your action here
}

void long_press_button(){
    if (!device_is_ready(button_0.port)) {
        printk("Button device not ready\n");
        return;
    }
    gpio_init_callback(&button_cb_data,long_button_pressed, BIT(button_0.pin));
    gpio_add_callback(button_0.port, &button_cb_data);

    k_timer_init(&button_timer, button_timer_expiry_handler, NULL);

}

above is the code of long press button.

Pin configuration :-

gpio_pin_configure_dt(&button_0, GPIO_INPUT);
gpio_pin_interrupt_configure_dt(&button_0, GPIO_INT_EDGE_BOTH);
configuration in overlay file:-
button0
{
gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
label = "SW1";
};
Suggest a solution how can implement long press button interrupt in zephyr ncs.
Parents Reply
  • The easiest is probably to strip down your application so it can just reproduce your issue without having any sensitive information, and you can upload it here. So e.g. if you are able to reproduce the issue without the eeprom parts, then perhaps you can strip down that part, basically remaining only the components for the button, the timer, and see if it still fails. If so, you can upload it here. It shouldn't hold any sensitive information.

    If you need to create a private ticket, that is pretty much the same way that you created this ticket, but I believe you need to fill your profile with a bit more information first. It should say what you need when you try to create a private ticket. 

    Best regards,

    Edvin

Children
  • long_press.zip

    Hi I have uploaded my application here, let me know if you faced any issue in test. it is without any sensitive information.

  • Thank you. I believe my behavior was a bit different than yours, but we are running this on different hardware, so that may be why. 

    In my case, I was not able to trigger the interrupt, because I shorted the pin to a button pin, and your button_0 devicetree configuration didn't have a pullup. So first, I added this in your test.overlay:

        buttons {
            compatible = "gpio-keys";
            button0
            {
                gpios = <&gpio0 21 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "SW1";
            };
        };  
    };

    Then I changed your bsp_button_init() to trigger on both rising and falling edges (like you originally had when you created this ticket):

    void bsp_button_init(){
    
        uint8_t ret;
    
        if(!device_is_ready(button_0.port)){
            LOG_INF("button init failed");
        }
    
        // configure button gpio as input
        ret = gpio_pin_configure_dt(&button_0, GPIO_INPUT);
        if (ret < 0) {
            return;
        }
        //ret = gpio_pin_interrupt_configure_dt(&button_0, GPIO_INT_EDGE_RISING);
        ret = gpio_pin_interrupt_configure_dt(&button_0, GPIO_INT_EDGE_BOTH);
        if (ret < 0) {
            return;
        }
    
    }

    And finally, I adjusted your long_button_pressed() callback to check the state of the pin, starting the timer only if it was pressed, and stopping the timer if it was not pressed (which would have been triggered by a release action):

    void long_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {
       // if (gpio_pin_get_dt(&button_0)) {
        if(pins & BIT(button_0.pin)){
            int val = gpio_pin_get_dt(&button_0);
            LOG_INF("button pin detected %08x, val %d", pins, val);
            if (val == 1) { // if (val) { 
                k_timer_start(&button_timer, K_SECONDS(10), K_NO_WAIT);
                LOG_INF("Timer started");
            }
            else {
                k_timer_stop(&button_timer);
                long_press_detected = false;
                LOG_INF("Timer stopped");
            }
        }
    }

    Also added some logging in that callback, as you can see. 

    Please note:

    For testing this is of course ok, but for HW specific .overlays, the "best practice" is to create a folder called boards in your application root folder, and then create an overlay file called "<board_name>.overlay" in there. This will automatically be picked up by the compiler. 

    For application specific overlays, the common practise is to have a file called "app.overlay". This should hold the devicetree configurations that are common for all boards. I'll add an empty nrf52840dk_nrf52840.overlay in a boards folder, just so that you see what I mean. But this is just formalities, and the way we do it in our samples. You decide how to build up your app. 

    long_press_v2.zip

    Give it a go, and let me know if it doesn't work.

    Best regards,

    Edvin

  • Thank you. It's also work for me. got print from button_timer_expiry_handler.

    "Button long-pressed for 10 seconds\n"

    but it working when I change pin number of button. I have custom nrf52832 board and button is connected with reset pin. I have attached a schematic of reset pin and button.

    what will be pin configuration according to above image?? Is zephyr support dual functionality??

    one more question is that can I use zephyr - long press instead of timer??
    Sorry for the I shared lately about custom hardware.

Related