The TIMER does not trigger the LED

I am developing a simple example to understand how GPIO, PPI, and Timers can be used together to kind of bypass reliance on the interrupt through the CPU.

In my code, I do the following.

  1. Setting up the timer.
  2. Setting up the GPIOTE
  3. Setting up the PPI
  4. Binding the GPIO LED to the TIMER via the PPI EEP and TEP.

I use a toggling task for the out-task to implement blinking LED. However, I have two issues.

  • The code does not work (the LED does not blink)
  • I get the following error codes 

nrfx_gpiote_init       : 0x0bad0005
nrfx_ppi_channel_alloc : 0x0bad0000
nrfx_gpiote_out_init   : 0x0bad0000
nrfx_timer_init        : 0x0bad0000
nrfx_ppi_channel_assign: 0x0bad0000
nrfx_ppi_channel_enable: 0x0bad0000

which basically means everything is OK except for the fact that the NRFX_GPIOTE is already initialized. (I tried to uninitialize it once before the initialization, but it still returns the same error)

Here is the code:

// Creating a hardware timer 1 handle
static nrfx_timer_t timer = NRFX_TIMER_INSTANCE(1);


#define LED_Pin1 14 // Pin connected with LED


// Empty interrupt handler for dealing with interrupt events, we do not need this, we use PPI
void timer1_interrupt_handler(nrfx_timer_event_handler_t evt, void * p_context)
{
    // Empty Handler
}


// A function to initialize and set for the timer 1,  PPi, GPIOTE
static void start_timers_leds(void)
{
// Variables to hold the event address and task address
// We connect the PPI TEP & PPI EEP
    uint32_t compare_event_addr;
    uint32_t gpiote_task_addr;

// PPI channel structure declration
// NRFX uses the address of the struct for automatic allocation.
    nrf_ppi_channel_t ppi_channel; 

// A variable to catch error messages
    nrfx_err_t err_code;


// Initialize gpiote module
    uint8_t interrupt_priority = 0;
    err_code = nrfx_gpiote_init(interrupt_priority);
    printk("nrfx_gpiote_init       : 0x%08x\n", err_code);

// Allocate the channel from the available PPI channels
    err_code = nrfx_ppi_channel_alloc(&ppi_channel);
    printk("nrfx_ppi_channel_alloc : 0x%08x\n", err_code);

// Enable & Configure A TOGGLING task for the LED pin
//      True : LED Pin is High initially
//      false: LED Pin is Low  initially
    nrfx_gpiote_out_config_t out_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
    err_code = nrfx_gpiote_out_init(LED_Pin1, &out_config);
    printk("nrfx_gpiote_out_init   : 0x%08x\n", err_code);

//  Creating timer configeration, which will be passed to the initializer
    nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
    err_code = nrfx_timer_init(&timer, &timer_cfg, timer1_interrupt_handler);
    printk("nrfx_timer_init        : 0x%08x\n", err_code);

 // Converting target timeout in milliseconds to ticks.
    uint32_t time_ticks = nrfx_timer_ms_to_ticks(&timer, 5000);

//  Configuring channel 0 of timer 1, and passing the value at which the timer resets and generates an Interrupt Event
    nrfx_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

//  Geting the event and task addresses
    compare_event_addr = nrfx_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE0);
    gpiote_task_addr   = nrfx_gpiote_out_task_addr_get(LED_Pin1);

//  Binding EEP & TEP through PPI channel
    err_code = nrfx_ppi_channel_assign(ppi_channel, compare_event_addr, gpiote_task_addr);
    printk("nrfx_ppi_channel_assign: 0x%08x\n", err_code);

//  Enabling the PPI channel for event-to-task execuation.
    err_code = nrfx_ppi_channel_enable(ppi_channel);
    printk("nrfx_ppi_channel_enable: 0x%08x\n", err_code);

//  Enabling LED Pin task to be called by the event via PPI
    nrfx_gpiote_out_task_enable(LED_Pin1);

//  Enabling the interupt of the timer.
    IRQ_DIRECT_CONNECT(TIMER1_IRQn, 1, timer1_interrupt_handler, 0);
    irq_enable(TIMER1_IRQn);
  }


// Mian function
int main(void)
{

    start_timers_leds(); 
    nrfx_timer_enable(&timer);
    
    while (true)
    {
        
    }
}

Parents Reply Children
  • Hi, here is the header of the main.c above:

    #include <zephyr/types.h>
    #include <stddef.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <string.h>
    #include <zephyr/irq.h>
    #include <nrfx.h>
    #include <nrfx_ppi.h>
    #include <nrf.h>
    #include <nrfx_gpiote.h>
    #include <nrfx_timer.h>
    #include <zephyr/logging/log.h>
    #include <hal/nrf_radio.h>
    
    LOG_MODULE_REGISTER(Logging_Name, LOG_LEVEL_INF);



    here is the project.conf file:

    CONFIG_BT=y
    CONFIG_BT_CENTRAL=y
    CONFIG_BT_DEVICE_NAME="GPIOTE_PPI_Experiment"
    CONFIG_DEBUG=y
    
    
    CONFIG_SERIAL=y
    
    CONFIG_GPIO=y
    
    CONFIG_NRFX_PPI=y
    CONFIG_NRFX_GPIOTE=y
    CONFIG_NRFX_TIMER1=y
    
    
    
    
    CONFIG_LOG=y

    here is the CMakeList.txt:

    cmake_minimum_required(VERSION 3.20.0)
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(xx)
    
    target_sources(app PRIVATE
      src/main.c
    )
    
    zephyr_library_include_directories(${ZEPHYR_BASE})

    That's all needed to build and flash, and I am using it.

  • Hello,

    I would suggest you to look at this sample which does the job you are doing

    The sample is called "nrfx_gppi one-to-one example" in Nordic Connect SDK.

    The sample initializes the nrfx_gpiote, nrfx_timer, and nrfx_gppi and works such that the TIMER compare event is set up to be forwarded via PPI/DPPI to GPIOTE and toggle a pin.
    BR, Naeem
Related