This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PWM Frequency Measurement on nRF52 with SDK 11

Hi,

I need to measure the frequency of a PWM signal with 50% duty cycle through one of the GPIO pins. The frequency of input PWM signal ranges between 100Hz to 1000Hz.

I am hoping to measure the PWM frequency in the following way: I'll wait for the signal to go HIGH, start timing, then wait for the signal to go LOW and stop timing. Then I'll repeat the same process but this time from LOW to HIGH, and then find the average of the two half periods measured.

I know the above process gives me half of a full period, but since the duty cycle of my PWM signal is 50% I can calculate the PWM frequency based on the averaged value.

How can I implement the above process?

Is there a better way for measuring PWM signals?

Thanks

Parents
  • It will be a lot more accurate to let the PWM transitions cause an interrupt and have the ISR increment a counter. Then let the whole works run for, say, 5 seconds. Divide the number of counts by 5 and you will have Hz.

  • Bret, I want to go back to the initial answer you posted "It will be a lot more accurate to let the PWM transitions cause an interrupt and have the ISR increment a counter. Then let the whole works run for, say, 5 seconds. Divide the number of counts by 5 and you will have Hz."

    So Based on the following code I can have the ISR increment a counter. But how can I start and stop the ISR within a specified period of time? Does the following code work reliably?

    static uint32_t IRQcount = 0;
    static const uint32_t oneSecond = 1000000;
    
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        IRQcount++;
    }
    /**
      * @brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output, 
      * and configures GPIOTE to give an interrupt on pin change.
      */
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, false);
    }
    
    /**
      * @brief Function for application main entry.
      */
    int main(void)
    {
        gpio_init();
    
        const int period_30ms = 30000;
        uint16_t i;
        bool time_start = false;
        uint32_t freq_value = 0;
    
            while (true)
            {
                if(time_start == true)
                {
                           nrf_drv_gpiote_in_event_enable(PIN_IN, true);
                           for(i = 0; i < 30000; i++);
                           nrf_drv_gpiote_in_event_enable(PIN_IN, false);
                           freq_value = IRQcount*oneSecond/period_30ms; //frequency in Hz
                           IRQcount = 0;
                           time_start = false;
                }
                nrf_delay_ms(1000);
                time_start = true;
            }
    }
    
Reply
  • Bret, I want to go back to the initial answer you posted "It will be a lot more accurate to let the PWM transitions cause an interrupt and have the ISR increment a counter. Then let the whole works run for, say, 5 seconds. Divide the number of counts by 5 and you will have Hz."

    So Based on the following code I can have the ISR increment a counter. But how can I start and stop the ISR within a specified period of time? Does the following code work reliably?

    static uint32_t IRQcount = 0;
    static const uint32_t oneSecond = 1000000;
    
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        IRQcount++;
    }
    /**
      * @brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output, 
      * and configures GPIOTE to give an interrupt on pin change.
      */
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, false);
    }
    
    /**
      * @brief Function for application main entry.
      */
    int main(void)
    {
        gpio_init();
    
        const int period_30ms = 30000;
        uint16_t i;
        bool time_start = false;
        uint32_t freq_value = 0;
    
            while (true)
            {
                if(time_start == true)
                {
                           nrf_drv_gpiote_in_event_enable(PIN_IN, true);
                           for(i = 0; i < 30000; i++);
                           nrf_drv_gpiote_in_event_enable(PIN_IN, false);
                           freq_value = IRQcount*oneSecond/period_30ms; //frequency in Hz
                           IRQcount = 0;
                           time_start = false;
                }
                nrf_delay_ms(1000);
                time_start = true;
            }
    }
    
Children
No Data
Related