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

Using app_buttons with BSP buttons PLUS own buttons?

I am writing an application for the nRF52DK which uses two additional push buttons besides the 4 already present on the board.

Using GPIOTE the detection of the button press for the 2 new buttons (connected to pin 22 and 23) works as desired, however the buttons bounce a lot so I would need to write a debounce routine.

Browsing the devzone I saw that there is a library called app_buttons which is based on GPIOTE and seems to handle all of this automatically. However I could not clearly see if this library was ONLY for the existing buttons or whether I could just add some more pins/buttons to it.

As I didn't want to change SDK files, and especially not pca10040.h, bps.c, boards.c, etc. I copied the whole stuff in a new "bsp_and_custom_buttons.h/.c" and made the following dirty hack changes:

#ifdef BUTTONS_NUMBER
#define BUTTONS_NUMBER 6

#define BUTTON_5       22
#define BUTTON_6       23
#define TRAINER_BUTTON_INCLINE_UP BUTTON_5
#define TRAINER_BUTTON_INCLINE_DOWN BUTTON_6
#define BSP_BUTTON_5  BUTTON_5
#define BSP_BUTTON_6  BUTTON_6
#define BUTTON_STOP 23
#endif
..
static void incline_button_event_handler(uint8_t pin_no, uint8_t button_action);
..
#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 TRAINER_BUTTON_INCLINE_UP
    {BSP_BUTTON_5, false, BUTTON_PULL, incline_button_event_handler},
    #endif

    #ifdef TRAINER_BUTTON_INCLINE_DOWN  
    {BSP_BUTTON_6, false, BUTTON_PULL, incline_button_event_handler},
    #endif
...
static void incline_button_event_handler(uint8_t pin_no, uint8_t button_action)
{
	
	if(app_button_is_pushed(TRAINER_BUTTON_INCLINE_UP) == true)
	{
                        if (incline_level < 20)
                        {
                            incline_level++;
                        }
			NRF_LOG_INFO("Button TRAINER_BUTTON_INCLINE_UP got pressed! New incline: %d", incline_level);
			//nrf_delay_ms(500);
			
	}
  //code run on button state change
        if(app_button_is_pushed(TRAINER_BUTTON_INCLINE_DOWN) == true)
        {
                if (incline_level > 10)
                        {
                            incline_level--;
                        }
                NRF_LOG_INFO("Button TRAINER_BUTTON_INCLINE_DOWN got pressed! New incline: %d", incline_level);

        }
	
}
...

My button definition:

#ifdef BSP_BUTTON_5
{BSP_BUTTON_5, false, BUTTON_PULL, incline_button_event_handler},
#endif // BUTTON_5

#ifdef BSP_BUTTON_6
{BSP_BUTTON_6, false, BUTTON_PULL, incline_button_event_handler},
#endif // BUTTON_6

My event handler:

static void incline_button_event_handler(uint8_t pin_no, uint8_t button_action)
{
	
	if(app_button_is_pushed(4) == true)
	{
                        if (incline_level < 20)
                        {
                            incline_level++;
                        }
			NRF_LOG_INFO("Button TRAINER_BUTTON_INCLINE_UP got pressed! New incline: %d", incline_level);
			//nrf_delay_ms(500);
			
	}
  //code run on button state change
        if(app_button_is_pushed(5) == true)
        {
                if (incline_level > 10)
                        {
                            incline_level--;
                        }
                NRF_LOG_INFO("Button TRAINER_BUTTON_INCLINE_DOWN got pressed! New incline: %d", incline_level);

        }
	
}

In the end it actually WORKED but this feels so ugly as I basically have to overwrite #defines from the SDK BSP in order to get my extra buttons "into the game". 

However I didn't see any other chance in order to keep the existing BSP code for the buttons, LEDs, etc and getting my stuff in.

I'm pretty sure this is not the way it is meant to be?

Am I supposed to use the app_button library for arbitrary pins besides the existing 4 buttons on the DK52?

Is there a best practice how to do it?

