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

measuring input GPIO pin frequency with soft device running

Hello,

is it possible to measure frequency from 1Hz up to 400kHz (50% duty cycle) on gpio pin having soft device enabled with Peripheral functionality? The measurement will be invoked on demand by the connected central device. I will use nRF51822, rev. 3, S110 or S130, SDK 8 or 9.

If this is not possible, please tell me if following scenario would be ok:

  • invoke measurement
  • disable soft device (disconnection from central)
  • manage measurement (what's the best way: which timer?, PPI? GPIOTE?)
  • enable soft device

Thank you!

btw, what is the maximum frequency that can be measure on gpio pin?

Parents
  • @Aryan, It's been a long time, however now I've already got time to deal with this frequency meter. Your advice works perfectly! After datasheet and forum reading I came up with the final code using all of these peripherals according to your scheme. PPI rulez :-) It also works with Soft Device enabled. I share my code below (not yet so beautiful..) so maybe someone would save his time on a similiar problem.

    #define FREQ_MEASURE_PIN 6
    
    static void timer_init()
    {
    	NRF_TIMER1->TASKS_STOP = 1;
    	NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;
    	NRF_TIMER1->PRESCALER = 8;	// Fhck / 2^8 
    	NRF_TIMER1->CC[0] = 62500;	// 62500 - 1s
    	
    	NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << 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_24Bit << 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()
    {
        // Soft Device initialization..
    
       	NVIC_EnableIRQ(TIMER1_IRQn);
        NVIC_SetPriority(TIMER1_IRQn, NRF_APP_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;
    	
    	for(;;) {
    		// power manage //
    	}
    }
    
    void TIMER1_IRQHandler(void) 
    {
    	if (NRF_TIMER1->EVENTS_COMPARE[0] != 0)
    	{
    		NRF_TIMER1->EVENTS_COMPARE[0] = 0;
    		NRF_TIMER2->TASKS_CAPTURE[0] = 1;
    				
    		LOG_INFO("cc: %dHz", NRF_TIMER2->CC[0]);
          	
    		NRF_TIMER1->TASKS_CLEAR = 1;
    		NRF_TIMER2->TASKS_CLEAR = 1;	
    						
    		NRF_TIMER2->TASKS_START = 1;			
        }
    }
    

    Thanks!

Reply
  • @Aryan, It's been a long time, however now I've already got time to deal with this frequency meter. Your advice works perfectly! After datasheet and forum reading I came up with the final code using all of these peripherals according to your scheme. PPI rulez :-) It also works with Soft Device enabled. I share my code below (not yet so beautiful..) so maybe someone would save his time on a similiar problem.

    #define FREQ_MEASURE_PIN 6
    
    static void timer_init()
    {
    	NRF_TIMER1->TASKS_STOP = 1;
    	NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;
    	NRF_TIMER1->PRESCALER = 8;	// Fhck / 2^8 
    	NRF_TIMER1->CC[0] = 62500;	// 62500 - 1s
    	
    	NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << 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_24Bit << 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()
    {
        // Soft Device initialization..
    
       	NVIC_EnableIRQ(TIMER1_IRQn);
        NVIC_SetPriority(TIMER1_IRQn, NRF_APP_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;
    	
    	for(;;) {
    		// power manage //
    	}
    }
    
    void TIMER1_IRQHandler(void) 
    {
    	if (NRF_TIMER1->EVENTS_COMPARE[0] != 0)
    	{
    		NRF_TIMER1->EVENTS_COMPARE[0] = 0;
    		NRF_TIMER2->TASKS_CAPTURE[0] = 1;
    				
    		LOG_INFO("cc: %dHz", NRF_TIMER2->CC[0]);
          	
    		NRF_TIMER1->TASKS_CLEAR = 1;
    		NRF_TIMER2->TASKS_CLEAR = 1;	
    						
    		NRF_TIMER2->TASKS_START = 1;			
        }
    }
    

    Thanks!

Children
Related