Measuring pulse time with timers/GPIOTE/PPI on the Arduino Nano 33 BLE sense

I'm trying to measure the pulse ON time of an input signal which has a variable duty cycle with the help of the GPIOTE/PPI/Timer interfaces.

#include <Arduino.h>
#include <hal/nrf_timer.h>
#include <hal/nrf_gpiote.h>
#include <hal/nrf_gpio.h>
#include <hal/nrf_ppi.h>

static uint8_t pin = 5;

void setup() {
  // put your setup code here, to run once:

  // timer init
  NRF_TIMER4->MODE = TIMER_MODE_MODE_Timer;
  NRF_TIMER4->TASKS_CLEAR = 1;
  NRF_TIMER4->PRESCALER = 4;    // 1MHz
  NRF_TIMER4->BITMODE = TIMER_BITMODE_BITMODE_16Bit;     //Set counter to 16 bit resolution

  // gpio init
  NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos | 
                                         GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos | 
                                         digitalPinToPinName(pin) << GPIOTE_CONFIG_PSEL_Pos | 
                                        
 GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;    // 
ignored when gpio is set to event mode
                                         
  NRF_GPIOTE->CONFIG[1] = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos | 
                                     GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos | 
                                     digitalPinToPinName(pin) << GPIOTE_CONFIG_PSEL_Pos | 
                                    
 GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;    // 
ignored when gpio is set to event mode  

  // ppi init
  // start timer on rising edge
  NRF_PPI->CH[0].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[0];
  NRF_PPI->CH[0].TEP = (uint32_t)&NRF_TIMER4->TASKS_CLEAR;
  NRF_PPI->FORK[0].TEP = (uint32_t)&NRF_TIMER4->TASKS_START;
  NRF_PPI->CHENSET = PPI_CHENSET_CH0_Enabled << PPI_CHENSET_CH0_Pos;
  
  // stop timer on falling edge
  NRF_PPI->CH[1].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[1];
  NRF_PPI->CH[1].TEP = (uint32_t)&NRF_TIMER4->TASKS_CAPTURE[1];
  NRF_PPI->FORK[1].TEP = (uint32_t)&NRF_TIMER4->TASKS_STOP;
  NRF_PPI->CHENSET = PPI_CHENSET_CH1_Enabled << PPI_CHENSET_CH1_Pos;
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print("Event 0 status - "); Serial.println(NRF_GPIOTE->EVENTS_IN[0]);
  Serial.print("Event 1 status - "); Serial.println(NRF_GPIOTE->EVENTS_IN[1]);
  Serial.print("CC value - "); Serial.println(NRF_TIMER4->CC[1]);
}

The code works fine for slower signals but when I give a signal in the KHz range I get a lot less timer count that expected. In the above code the timer is ticking at 1us, so for a signal with ON time of 60us, I was expecting 60 ticks, but the NRFTIMER->CC[1] register is showing only 5 ticks.

Is this a limitation from the GPIOTE/PPI peripherals? Has anyone tried this approach?

Welcome to the forum

How do you create the pulses?

I modified your sketch and created pulses using another pin, hardwired it to the input and confirmed the pulse length with an oscilloscope. I created pulses from 11us to 1000us using delayMicroseconds(). The CC value matched the values I measured with my oscilloscope.

I then modified the sketch to use __NOP() for delay and tested pulses from 1 to 100us and the CC values matched again.

Thanks Klaus_K!
I was using another arduino board to generate the pulse on one of it's pins. Turns out the delay function I used to generate the pulse on the board was the problem. Using delayMicroseconds(x) instead of delay(0.00x) seems to have fixed the issue.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.