NRFX_ERROR_INVALID_PARAM error on nrfx_timer_init with

I'm trying too use a timer as a counter on my nRF52840.
This is the function in question:

static void timer_init(void)
{
    nrfx_timer_config_t timer_cfg = {
        .mode      = NRF_TIMER_MODE_COUNTER,
        .bit_width = NRF_TIMER_BIT_WIDTH_32,
        .frequency = NRF_TIMER_FREQ_1MHz,  
        .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
        .p_context = NULL
    };
    nrfx_err_t err = nrfx_timer_init(&timer, &timer_cfg, NULL);
    if (err != NRFX_SUCCESS) {
        printk("Timer init failed: %d\n", err);
        return;
    }
    nrfx_timer_enable(&timer);
}

I have tried all frequencies and I get NRFX_ERROR_INVALID_PARAM with all of them expect for NRF_TIMER_FREQ_16MHz where I get:

[00:00:00.027,954] <err> os: ***** USAGE FAULT ***** [00:00:00.027,984] <err> os: Division by zero [00:00:00.028,015] <err> os: r0/a1: 0x0005223c r1/a2: 0x2000e12c r2/a3: 0x00f42400 [00:00:00.028,015] <err> os: r3/a4: 0x00000003 r12/ip: 0x00000000 r14/lr: 0x0003e1ef [00:00:00.028,045] <err> os: xpsr: 0x61000000 [00:00:00.028,045] <err> os: Faulting instruction address (r15/pc): 0x0003e106 [00:00:00.028,076] <err> os: >>> ZEPHYR FATAL ERROR 30: Unknown error on CPU 0 [00:00:00.028,137] <err> os: Current thread: 0x20006aa0 (main)

On line 86 of the nrfx_timer.c

