This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Why does the GPIOTE event not link to the GPIOTE task via PPI though the event handler works?

I was learning GPIOTE using the example provided in SDK 9.0.0. (examples\peripheral\gpiote). The example only uses GPIOTE task and a timer to drive the task through PPI.

So I created a similar function (pasted below) that is meant to link a GPIOTE event to a GPIOTE task through PPI. The GPIOTE event corresponds to button 2 (BSP_Button_1) of the nRF51 DK board. The GPIOTE task corresponds to LED 2 (BSP_LED_1).

The GPIOTE event's handler also toggles LED 3 (for verification purposes).

LED 3 toggled when button 2 was pressed, confirming that the GPIOTE event was working. But LED 2 was always on. So either PPI or GPIOTE task, or both was not working.

#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_gpiote.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_gpiote.h"
#include "app_error.h"
#include "nrf_delay.h"

#ifdef BSP_LED_0
    #define GPIO_OUTPUT_PIN_NUMBER BSP_LED_0  /**< Pin number for output. */
#endif

#ifndef GPIO_OUTPUT_PIN_NUMBER
    #error "Please indicate output pin"
#endif


static nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(0);

void timer_dummy_handler(nrf_timer_event_t event_type, void * p_context){}

	
#define GPIO_LED_PIN 			BSP_LED_1
#define GPIO_LED2_PIN			BSP_LED_2
#define GPIO_BUTTON_PIN   BSP_BUTTON_1

void button_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) 
{
	nrf_gpio_pin_toggle(GPIO_LED2_PIN);
	nrf_delay_ms(1000);
}
	
static void led_button_setup()
{
  uint32_t gpiote_event_addr;
  uint32_t gpiote_task_addr;
  nrf_ppi_channel_t ppi_channel;
  ret_code_t err_code;
	
	// Initialise the LED task GPIOTE
  nrf_drv_gpiote_out_config_t task_config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);

  err_code = nrf_drv_gpiote_out_init(GPIO_LED_PIN, &task_config);
  APP_ERROR_CHECK(err_code);

  gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(GPIO_LED_PIN);

  nrf_drv_gpiote_out_task_enable(GPIO_LED_PIN);

	// Initialise LED 2 as an output
	nrf_gpio_cfg_output(GPIO_LED2_PIN);
	
	// Initialise the button event GPIOTE
  nrf_drv_gpiote_in_config_t event_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);

  err_code = nrf_drv_gpiote_in_init(GPIO_BUTTON_PIN, &event_config, button_handler);
  APP_ERROR_CHECK(err_code);

  gpiote_event_addr = nrf_drv_gpiote_in_event_addr_get(GPIO_BUTTON_PIN);
	
  nrf_drv_gpiote_in_event_enable(GPIO_BUTTON_PIN, true);

  // Initialise the ppi channel
  err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
  APP_ERROR_CHECK(err_code);

  err_code = nrf_drv_ppi_channel_assign(ppi_channel, gpiote_event_addr, gpiote_task_addr);
  APP_ERROR_CHECK(err_code);

  err_code = nrf_drv_ppi_channel_enable(ppi_channel);
  APP_ERROR_CHECK(err_code);

	
}

static void led_blinking_setup()
{
    uint32_t compare_evt_addr;
    uint32_t gpiote_task_addr;
    nrf_ppi_channel_t ppi_channel;
    ret_code_t err_code;
    nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);

    err_code = nrf_drv_gpiote_out_init(GPIO_OUTPUT_PIN_NUMBER, &config);
    APP_ERROR_CHECK(err_code);


    nrf_drv_timer_extended_compare(&timer, (nrf_timer_cc_channel_t)0, 200*1000UL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);

    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
    APP_ERROR_CHECK(err_code);

    compare_evt_addr = nrf_drv_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE0);
    gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(GPIO_OUTPUT_PIN_NUMBER);

    err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_evt_addr, gpiote_task_addr);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_enable(ppi_channel);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_out_task_enable(GPIO_OUTPUT_PIN_NUMBER);
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_timer_init(&timer, NULL, timer_dummy_handler);
    APP_ERROR_CHECK(err_code);
    *(uint32_t *)0x40008C0C = 1;

    // Setup PPI channel with event from TIMER compare and task GPIOTE pin toggle.
//    led_blinking_setup();

	  led_button_setup();
	
    // Enable timer
//    nrf_drv_timer_enable(&timer);

    while (true)
    {
        // Do Nothing - GPIO can be toggled without software intervention.
    }
}
  • Hmm, it worked after I set the GPIOTE event to high accuracy.

      nrf_drv_gpiote_in_config_t event_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    

    Also it seemed that the button is not as responsive as it should be in either case.

    Is there anything wrong in the code that makes the button randomly unresponsive?

  • You may be experiencing button bounce. The button will generate fast transitions between Vdd and GND before settling, this may be read as multiple button presses. Since you are toggling a LED, it may switch on and off multiple times and if the number of times is odd you will see a change, if the number of times is even you will not see a change. A normal debounce procedure in code is to start a timer when the button is pushed and then read the input after a certain amount of time. Do a quick search for "debounce button" on google for more information.

    Regarding the low accuracy not working, this is because low accuracy means that the driver uses PORT event instead of IN events. You are configuring the PPI to connect the gpiote IN event to the task. Change to this if you want to use PORT event (it seems like it is not supported by the driver so have to use register):

    err_code = nrf_drv_ppi_channel_assign(ppi_channel, (uint32_t)&NRF_GPIOTE->EVENTS_PORT, gpiote_task_addr);
    

    The problem with the PORT event is that it is shared between all pins that has sense enabled. You can read more about the PORT event and SENSE functionality in the Reference Manual.

  • Thanks Ole. I added a capacitor (1 uF) across the button. It resolved the bouncing issue.

    It still have one question:

    Why does the PPI only work after setting the GPIOTE event to high accuracy?

    nrf_drv_gpiote_in_config_t event_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    
  • You should also add pullup on the pin:

    event_config.pull = NRF_GPIO_PIN_PULLUP;
    
Related