Using timer in counter mode is producing incorrect counts

Hello,

I am using an Arduino Nano-ble-33 and I am having issue counting edges. The values seem to be roughly 0.4% higher than they should be. If I put a 1000Hz clock, I get roughly 1004, at 10kHz I get ~10040, at 100KHz I get ~100400, etc. It gets worse the higher the freq. I read the errata and implemented the recommended fix. The input signal is spot on, measured with two scopes. 

I believe it is set up correctly according to the spec. I just don't see where the extra pulses are coming from.

Below is a snippet of the output. I am running two timers with the same signal as input. The first value is the time in microseconds. As you can see, the variation in time can't account for the extra counts. I am assuming micros() is accurate. 

---1000005,100385,100385
---1000004,100386,100386
---1000005,100412,100412
---1000005,100423,100423
---1000001,100424,100424
---1000006,100417,100417
---1000007,100407,100407
---1000006,100426,100426
---1000000,100413,100413
---1000008,100429,100429
---1000003,100447,100447
---1000009,100414,100414

Below is my code. 

#include "Arduino.h"

#include <nrf_timer.h>

#define TIMER3 NRF_TIMER3
#define TIMER4 NRF_TIMER4

static uint8_t InitCounter(NRF_TIMER_Type* timer, uint8_t pin);

static uint8_t _compChan[2];
static uint32_t _compCaptureIntervalUs = 1000000; // 1 sec

void setup()
{
    Serial.begin(115200);

    _compChan[0] = InitCounter(TIMER3, 2);
    _compChan[1] = InitCounter(TIMER4, 3);

    // this comes from an errata, it allows the ports to run faster than 2.6MHz
    *(volatile uint32_t*)(NRF_GPIOTE_BASE + 0x600 + (4 * _compChan[0])) = 1;
    *(volatile uint32_t*)(NRF_GPIOTE_BASE + 0x600 + (4 * _compChan[1])) = 1;

    // start the timers
    TIMER3->TASKS_START = 1;
    TIMER4->TASKS_START = 1;
}


void loop(void)
{
    static ulong prevMicros = micros();
    static ulong curMicros  = micros();


    curMicros = micros();

    uint32_t diff = (curMicros - prevMicros);

    if (diff >= _compCaptureIntervalUs) {
        TIMER3->TASKS_CAPTURE[_compChan[0]] = 1;
        TIMER4->TASKS_CAPTURE[_compChan[1]] = 1;

        TIMER3->TASKS_CLEAR        = 1;
        TIMER4->TASKS_CLEAR        = 1;
        prevMicros                 = micros();

            Serial.print("---");
            Serial.print(diff);
            Serial.print(",");
            Serial.print(TIMER3->CC[_compChan[0]]);
            Serial.print(",");
            Serial.println(TIMER4->CC[_compChan[1]]);
    }
}

static uint8_t InitCounter( NRF_TIMER_Type* timer, uint8_t pin )
{
    static uint8_t chan        = 0;
    uint8_t        currentChan = chan;

    pinMode( pin, INPUT );
    // timer init
    timer->MODE        = TIMER_MODE_MODE_Counter;
    timer->TASKS_CLEAR = 1;
    timer->BITMODE     = TIMER_BITMODE_BITMODE_32Bit; // Set counter to 32 bit resolution

    // gpio init
    NRF_GPIOTE->CONFIG[chan] = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos
                             | GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos
                             | digitalPinToPinName(pin) << GPIOTE_CONFIG_PSEL_Pos;

    // ppi init
    NRF_PPI->CH[chan].EEP   = (uint32_t)&NRF_GPIOTE->EVENTS_IN[chan];
    NRF_PPI->CH[chan].TEP   = (uint32_t)&timer->TASKS_COUNT;
    NRF_PPI->CHENSET        = 1 << chan;
    chan++;
    return currentChan;
}

Thanks,

Anthony

Related