This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Best pratice to detect pin changes with high reliability?

Hello there.

I´m using a Taiyo Yuden evaluation board with a nRF51422 to connect with 3 different sensors. In addition to that there are also 2 buttons connected to the eval board. The collected data get´s sent over UART. I used the app_uart_c example to implement my code.

Now i have problems to recognize every button press. This seems to me related to the softdevice. I modified the bsp code which works so far but sometimes i only manage to execute the event handler every second press. Searching for any issues i decided to first initialize the ble stack to start the lf clk and after initialize the timer which in my feeling was an improvement in the response. However the result is not satisfying for me. I rather don´t want to miss any button press. Is there a solution that can handle pin change interrupts and softdevice reliable at the same time?

  • Could you share your project so I can have a look? Or a project where this is reproducible?

  • My basic project is the ble_app_c example and modified it. I use the arm5_no_packs from the pca10028 board project.

    Dropbox Project Link

    I don´t know if the call of ble_stack_init before the APP_TIMER_INIT hat any effect because i found out that the buttons were slightly damaged during soldering. However with new buttons the problem still exists and i must not miss a falling edge when i received a rising edge.

  • I don't think calling ble_stack_init before APP_TIMER_INIT matters.

    The app button library uses the GPIOTE driver in low accuracy/low power mode. In this mode the PORT event/interrupt is used to sense level changes on the pin. With the app button library the PORT event is triggered every time a pin toggles. It is not very accurate, and cannot be used to track high speed pin changes.

    When you get the PORT event you do not know which pin that generated the event (unless you only have activated one pin), which means that you have to read the state of pins when you get this event. This means that if the PORT event is not handled quickly enough the state of the pins might actually have changed again.

    Until the event is handled the event can't be triggered again, and all changes will be lost.

    I see in your project that the priority of the GPIOTE interrupt (GPIOTE_CONFIG_IRQ_PRIORITY) is set to 3 (APP_IRQ_PRIORITY_LOW). This means that any interrupts with higher priority will be handled first, which means that you potentially lose more changes. You can try to change it to APP_IRQ_PRIORITY_HIGH, see if that helps, but you will not be able to high priority SoftDevice interrupts.

    If not, I think you need to look into using the IN events instead of the PORT event. If you have two buttons you can tie these to two IN events. Then you will at least know what pin that triggered the event.

    You are still vulnerable to losing changes on the same pin if the IN event for that pin is not handled quickly enough. Then I think you need to do something like what is discussed here.

  • Ok thanks for your help.

    The APP_IRQ_PRIORITY doesn´t solve the problem but the IN events do. But now i face new issues with the pin value.

    I stick to the code of the pin_change_int example. When the pin is configered to TOGGLE i don´t know the value and just toggling my bit is not a solution. Reading the pin value in the event handler with nrf_drv_gpiote_in_is_set returns me sometimes the wrong state or doesn´t seem to be accurate However also if i only configure it to detect rising edges i get events on the falling edge.

    So how to handle this? First, how can i set up two events (one for LOTOHI and HITOLO) for one pin or how do i get the pin value on TOGGLE?

    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    
    	switch (pin)
    	
    		case BSP_BUTTON_0:
    			button_0 = nrf_drv_gpiote_in_is_set(BSP_BUTTON_0);		
    			break;
    		case BSP_BUTTON_1:
    			button_1 = nrf_drv_gpiote_in_is_set(BSP_BUTTON_1);
    			break;
    	
    	button_update = true;
    
    static void gpio_init(void)
    
    ret_code_t err_code;
    
    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    in_config.pull = NRF_GPIO_PIN_PULLUP;
    
    err_code = nrf_drv_gpiote_in_init(BSP_BUTTON_0, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);
    
    	err_code = nrf_drv_gpiote_in_init(BSP_BUTTON_1, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_gpiote_in_event_enable(BSP_BUTTON_0, true);
    	nrf_drv_gpiote_in_event_enable(BSP_BUTTON_1, true);
    

    P.S.: I left out the brackets because they corrupt the highlighting of the code

  • You receive events on falling edge when you configure LOTOHI?

    First, how can i set up two events (one for LOTOHI and HITOLO) for one pin This is discussed here.

    how do i get the pin value on TOGGLE I don't know of any way that guarantees that the pin value is correct, when the the interrupt is not handled instantly.

Related