I'm on nRF Connect SDK V3.0.2
  • What does your timer variable initialization look like ?

  • Hi Thomas,
    This is my current code including the timer variable initialization:

    #include <zephyr/kernel.h>
    #include <nrfx_gpiote.h>
    #include <nrfx_timer.h>
    #include <nrfx_ppi.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/drivers/gpio.h>
    #include "encoder_handler.h"
    
    #define PIN_A 28
    #define PIN_B 29
    #define GPIOTE_INSTANCE_IDX 0
    
    // TIMER instance for counting
    #define TIMER_INSTANCE 2
    static const nrfx_timer_t timer = NRFX_TIMER_INSTANCE(TIMER_INSTANCE);
    
    // PPI channels
    static uint8_t ppi_ch_a;
    static uint8_t ppi_ch_b;
    
    // Encoder power pin from DeviceTree
    #define ENCODER_POWER_NODE DT_ALIAS(encoder_power)
    static const struct gpio_dt_spec encoder_power = GPIO_DT_SPEC_GET(ENCODER_POWER_NODE, gpios);
    
    // Forward declaration of helper ISR
    static void encoder_dir_isr(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action);
    
    /**
     * @brief Initialize TIMER in COUNTER mode
     */
    static void timer_init(void)
    {
        nrfx_timer_config_t timer_cfg = {
            .mode      = NRF_TIMER_MODE_COUNTER,
            .bit_width = NRF_TIMER_BIT_WIDTH_32,
            .frequency = NRF_TIMER_FREQ_1MHz,  
            .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
            .p_context = NULL
        };
        nrfx_err_t err = nrfx_timer_init(&timer, &timer_cfg, NULL);
        if (err != NRFX_SUCCESS) {
            printk("Timer init failed: %d\n", err);
            return;
        }
        nrfx_timer_enable(&timer);
    }
    
    /**
     * @brief Initialize GPIOTE pins
     * Pin A and B generate events, sampled in ISR to determine direction
     */
    static void gpiote_init(void)
    {
        static const nrfx_gpiote_t pio_instance = NRFX_GPIOTE_INSTANCE(GPIOTE_INSTANCE_IDX);
    
        if (!nrfx_gpiote_init_check(&pio_instance)) {
            nrfx_err_t err = nrfx_gpiote_init(&pio_instance, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
            // Optionally handle error here
        }
    
        static const nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_PULLUP;
        static const nrfx_gpiote_trigger_config_t trigger_config = {
            .trigger = NRFX_GPIOTE_TRIGGER_TOGGLE,
            .p_in_channel = NULL, // Not needed for simple input
        };
        static const nrfx_gpiote_handler_config_t handler_config = {
            .handler = encoder_dir_isr,
        };
        nrfx_gpiote_input_pin_config_t input_pin_cfg = {
            .p_pull_config = &pull_config,
            .p_trigger_config = &trigger_config,
            .p_handler_config = &handler_config,
        };
    
        nrfx_gpiote_input_configure(&pio_instance, PIN_A, &input_pin_cfg);
        nrfx_gpiote_trigger_enable(&pio_instance, PIN_A, true);
    
        // For PIN_B, no handler needed
        nrfx_gpiote_input_pin_config_t input_pin_cfg_b = {
            .p_pull_config = &pull_config,
            .p_trigger_config = &trigger_config,
            .p_handler_config = NULL,
        };
        nrfx_gpiote_input_configure(&pio_instance, PIN_B, &input_pin_cfg_b);
        nrfx_gpiote_trigger_enable(&pio_instance, PIN_B, true);
    }
    
    /**
     * @brief Configure PPI: Link A/B pins to TIMER
     */
    static void ppi_init(void)
    {
        static const nrfx_gpiote_t pio_instance = NRFX_GPIOTE_INSTANCE(GPIOTE_INSTANCE_IDX);
    
        // Allocate PPI channels
        if (nrfx_ppi_channel_alloc(&ppi_ch_a) != NRFX_SUCCESS) {
            printk("PPI channel A allocation failed!\n");
        }
        if (nrfx_ppi_channel_alloc(&ppi_ch_b) != NRFX_SUCCESS) {
            printk("PPI channel B allocation failed!\n");
        }
    
        // Connect PIN_A event to TIMER count task
        nrfx_ppi_channel_assign(ppi_ch_a,
            nrfx_gpiote_in_event_address_get(&pio_instance, PIN_A),
            nrfx_timer_task_address_get(&timer, NRF_TIMER_TASK_COUNT));
    
        // Connect PIN_B event to TIMER count task
        nrfx_ppi_channel_assign(ppi_ch_b,
            nrfx_gpiote_in_event_address_get(&pio_instance, PIN_B),
            nrfx_timer_task_address_get(&timer, NRF_TIMER_TASK_COUNT));
    
        nrfx_ppi_channel_enable(ppi_ch_a);
        nrfx_ppi_channel_enable(ppi_ch_b);
    }
    
    /**
     * @brief Lightweight ISR for determining direction on PIN_A toggle
     * Increments/decrements TIMER via software if needed for direction
     */
    static void encoder_dir_isr(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        bool a_state = nrf_gpio_pin_read(PIN_A);
        bool b_state = nrf_gpio_pin_read(PIN_B);
    
        // Software correction for direction:
        if ((a_state && !b_state) || (!a_state && b_state)) {
            nrfx_timer_clear(&timer);
        }
    }
    
    /**
     * @brief Initialize encoder hardware
     */
    int encoder_init(void)
    {
        if (!device_is_ready(encoder_power.port)) {
            printk("Encoder power GPIO device not ready!\n");
            return -1;
        }
    
        gpio_pin_configure_dt(&encoder_power, GPIO_OUTPUT_ACTIVE);
        k_msleep(10); // allow power-up
    
        timer_init();
        gpiote_init();
        ppi_init();
    
        printk("Quadrature encoder initialized (GPIOTE + PPI + TIMER)\n");
        return 0;
    }
    
    /**
     * @brief Get current encoder count
     */
    int32_t encoder_get_count(void)
    {
        uint32_t count;
        nrfx_timer_capture(&timer, NRF_TIMER_CC_CHANNEL0); // capture value
        // nrfx_timer_clear(&timer); 
        nrfx_timer_capture_get(&timer, NRF_TIMER_CC_CHANNEL0);
        count = nrfx_timer_capture_get(&timer, NRF_TIMER_CC_CHANNEL0);
        return (int32_t)count;
    }
    
    /**
     * @brief Reset encoder count
     */
    void encoder_reset_count(void)
    {
        nrfx_timer_clear(&timer);
    }

  • I got it working like this:

        nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG(0);
        timer_cfg.mode = NRF_TIMER_MODE_COUNTER;
        timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;

        if (nrfx_timer_init(&timer, &timer_cfg, NULL) != NRFX_SUCCESS) {
            printk("Timer init failed!\n");
            return;
        }
Related