Or should I better keep my hands of here and use the GPIOTE stuff directly but need to implement an debounce handler then myself?

  • Hi, Daubsi!

    You should be able to use the app_button library for any available pin. Looking at the header file definitions you have the app_button_cfg_t structure which enables configuration and instantiation of an arbitrary button connected to any available pin. It is defined as follows:

    /**@brief Button configuration structure. */
    typedef struct
    {
        uint8_t              pin_no;           /**< Pin to be used as a button. */
        uint8_t              active_state;     /**< APP_BUTTON_ACTIVE_HIGH or APP_BUTTON_ACTIVE_LOW. */
    #if defined(BUTTON_HIGH_ACCURACY_ENABLED) && (BUTTON_HIGH_ACCURACY_ENABLED == 1)
        bool                 hi_accuracy;      /**< True if GPIOTE high accuracy (IN_EVENT) is used. */
    #endif
        nrf_gpio_pin_pull_t  pull_cfg;         /**< Pull-up or -down configuration. */
        app_button_handler_t button_handler;   /**< Handler to be called when button is pushed. */
    } app_button_cfg_t;
     

    The code below, from examples\ble_peripheral\ble_app_blinky\main.c, shows how it can be used.
    /**@brief Function for initializing the button handler module.
     */
    static void buttons_init(void)
    {
        ret_code_t err_code;
    
        //The array must be static because a pointer to it will be saved in the button handler module.
        static app_button_cfg_t buttons[] =
        {
            {LEDBUTTON_BUTTON, false, BUTTON_PULL, button_event_handler}
        };
    
        err_code = app_button_init(buttons, ARRAY_SIZE(buttons),
                                   BUTTON_DETECTION_DELAY);
        APP_ERROR_CHECK(err_code);
    }


    Here the LEDBUTTON_BUTTON is a pin, in this case button 1 of the DK. 

    Hope this makes things easier/clearer!

    Best regards,
    Carl Richard

  • Hi Carl,

    yes, clear so far - that's what I did and where I was reading along. The point is, the example I placed my own code on already made use of the app_library by setting functions on the 4 available HW buttons of the DK.

    nRF5_SDK_17.0.2_d674dde\examples\ble_central_and_peripheral\experimental\ble_app_hrs_rscs_relay

    /**@brief Function for initializing buttons and LEDs.
     *
     * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to
     *                            wake the application up.
     */
    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, NULL);
        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);
    }

    Following that code I go down the rabbit hole to board.c, bsp.c, pca10040.h, etc. where all the handler code for pressing those buttons is defined, e.g. events like BSP_INDICATE_RCV_OK, BSP_INDICATE_CONNECTED, etc. etc.

    Also bsp.c does all the initialization, meaning I cannot just call app_button_init() once more in MY code to add 2 extra buttons?

    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);
            }
        }
        ...
        ...

    So I want to KEEP all this stuff, because it works well in the app, but I want to ADD my two custom buttons to the code flow. The only way I SAW how I could do this was to do this "dirty hack" by redefining the button array and getting my stuff in. For me it doesn't look like this would be the proper way to do it.

    I think the example you provided works well for starting of. But as said, I'd like to augment/extend the existing BSP stuff code with my buttons and it does not seem to be possible in a clean way? At least I don't see it. I hope these explanations make my problem somewhat clearer? Am I misinterpreting some obstacles I see? 

    Or - saying it another way: How would you add support for 2 additional buttons on pin 22 and 23 starting from ble_app_hrs_rscs_relay? Thank you!

  • Hi again!

    Thanks for the clarification. I asked my internally and your suspicion that the app_button library cannot be used along side the bsp library was confirmed. If you want to base your code on the current sample I believe the best solution is to modify the board files and extend the BSP library with the additional buttons. You can also stick to your current solution of course, but I don't have any better suggestions unfortunately.

    On that note, the BSP library main intention is to be make it easier to maintain examples for all the different boards we design here at Nordic. For an end application it's probably more ideal to control things yourself, using for example the app_button library.

    Sorry that this isn't ideal.

    Best regards,
    Carl Richard

  • Dear Carl, thanks for seeking clarification. It's a pity to hear this scenario is not supported today natively in your SDK provided examples or bsp files, but it's good to know now, that I didn't overlook any obvious function or #define which would have been all I need to change or call.

    Yet, I'd appreciate if in a future version this topic might get some attention. I think it should be possible to provide such a "definition hook" in the BSP library to, by means of some custom #define in the app of the developer. These #defines coudl then are considered during the generic app_button_init() within the BSP code. It would be great if NRF could consider this for implementation.

    Thanks again

    Best regards!

    Markus

Related