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.

Parents
  • Which Timer are you using? RTC? if so which instance? make sure that the instance you are using is not used by anything else in your system. Preferably use RTC1 or 2 if available.

  • I have used a generic GPIO and timer on other examples in the past. I am not using it now for this application. I wanted to use the capture capability of the PWM. I see there is a ...\v3.02\zephyr\tests\drivers\pwm\pwm_loopback example. this looks like it uses a PWM output connected to a PWM input that does use capture capabilities. I tired to understand and build this but was unsuccessful. there is not an overlay for nRF9160 so I could not get it to compile. Is this what I need to understand to do PWM measure frequency and period. The example is not very clear is there some description of the PWM loopback example?

  • 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

Reply Children
No Data
Related