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

nRF52832 Custom Board Pin In Use By GPIOTE Fault in BSP

Hi, 

I am trying to build out a button pressing scheme for BSP on a custom device with 15 buttons operating on a BL652 Laird Module (underlying nRF52832). After modifying the BOARD_PCA10040.h file to a custom one with our buttons (15) and leds (2), I've been able to get the LED initialization working provided I have defined my BUTTONS_NUMBER to 11 or less (not sure why). The LED indications change based on connecting and disconnecting to the BLE device, so that part works. However, when I increase the 'GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS' to 15 in the sdk_config.h file for our 15 buttons I get a hard fault. 

// <e> GPIOTE_ENABLED - nrf_drv_gpiote - GPIOTE peripheral driver - legacy layer
//==========================================================
#ifndef GPIOTE_ENABLED
#define GPIOTE_ENABLED 1
#endif
// <o> GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins 
#ifndef GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS
#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 15
#endif

I've traced the hard fault through the following areas of code and found that the fault is due to a pin (I think P0.14) being used twice (one for my button and one for something else 'maybe TRACE'). 

1. First - buttons_led_init  (found in main.c)

static void buttons_leds_init(bool * p_erase_bonds)
{
    ret_code_t err_code;
    bsp_event_t startup_event;

    err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_btn_ble_init(NULL, &startup_event);
    APP_ERROR_CHECK(err_code);

    *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
}

2. Second - bsp_init   (found in bsp.c)

uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback)
{
    uint32_t err_code = NRF_SUCCESS;

#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
    m_indication_type     = type;
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)

#if (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)
    m_registered_callback = callback;

    // BSP will support buttons and generate events
    if (type & BSP_INIT_BUTTONS)
    {
        uint32_t num;

        for (num = 0; ((num < BUTTONS_NUMBER) && (err_code == NRF_SUCCESS)); num++)
        {
            err_code = bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);
        }

        if (err_code == NRF_SUCCESS)
        {
            err_code = app_button_init((app_button_cfg_t *)app_buttons,
                                       BUTTONS_NUMBER,
                                       APP_TIMER_TICKS(50));
        }

        if (err_code == NRF_SUCCESS)
        {
            err_code = app_button_enable();
        }

        if (err_code == NRF_SUCCESS)
        {
            err_code = app_timer_create(&m_bsp_button_tmr,
                                        APP_TIMER_MODE_SINGLE_SHOT,
                                        button_timer_handler);
        }
    }
#elif (BUTTONS_NUMBER > 0) && (defined BSP_SIMPLE)
    bsp_board_init(type);
#endif // (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)

#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)
    if (type & BSP_INIT_LEDS)
    {
      //handle LEDs only. Buttons are already handled.
      bsp_board_init(BSP_INIT_LEDS);

      // timers module must be already initialized!
      if (err_code == NRF_SUCCESS)
      {
          err_code =
              app_timer_create(&m_bsp_leds_tmr, APP_TIMER_MODE_SINGLE_SHOT, leds_timer_handler);
      }

      if (err_code == NRF_SUCCESS)
      {
          err_code =
              app_timer_create(&m_bsp_alert_tmr, APP_TIMER_MODE_REPEATED, alert_timer_handler);
      }
    }
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)

    return err_code;
}

3. Third - app_button_init   (found in app_button.c)

uint32_t app_button_init(app_button_cfg_t const *       p_buttons,
                         uint8_t                        button_count,
                         uint32_t                       detection_delay)
{
    uint32_t err_code;

    if (detection_delay < APP_TIMER_MIN_TIMEOUT_TICKS)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

    if (!nrf_drv_gpiote_is_init())
    {
        err_code = nrf_drv_gpiote_init();
        VERIFY_SUCCESS(err_code);
    }

    // Save configuration.
    mp_buttons          = p_buttons;
    m_button_count      = button_count;
    m_detection_delay   = detection_delay;

    m_pin_state      = 0;
    m_pin_transition = 0;

    while (button_count--)
    {
        app_button_cfg_t const * p_btn = &p_buttons[button_count];

#if defined(BUTTON_HIGH_ACCURACY_ENABLED) && (BUTTON_HIGH_ACCURACY_ENABLED == 1)
        nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(p_btn->hi_accuracy);
#else
        nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
#endif
        config.pull = p_btn->pull_cfg;

        err_code = nrf_drv_gpiote_in_init(p_btn->pin_no, &config, gpiote_event_handler);
        VERIFY_SUCCESS(err_code);
    }

    // Create polling timer.
    return app_timer_create(&m_detection_delay_timer_id,
                            APP_TIMER_MODE_SINGLE_SHOT,
                            detection_delay_timeout_handler);
}

