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.
- Setting up the timer.
- Setting up the GPIOTE
- Setting up the PPI
- 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) { } }