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

Related