Max. measurable GPIO input frequency

Hi all, 

I have to measure the frequency of a PWM signal routed to one of the nRF52840 GPIO pins. 

The signal frequency is ~3MHz. 

The measurement is done with the help of two timers, the code is taken from this thread

// ------------------------------------------------------------ dependencies ---
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"



#define FREQ_MEASURE_PIN 24
uint32_t time = 1; // timer time in seconds

static void timer_init()
{
  uint32_t counter; 
  counter = (16000000 >> 8)*time;
  NRF_TIMER1->TASKS_STOP = 1;
  NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;
  NRF_TIMER1->PRESCALER = 8;	// f_hck / 2^8 
  NRF_TIMER1->CC[0] = counter;	
  NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos);	
  NRF_TIMER1->TASKS_CLEAR = 1;
  NRF_TIMER1->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
  NRF_TIMER1->EVENTS_COMPARE[0] = 0;
}

static void counter_init()
{
  NRF_TIMER2->TASKS_STOP = 1;	
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Counter;
  NRF_TIMER2->BITMODE = (TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos);
  NRF_TIMER2->TASKS_CLEAR = 1;
  NRF_TIMER2->EVENTS_COMPARE[0] = 0;
}

static void gpiote_init(uint32_t pin)
{
  NRF_GPIOTE->CONFIG[0] = 0x01 << 0;                            // MODE: Event
  NRF_GPIOTE->CONFIG[0] |= pin << 8;			      // Pin number
  NRF_GPIOTE->CONFIG[0] |= NRF_GPIOTE_POLARITY_LOTOHI	<< 16;// Event rising edge 	
}

static void ppi_timer_stop_counter_init()
{
  NRF_PPI->CHEN |= 1 << 0;
  *(&(NRF_PPI->CH0_EEP)) = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0];
  *(&(NRF_PPI->CH0_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_STOP;
  NRF_PPI->CHENSET |= 1 << 0;
}

static void ppi_gpiote_counter_init()
{
  NRF_PPI->CHEN |= 1 << 1;
  *(&(NRF_PPI->CH1_EEP)) = (uint32_t)&NRF_GPIOTE->EVENTS_IN[0];
  *(&(NRF_PPI->CH1_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_COUNT;
  NRF_PPI->CHENSET |= 1 << 1;
}

int main()
{
    uint32_t err_code = NRF_LOG_INIT(NULL);

    // Start clock for accurate frequencies
    NRF_CLOCK->TASKS_HFCLKSTART = 1; 
    // Wait for clock to start
    while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("Timer Test");
    NVIC_EnableIRQ(TIMER1_IRQn);
    NVIC_SetPriority(TIMER1_IRQn, APP_IRQ_PRIORITY_LOW);	

    nrf_gpio_cfg_input(FREQ_MEASURE_PIN, NRF_GPIO_PIN_NOPULL);

    counter_init();
    timer_init();
    gpiote_init(FREQ_MEASURE_PIN);
    ppi_gpiote_counter_init();
    ppi_timer_stop_counter_init();

    NRF_TIMER1->TASKS_START = 1;
    NRF_TIMER2->TASKS_START = 1;
    
    while(1)
    {
      NRF_LOG_FLUSH();
    }
}

void TIMER1_IRQHandler(void) 
{
  if (NRF_TIMER1->EVENTS_COMPARE[0] != 0)
  {
      nrf_drv_gpiote_out_toggle(LED_GREEN);
      NRF_TIMER1->EVENTS_COMPARE[0] = 0;
      NRF_TIMER2->TASKS_CAPTURE[0] = 1;
                  
      NRF_LOG_INFO("%lu Hz", NRF_TIMER2->CC[0]*time);

      NRF_TIMER1->TASKS_CLEAR = 1;
      NRF_TIMER2->TASKS_CLEAR = 1;	
                                  
      NRF_TIMER2->TASKS_START = 1;			
    }
}

As long as the PWM frequency on the GPIO pin is below ~2.66 MHz, the measured value is correct, here some results for different frequencies (generated with a signal generator): 

Input Frequency 1.5MHz: 

Input Frequency 2.5MHz: 

If i increase the frequency to 3 MHz, the measured value is incorrect: 

According to this thread the nRF52 is not able to measure frequencies above 2.66 MHz. Is this true?? 


I have - additional to this problem - another problem with the code: 

I have a button on my PCB, which I am currently using to toggle a LED, here is the code: 

Initialization of the GPIO button input:

nrf_drv_gpiote_in_config_t in_config_toggle_button = NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(true); // Configure a pin to use a GPIO IN or PORT EVENT to detect any change on the pin.
in_config_toggle_button.pull = NRF_GPIO_PIN_PULLUP;
APP_ERROR_CHECK(nrf_drv_gpiote_in_init(BUTTON_1,  &in_config_toggle_button, button1_handler));  // Call handler when switch pin toggles
nrf_drv_gpiote_in_event_enable(BUTTON_1, true);

Button callback function:

static void button1_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) //called when switch toggles
{
    UNUSED_VARIABLE(pin);
    UNUSED_VARIABLE(action);
    button1_state = 1; 
#ifdef LED_WHITE_ON
    nrf_drv_gpiote_out_toggle(LED_WHITE);
#endif
}

When I initialize and use the button like this WITH the timer code shown above, it does not output the frequency to the console. Instead, only the button's callback function is constantly called (the white LED then flashes constantly). It is as if the counter interrupt from my high frequency signal triggers the button's interrupt. Do I have to delete an interrupt flag in the timer interrupt? 

Thanks for your support.

Best Regards

hypn0

Parents
  • Hello hypn0,

    Sorry for the late reply. Without having checked or done the math, I believe this frequency is about the maximum frequency possible to measure using PPI. 

    The PPI itself is running at 16MHz. There i up to 1 tick delay on the PPI, so that gives you a 8MHz. The you have some delay in the GPIO itself. The pad capacitance is 5pF. Depending on the input signal you are measuring it will take a certain amount of time from you set the output high until the input on the nRF is actually pulled high. If this takes a few µs, then that would explain the delay you are seeing.

    If you try to use a logic analyzer to measure your input signal, and then use the PPI to toggle a pin on every GPIO event (so that you basically duplicate the input signal), what sort of delay are you seeing between the (PWM) input and the (GPIO) output using the PWM generator that you are using?

    Best regards,

    Edvin

Reply
  • Hello hypn0,

    Sorry for the late reply. Without having checked or done the math, I believe this frequency is about the maximum frequency possible to measure using PPI. 

    The PPI itself is running at 16MHz. There i up to 1 tick delay on the PPI, so that gives you a 8MHz. The you have some delay in the GPIO itself. The pad capacitance is 5pF. Depending on the input signal you are measuring it will take a certain amount of time from you set the output high until the input on the nRF is actually pulled high. If this takes a few µs, then that would explain the delay you are seeing.

    If you try to use a logic analyzer to measure your input signal, and then use the PPI to toggle a pin on every GPIO event (so that you basically duplicate the input signal), what sort of delay are you seeing between the (PWM) input and the (GPIO) output using the PWM generator that you are using?

    Best regards,

    Edvin

Children
No Data
Related