using pwm input to measure frequency

I have an NRF9160 system running and I see mention of "The nRF9160 PWM peripheral can capture the period and pulse width of an external PWM signal" but  was a little confused as to how to implement it. I have used and I am using PWM as an output so that I understand. I have used a generic GPIO as input and used interrupts to start and stop a timer to measure time between edges. This uses two items a generic GPIO and a timer. as I understand the capture capability it just used a single PWM to do the measurement.

can you point me to any examples how to implement this if I am correct in assuming all I need is a single PWM pin.

  • Thanks for lettings us know Timothy, if possible please post the solution here so that it could help others aswell. The code I posted compiled fine at my end, but I am not sure what your complete setup is.

  • #include <nrfx_timer.h>
    
    #if 1
    
    #define TIMER_ID 1
    static const nrfx_timer_t timer = NRFX_TIMER_INSTANCE(TIMER_ID);
    
    static void on_timer_event(nrf_timer_event_t evt, void *ctx) {}
    
    void init_us_timer(void)
    {
    
        nrfx_timer_config_t cfg = NRFX_TIMER_DEFAULT_CONFIG(1000000);
    //    nrfx_timer_config_t cfg = NRFX_TIMER_DEFAULT_CONFIG(16000000);
    //    cfg.frequency = NRF_TIMER_FREQ_1MHz;
        cfg.mode = NRF_TIMER_MODE_TIMER;
        cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    
    uint32_t status = nrfx_timer_init(&timer, &cfg, on_timer_event);
    __ASSERT_NO_MSG(status == NRFX_SUCCESS);
        nrfx_timer_enable(&timer);
    }
    
    uint32_t get_us_count(void)
    {
        return nrfx_timer_capture_get(&timer, NRF_TIMER_CC_CHANNEL0);
    }
    
    uint32_t capture_us(void)
    {
        nrfx_timer_capture(&timer, NRF_TIMER_CC_CHANNEL0);
        return get_us_count();
    }
    
    void clear_us(void)
    {
        nrfx_timer_clear(&timer);
        return;
    }
    #endif
    

    I used the attached file. my interrupt handler for GPIO 09 is as follows. this is as minimum as I could get it.

     
    uint32_t nrfxCount = NRFX_COUNTER_ARRAY_SIZE;
    uint32_t nrfxCountArray[NRFX_COUNTER_ARRAY_SIZE];
     
    void gpio09Callback(struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {

        if (nrfxCount < NRFX_COUNTER_ARRAY_SIZE)
        {
            nrfxCountArray[nrfxCount++] = capture_us();
        }
       }
    the simple test program is as follows
       struct gpio_callback gpio_09_cb;

        init_us_timer();
        k_sleep(K_SECONDS(1));

        gpio_init_callback(&gpio_09_cb, (gpio_callback_handler_t)gpio09Callback, BIT(GPIO_09_DEV_PIN));
        gpio_add_callback(gpio_09_dev, &gpio_09_cb);
        gpio_pin_interrupt_configure(gpio_09_dev, GPIO_09_DEV_PIN, GPIO_INT_ENABLE | GPIO_INT_EDGE | GPIO_INT_EDGE_RISING);

        printf("Start GPIO_09 Interrupt test\r\n");
        nrfxCount = 0;
        while (1)
        {
            if (nrfxCount >= NRFX_COUNTER_ARRAY_SIZE)
            {
                for (int j = 1; j < NRFX_COUNTER_ARRAY_SIZE; j++)
                {
                     printk("GPIO_09 %d\tcounts:%d\tsec: %3.5e\tfreq: %3.3e\r\n", j, (nrfxCountArray[j] - nrfxCountArray[j - 1]),
                           (nrfxCountArray[j] - nrfxCountArray[j - 1]) / NRFX_COUNTER_FREQ,
                           1 / ((nrfxCountArray[j] - nrfxCountArray[j - 1]) / NRFX_COUNTER_FREQ));
                    k_sleep(K_MSEC(200));
                }
                printk("\r\n");
                k_sleep(K_SECONDS(1));
                nrfxCount = 0;
            }
            k_sleep(K_SECONDS(1));
        }
    NOTES: !!!
    this measures the frequency well up to about 30 kHz. I am setting the timer frequency to 16 MHz to get the most counts (accuracy). It does not work at all past that. anything past 60 kHz reads as ~65 kHz. I need to be able to measure a frequency of up to 150 kHz. this solution cannot do that. The interrupt handler looks like it takes about 20 usec so I miss counts when the period is < 20 usec. the interrupt handler needs to be on the order of 5 usec in order to count 150 kHz (6.67 usec).
    How can I get the timer to measue frequencies up to 150 kHz?
  • How can I assure that the GPIO 09 pin has the highest priority and is handle in the fastest way.

  • You cannot set the interrupt priority of the pin handling itself but you can set the priority of interrupt handler for GPIO driver. The priority is handled with NRFX_DEFAULT_IRQ_PRIORITY in modules\hal\nordic\nrfx\templates\nrfx_config_nrf91.h

Related