4. Finally (Fault Here) - nrfx_gpiote_in_init  (found in nrfx_gpiote.c)

nrfx_err_t nrfx_gpiote_in_init(nrfx_gpiote_pin_t               pin,
                               nrfx_gpiote_in_config_t const * p_config,
                               nrfx_gpiote_evt_handler_t       evt_handler)
{
    NRFX_ASSERT(pin < NUMBER_OF_PINS);
    nrfx_err_t err_code = NRFX_SUCCESS;

    /* Only one GPIOTE channel can be assigned to one physical pin. */
    if (pin_in_use_by_gpiote(pin))
    {
        err_code = NRFX_ERROR_INVALID_STATE;
    }
    else
    {
        int8_t channel = channel_port_alloc(pin, evt_handler, p_config->hi_accuracy);
        if (channel != NO_CHANNELS)
        {
            if (!p_config->skip_gpio_setup)
            {
                if (p_config->is_watcher)
                {
                    nrf_gpio_cfg_watcher(pin);
                }
                else
                {
                    nrf_gpio_cfg_input(pin, p_config->pull);
                }
                pin_configured_set(pin);
            }

            if (p_config->hi_accuracy)
            {
                nrf_gpiote_event_configure((uint32_t)channel, pin, p_config->sense);
            }
            else
            {
                m_cb.port_handlers_pins[channel -
                                        GPIOTE_CH_NUM] |= (p_config->sense) << SENSE_FIELD_POS;
            }
        }
        else
        {
            err_code = NRFX_ERROR_NO_MEM;
        }
    }

    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

Specifically the fault happens in the following with the following images showing the local variables, etc. information.

    /* Only one GPIOTE channel can be assigned to one physical pin. */
    if (pin_in_use_by_gpiote(pin))
    {
        err_code = NRFX_ERROR_INVALID_STATE;
    }

 

I've changed my clock configuration to the following for use in a BL652 and verified that I am not attempting to use high accuracy interrupts as described in the following link. 

// </h> 
//==========================================================

// <h> Clock - SoftDevice clock configuration

//==========================================================
// <o> NRF_SDH_CLOCK_LF_SRC  - SoftDevice clock source.
 
// <0=> NRF_CLOCK_LF_SRC_RC 
// <1=> NRF_CLOCK_LF_SRC_XTAL 
// <2=> NRF_CLOCK_LF_SRC_SYNTH 

#ifndef NRF_SDH_CLOCK_LF_SRC
#define NRF_SDH_CLOCK_LF_SRC 0
#endif

// <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval. 
#ifndef NRF_SDH_CLOCK_LF_RC_CTIV
#define NRF_SDH_CLOCK_LF_RC_CTIV 16
#endif

// <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature. 
// <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated
// <i>  if the temperature has not changed.

#ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV
#define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 2
#endif

// <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.
 
// <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
// <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
// <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
// <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
// <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
// <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
// <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
// <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
// <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
// <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
// <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
// <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 

#ifndef NRF_SDH_CLOCK_LF_ACCURACY
#define NRF_SDH_CLOCK_LF_ACCURACY 7
#endif

https://devzone.nordicsemi.com/f/nordic-q-a/35205/setting-xl1-xl2-as-gpio-does-not-work

What am I missing? Is there some other setting for P0.14 (likely in a TRACEDATA setting)? Is there some other sdk_config.h settings, or other build settings that need to be setup?

Thanks for the help!

  • Worth checking these (slightly confusing) mappings, as Button 1 isn't ..:

    #define BUTTON_2        14
    #define SPIM2_MISO_PIN  14  // SPI Master In Slave Out GPIO pin number.
    #define ARDUINO_3_PIN   14  // Digital pin 3
    
    #define #define BSP_BUTTON_1   BUTTON_2
    BUTTONS_LIST       { BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 }

    There are a few others worth reviewing:

    #define BSP_BOARD_BUTTON_2 2
    
    #ifdef BSP_BUTTON_2
    #define BSP_BUTTON_2_MASK (1<<BSP_BUTTON_2)
    #define BUTTON_CAPSLOCK   BSP_BUTTON_2_MASK
    
    #define BTN_ID_WAKEUP             0  /**< ID of button used to wake up the application. */
    #define BTN_ID_SLEEP              0  /**< ID of button used to put the application into sleep mode. */
    #define BTN_ID_DISCONNECT         0  /**< ID of button used to gracefully terminate a connection on long press. */
    #define BTN_ID_WAKEUP_BOND_DELETE 1  /**< ID of button used to wake up the application and delete all bonding information. */
    #define BTN_ID_WHITELIST_OFF      1  /**< ID of button used to turn off usage of the whitelist. */

    Since Button 1 is really button 2 fiddling with (say) the whitelist can have unexpected pin assignments .. I was confused, if I recall ..

  • Hi,

    I see the confusion you were having with the naming of the buttons (i.e. #define BSP_BUTTON_1 BUTTON_2). However, in my program I'm defining my buttons in a very specific way (i.e. #define BSP_BUTTON_12 PN_BT) so I don't think there would be any issues there. As well as the file where the definition of buttons happens (bsp_btn_ble.c) as far as I can tell doesn't get called at all yet at the point of failure. 

    It seems like the issue has more to do with GPIOTE Channels and their limitations, but I'm not sure how I can modify to support more than 8 since the documentation states the following:

    "Only one GPIOTE channel can be assigned to one physical pin. Failing to do so may result in unpredictable behavior."

    https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fgpiote.html

    Or is the GPIOTE channels just the way to be able to deal with GPIO tasks and events? I see there is some more documentation regarding Port Events (PORT is an event that can be generated from multiple input pins using the GPIO DETECT signal.). 

    Does anyone know if it's possible to modify the BSP functionality to support more than 8 buttons? In this case 15? Is there a way to modify the BSP functions to support Port Events (if this is the way that is required for more I/O)? If so how would this be done?

    Thanks!

  • Fire up! I figured out the issue. Similar to your original suggestion, just in a different location. Simple, but still difficult to find. When I redefined the BSP_BUTTON_# for all 15 of my buttons, I accidentally defined the failing button as the following. 

       #ifdef BSP_BUTTON_10
        {BSP_BUTTON_11, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_10

    The correct definition (in bsp.c) should be as follows for more buttons. 

    #ifndef BSP_SIMPLE
    static const app_button_cfg_t app_buttons[BUTTONS_NUMBER] =
    {
        #ifdef BSP_BUTTON_0
        {BSP_BUTTON_0, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_0
    
        #ifdef BSP_BUTTON_1
        {BSP_BUTTON_1, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_1
    
        #ifdef BSP_BUTTON_2
        {BSP_BUTTON_2, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_2
    
        #ifdef BSP_BUTTON_3
        {BSP_BUTTON_3, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_3
    
        #ifdef BSP_BUTTON_4
        {BSP_BUTTON_4, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_4
    
        #ifdef BSP_BUTTON_5
        {BSP_BUTTON_5, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_5
    
        #ifdef BSP_BUTTON_6
        {BSP_BUTTON_6, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_6
    
        #ifdef BSP_BUTTON_7
        {BSP_BUTTON_7, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_7
    
        #ifdef BSP_BUTTON_8
        {BSP_BUTTON_8, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_8
    
        #ifdef BSP_BUTTON_9
        {BSP_BUTTON_9, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_9
    
        #ifdef BSP_BUTTON_10
        {BSP_BUTTON_10, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_10
    
        #ifdef BSP_BUTTON_11
        {BSP_BUTTON_11, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_11
    
        #ifdef BSP_BUTTON_12
        {BSP_BUTTON_12, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_12
    
        #ifdef BSP_BUTTON_13
        {BSP_BUTTON_13, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_13
    
        #ifdef BSP_BUTTON_14
        {BSP_BUTTON_14, false, BUTTON_PULL, bsp_button_event_handler},
        #endif // BUTTON_14
    
    };

    This at least got me past that error, going to start testing the rest of it now.

Related