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?

  • Susheel
    when I try to add just the first few lines it does not build. I am using SDK toolchain 3.0.2.
    what am I missing in order to get this to build. I tried to build the lines shown below.
    *************************************
    #include <nrfx_timer.h>
    
    #define TIMER_ID 1
    static const nrfx_timer_t timer = NRFX_TIMER_INSTANCE(TIMER_ID);
    
    ******************** errors  *******************
                   from C:/Nordic4/test_n9160/agr_ind_new_9160/src/jfet_files/jfet_init.c:1982:
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h: In function 'jfet_init':
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:472:24: error: invalid storage class for function 'nrf_timer_prescaler_set'
      472 | NRF_STATIC_INLINE void nrf_timer_prescaler_set(NRF_TIMER_Type * p_reg, uint32_t prescaler_factor);
          |                        ^~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:481:28: error: invalid storage class for function 'nrf_timer_prescaler_get'
      481 | NRF_STATIC_INLINE uint32_t nrf_timer_prescaler_get(NRF_TIMER_Type const * p_reg);
          |                            ^~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:489:24: error: invalid storage class for function 'nrf_timer_task_trigger'
      489 | NRF_STATIC_INLINE void nrf_timer_task_trigger(NRF_TIMER_Type * p_reg,
          |                        ^~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:500:28: error: invalid storage class for function 'nrf_timer_task_address_get'
      500 | NRF_STATIC_INLINE uint32_t nrf_timer_task_address_get(NRF_TIMER_Type const * p_reg,
          |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:509:24: error: invalid storage class for function 'nrf_timer_event_clear'
      509 | NRF_STATIC_INLINE void nrf_timer_event_clear(NRF_TIMER_Type *  p_reg,
          |                        ^~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:521:24: error: invalid storage class for function 'nrf_timer_event_check'
      521 | NRF_STATIC_INLINE bool nrf_timer_event_check(NRF_TIMER_Type const * p_reg,
          |                        ^~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:532:28: error: invalid storage class for function 'nrf_timer_event_address_get'
      532 | NRF_STATIC_INLINE uint32_t nrf_timer_event_address_get(NRF_TIMER_Type const * p_reg,
          |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:541:24: error: invalid storage class for function 'nrf_timer_shorts_enable'
      541 | NRF_STATIC_INLINE void nrf_timer_shorts_enable(NRF_TIMER_Type * p_reg,
          |                        ^~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:550:24: error: invalid storage class for function 'nrf_timer_shorts_disable'
      550 | NRF_STATIC_INLINE void nrf_timer_shorts_disable(NRF_TIMER_Type * p_reg,
          |                        ^~~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:559:24: error: invalid storage class for function 'nrf_timer_shorts_set'
      559 | NRF_STATIC_INLINE void nrf_timer_shorts_set(NRF_TIMER_Type * p_reg,
          |                        ^~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:569:42: error: invalid storage class for function 'nrf_timer_short_compare_clear_get'
      569 | NRF_STATIC_INLINE nrf_timer_short_mask_t nrf_timer_short_compare_clear_get(uint8_t channel);
          |                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    C:/Nordic4/v2.9.0/modules/hal/nordic/nrfx/hal/nrf_timer.h:578:42: error: invalid storage class for function 'nrf_timer_short_compare_stop_get'
      578 | NRF_STATIC_INLINE nrf_timer_short_mask_t nrf_timer_short_compare_stop_get(uint8_t channel);
       
  • 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.

Reply Children
Related