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

How do I interface low-latency pin change interrupts with the app_gpiote service?

Hello, before you say anything: "yes I have searched!" :D I found that this question was similar to mine How to write GPIOTE Interrupt

Now I am fairly certain that I can handle that part just fine, however here is when things get tricky. After stealing "GPIOTE_IRQHandler" from app_gpiote (removing app_gpiote and implementing the IRQHandler in my own module), the BLE softdevice would no longer start up. The error code provided was 0x0000001. Yes I looked it up, but wasn't able to glean any information from it.

When I subscribe using the standard

#define HAL_AFE_ADC_RDY_PIN 13
app_gpiote_user_id_t hGPIOTE = 0;
...
{
	err_code = app_gpiote_user_register(&hGPIOTE, (1 << HAL_AFE_ADC_RDY_PIN), 0x00000000, app_gpiote_event_handler);
	APP_ERROR_CHECK(err_code);
	err_code = app_gpiote_user_enable(hGPIOTE);
	APP_ERROR_CHECK(err_code);
}
...

I get latencies of up to 500 milliseconds in receiving the callback from this handler. The signal I need to detect is a logic level high pulse with 250 nanosecond width, active high. It is on pin 13.

My question is this: How do I use pin change interrupts correctly while still being able to use your bluetooth low energy softdevice?

Code dump below:


#include "nrf_gpio.h"
#include "app_gpiote.h"

#define HAL_AFE_ADC_RDY_PIN  13

app_gpiote_user_id_t hGPIOTE = 0;

void app_gpiote_event_handler(uint32_t event_pins_low_to_high, uint32_t event_pins_high_to_low)
{
	uint8_t i = 2;
	uint32_t k[] = {0, 0, 0, 0, 0, 0};
	
	event_pins_low_to_high++;
	event_pins_high_to_low++;
	i++;
	HalAfe_HW_ReadADC(k);
}

static void halAfe_ConfigIO(void)
{
  uint32_t err_code = 0;
  /* GPIO configuration */
	AFE_CONFIGURE_RESET();
	AFE_RELEASE_RESET();
	
  nrf_gpio_cfg_input(HAL_AFE_ADC_RDY_PIN, NRF_GPIO_PIN_NOPULL);
	err_code = app_gpiote_user_register(&hGPIOTE, (1 << HAL_AFE_ADC_RDY_PIN), 0x00000000, app_gpiote_event_handler);
	APP_ERROR_CHECK(err_code);
	err_code = app_gpiote_user_enable(hGPIOTE);
	APP_ERROR_CHECK(err_code);
}

Parents
  • Yes, your response led me to the solution as always. I had quoted you the wrong error code. I was only looking at nrf_error.h so I disregarded the NRF_ERROR_SDM_BASE_NUM portion.

    I'll add my notes to this post so I may be able to help others who encounter this issue. I ended up removing the app_gpiote service/driver/module from my project since we're working with very tight timing constraints and only have one external interrupt to process.

    With that out of the way, I found that I needed to re-order my code in order to 'play nicely' with the softdevice. That meant placing my configuration code after ble_stack_init() in the main() function since it contained calls prefixed with sd_.

    Code dump below:

    
    void GPIOTE_IRQHandler(void)
    {
        // Event causing the interrupt must be cleared.
        if ((NRF_GPIOTE->EVENTS_IN[0] == 1) && 
            (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk))
        {
            NRF_GPIOTE->EVENTS_IN[0] = 0;
    			
    				uint8_t i = 2;
    				uint32_t k[] = {0, 0, 0, 0, 0, 0};
    				
    				i++;
    				HalAfe_HW_ReadADC(k);
        }
    }
    
    static void halAfe_ConfigIO(void)
    {
      uint32_t err_code = 0;
    	AFE_CONFIGURE_RESET();
    	AFE_RELEASE_RESET();
    	
      nrf_gpio_cfg_input(HAL_AFE_ADC_RDY_PIN, NRF_GPIO_PIN_NOPULL);
    	
    	
    	NRF_GPIOTE->INTENSET  = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
    	nrf_gpiote_unconfig(0);
    	nrf_gpiote_event_config(0, HAL_AFE_ADC_RDY_PIN, NRF_GPIOTE_POLARITY_LOTOHI);
    	err_code = sd_nvic_SetPriority(GPIOTE_IRQn, 1);
      err_code = sd_nvic_EnableIRQ(GPIOTE_IRQn);
    }
    

    I found that either enabling the IRQ last was necessary but it may not be since I was erroneously trying to configure channel 1. I do not know if the NRF_GPIOTE->INTENSET operation is necessary.

    Thanks Ole!

  • Thanks, this saved my day. I had two almost identical codes, one was working, one was hardfaulting with err_code 0x1001. My problem was the UART interrupt priority which was not set, I needed to add NVIC_SetPriority(UART0_IRQn, APP_IRQ_PRIORITY_LOW);

Reply Children
No Data
Related