Arduino Zero TCC Capture

Hi Alexander,

To use the micros2() function in two different libraries it's necessary to declare the function in a header file, say "micros2.h". The function declaration just specifies its parameters and return value, terminated with a semicolon, (rather than the function definition that contains the function's code in the curly brackets {}):

extern unsigned long micros2(void);

This header file can be placed in the Arduino IDE's "libraries" directory (where the sketches are stored by default). The file can then be included at the beginning of both libraries:

#include <micros2.h>

Doing this essentially defers the resolution of the micros2() function from compiler to the linker, allowing the function to be called by both libraries.

For example, if you look at the standard micros() code, you'll see that the function is declared in the Arduino core file "delay.h":

#ifdef __cplusplus
extern "C" {
#endif

// ...

extern unsigned long micros( void ) ;

// ...

#ifdef __cplusplus
}
#endif

...but defined in the file "delay.c":

unsigned long micros( void )
{
  uint32_t ticks, ticks2;
  uint32_t pend, pend2;
  uint32_t count, count2;

  ticks2  = SysTick->VAL;
  pend2   = !!(SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)  ;
  count2  = _ulTickCount ;

  do
  {
    ticks=ticks2;
    pend=pend2;
    count=count2;
    ticks2  = SysTick->VAL;
    pend2   = !!(SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)  ;
    count2  = _ulTickCount ;
  } while ((pend != pend2) || (count != count2) || (ticks < ticks2));

  return ((count+pend) * 1000) + (((SysTick->LOAD  - ticks)*(1048576/(VARIANT_MCK/1000000)))>>20) ;
  // this is an optimization to turn a runtime division into two compile-time divisions and
  // a runtime multiplication and shift, saving a few cycles
}

Hi Martin,

thank you so much for your help!
I have tried to write your Code as .h and .cpp files.

But the problem is that it didn't know the GCLK etc. commands.
error: 'GCLK' was not declared in this scope
error: 'GCLK_GENDIV_DIV' was not declared in this scope etc.

I am already using the 1.8.7 Arduino.cc IDE.

Do you know where the problem is? Are these files correct written?

header file looks like:

#ifndef micros2_h
#define micros2_h

#include <Arduino.h>


class micros2{
public:
micros2();
~micros2();
void micros_2();
void TC3_Handler();
};


#endif

cpp File looks like this:

#include "micros2.h"
#include <Arduino.h>

micros2::micros2(){
  // Set up the generic clock (GCLK4) used to clock timers
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) |          // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
                    GCLK_GENDIV_ID(4);             // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |         // Enable GCLK4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                      GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization
  
  // Feed GCLK4 to TCC2 (and TC3)
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC2 (and TC3)
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed GCLK4 to TCC2 (and TC3)
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  TC3->COUNT8.PER.reg = 0xFF;                      // Set period register to 255
  while (TC3->COUNT8.STATUS.bit.SYNCBUSY);         // Wait for synchronization

  TC3->COUNT8.INTENSET.reg = /*TC_INTENSET_MC1 | TC_INTENSET_MC0 |*/ TC_INTENSET_OVF; // Enable TC3 interrupts
  
  //NVIC_DisableIRQ(TC3_IRQn);
  //NVIC_ClearPendingIRQ(TC3_IRQn);
  NVIC_SetPriority(TC3_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 0 (highest) 
  NVIC_EnableIRQ(TC3_IRQn);         // Connect TC3 to Nested Vector Interrupt Controller (NVIC)

  // Set the TC3 timer to tick at 2MHz, or in other words a period of 0.5us - timer overflows every 128us 
  // timer counts up to (up to 255 in 128us)
  TC3->COUNT8.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV8 |      // Set prescaler to 8, 16MHz/8 = 2MHz
                           TC_CTRLA_PRESCSYNC_PRESC |     // Set the reset/reload to trigger on prescaler clock
                           TC_CTRLA_MODE_COUNT8;          // Set the counter to 8-bit mode
                            
  TC3->COUNT8.CTRLA.bit.ENABLE = 1;               // Enable TC3
  while (TC3->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for synchronization

  TC3->COUNT8.READREQ.reg = TC_READREQ_RCONT |            // Enable a continuous read request
                            TC_READREQ_ADDR(0x10);        // Offset of the 8 bit COUNT register
  while (TC3->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for (read) synchronization
}

micros2::~micros2(){/*nothing to destruct*/}

volatile unsigned long timer2Counter;

// Micros2 is used to measure the receiver pulsewidths down to 1us accuracy
void micros2::micros_2() 
{
  uint32_t m;
  uint8_t t;
     
  noInterrupts();                                 // Disable interrupts
  m = timer2Counter;                              // Get the number of overflows
  t = TC3->COUNT8.COUNT.reg;                      // Get the current TC3 count value

  if (TC3->COUNT8.INTFLAG.bit.OVF && (t < 255))   // Check if the timer has just overflowed (and we've missed it)
  {
    m++;                                          // Then in this case increment the overflow counter
  }  
  interrupts();                                   // Enable interrupts
  return ((m << 8) + t) / 2;                      // Return the number of microseconds that have occured since the timer started
}

// This ISR is called every 128us
void micros2::TC3_Handler()           // ISR TC3 overflow callback function
{
  if (TC3->COUNT8.INTFLAG.bit.OVF)
  {
    timer2Counter++;           // Increment the overflow counter
  }
  TC3->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF;   // Rest the overflow interrupt flag
}

Thank you in advance with best regards
Alex

Hi Alex,

Including the "Arduino.h" header file like you've done, should be enough to make the CMSIS (Cortex Microcontroller Software Interface Standard) register definitions such as GCLK, TC3 etc... visible to your sketch.

When writing small C++ programs, I just use a simple editor such as Notepad++, then place the .h and .cpp files in a folder of the same name and deposit them in the Arduino IDE libraries directory. It's then possible to include the header file in your sketch and compile using the Arduino IDE. If there are any errors in your C++ code the compiler in the Arduino IDE will flag them up. This should allow the register definitions to become visible in your sketch.

In your code, I suggest removing #include <Arduino.h> line from your .cpp file, as it's already been included in the header file. Also, the micros2() function should return an unsigned long value.

The TC3_Handler() function has already been declared outside the scope of you C++ class, in the Atmel CMSIS "samd21g18a.h" file:

//...
void TCC0_Handler                ( void );
void TCC1_Handler                ( void );
void TCC2_Handler                ( void );
void TC3_Handler                 ( void );
void TC4_Handler                 ( void );
void TC5_Handler                 ( void );
//...

One way to implement this to create a static C++ member function, say: static void TC3_IrqHandler(), then call this from the TC3_Handler() function at the bottom of the .cpp file:

void TC3_Handler()            // TC3 Interrupt Service Routine
{
  micros2::TC3_IrqHandler();  // Call the micros2() interrupt handler function 
}

Another option is to declare a micro2() object, by including the line:

extern micros2 micros2;

... at the bottom of the .h file, then instantiate (define) it at the bottom of the .cpp file:

micros2 micros2();

... following this you can just call on the non-static C++ member function: void TC3_IrqHandler(), also at the bottom of the .cpp file:

void TC3_Handler()            // TC3 Interrupt Service Routine
{
  micros2.TC3_IrqHandler();  // Call the micros2() interrupt handler function 
}

Hi Martin,

thank you soo much for your support and help!
I haven't tried your hints but I will do that in the next days for sure.

I wish you a Merry Christmas and a Happy New Year!

Best regards,
Alex

Hi Martin,

I am very happy to let you know that its working now :smiley:
thank you sooo much for your help!

With best regards,
Alex

Hi Martin,

At the moment, both receiver libraries working with ARDUINO MKR 1010 Wifi, the ISR callback functions and the micros2() function but for some mysterious reasons, the attachInterrupt - ISR functions stop working after about 30-40 mins. All other functions like webserver combined with transmitting signals etc. is still running. Just the receiving part with the micros2() and the attachInterrupt() function is not working anymore. I am using the CHANGE mode for the attachInterrupt() and I have directly connected the receiver output wire directly to two input pins of the microcontroller. One pin is for one receiver library and the other pin for the other library. So I am using two ISR callback functions at the same time with the same micros2() function. Do I need to reset the interrupt flag or something else? At the ARDUINO YUN it worked over years without any problem. Do you know what the reason could be?

Thank you very much!
With best regards
Alex

Hi Alex,

It shouldn't be necessary to write to the interrupt flags to clear them, as this is done automatically by the Arduino code, (in the EIC_Handler() interrupt service routine).

Could it be the micros2() counter rolling over? Roll overs need to be handled in a particular way. An excellent explanation is provided on Nick Gammon's website: Gammon Forum : Electronics : Microprocessors : millis() overflow ... a bad thing?.

The micros2() function rolls over every 9 minutes or so.

EDIT: This is wrong, actually the micros2() function rolls over every 70 minutes or so like micros().

Kind regards,
Martin

Hi Martin,

thank you for the reply.
I am using that function for the micros2:

volatile unsigned long timer2Counter;

// Micros2 is used to measure the receiver pulsewidths down to 1us accuracy
uint32_t micros2()
{
  uint32_t m;
  uint8_t t;
     
  noInterrupts();                                 // Disable interrupts
  m = timer2Counter;                              // Get the number of overflows
  t = TC3->COUNT8.COUNT.reg;                      // Get the current TC3 count value

  if (TC3->COUNT8.INTFLAG.bit.OVF && (t < 255))   // Check if the timer has just overflowed (and we've missed it)
  {
    m++;                                          // Then in this case increment the overflow counter
  } 
  interrupts();                                   // Enable interrupts
  return ((m << 8) + t) / 2;                      // Return the number of microseconds that have occured since the timer started
}

// This ISR is called every 128us
void TC3_Handler()           // ISR TC3 overflow callback function
{
  if (TC3->COUNT8.INTFLAG.bit.OVF)
  {
    timer2Counter++;           // Increment the overflow counter
  }
  TC3->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF;   // Rest the overflow interrupt flag
}

Do you think there could the problem be?

Best regards
Alex

Hi Alex,

Thanks for the code snippet.

Have you also set-up the continous read synchronization in the setup() portion of the code?:

REG_TC3_READREQ = TC_READREQ_RCONT |            // Enable a continuous read request
                  TC_READREQ_ADDR(0x10);        // Offset of the 8 bit COUNT register
while (TC3->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for (read) synchronization

Might I ask how you're using or calling the micros2() function in your attachInterrupt()'s callback function?

Kind regards,
Martin

Hi Martin,

I think I added the important code snippet you described. I used the following code:

  //***********************************************************************************
  // Micros2 function for ARDUINO MKR SAMD21 Processor
  //***********************************************************************************

  // Set up the generic clock (GCLK4) used to clock timers
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) |          // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
                    GCLK_GENDIV_ID(4);             // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |         // Enable GCLK4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                      GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization
  
  // Feed GCLK4 to TCC2 (and TC3)
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC2 (and TC3)
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed GCLK4 to TCC2 (and TC3)
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  TC3->COUNT8.PER.reg = 0xFF;                      // Set period register to 255
  while (TC3->COUNT8.STATUS.bit.SYNCBUSY);         // Wait for synchronization

  TC3->COUNT8.INTENSET.reg = /*TC_INTENSET_MC1 | TC_INTENSET_MC0 |*/ TC_INTENSET_OVF; // Enable TC3 interrupts
  
  //NVIC_DisableIRQ(TC3_IRQn);
  //NVIC_ClearPendingIRQ(TC3_IRQn);
  NVIC_SetPriority(TC3_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC3 to 0 (highest) 
  NVIC_EnableIRQ(TC3_IRQn);         // Connect TC3 to Nested Vector Interrupt Controller (NVIC)

  // Set the TC3 timer to tick at 2MHz, or in other words a period of 0.5us - timer overflows every 128us 
  // timer counts up to (up to 255 in 128us)
  TC3->COUNT8.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV8 |      // Set prescaler to 8, 16MHz/8 = 2MHz
                           TC_CTRLA_PRESCSYNC_PRESC |     // Set the reset/reload to trigger on prescaler clock
                           TC_CTRLA_MODE_COUNT8;          // Set the counter to 8-bit mode
                            
  TC3->COUNT8.CTRLA.bit.ENABLE = 1;               // Enable TC3
  while (TC3->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for synchronization

  TC3->COUNT8.READREQ.reg = TC_READREQ_RCONT |            // Enable a continuous read request
                            TC_READREQ_ADDR(0x10);        // Offset of the 8 bit COUNT register
  while (TC3->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for (read) synchronization

  //***********************************************************************************
  //***********************************************************************************

I tried the two receiver libraries with the micros2() function without any other additional services like webserver etc. and now it seems to work for one hour now. I will try to figure it out if it works for a longer period of time.

Hi Martin,

I have to revise the previous findings. After about 60-70mins the interrupt function didn't work anymore. So it is still the problem of the receiving libraries or the micros2() function.

The attachedInterrupt calls a function of the receiver class which contains the micros2() function: (it is just a code snippet of the function)

	static byte receivedBit;		// Contains "bit" currently receiving
	static NewRemoteCode receivedCode;		// Contains received code
	static NewRemoteCode previousCode;		// Contains previous received code
	static byte repeats = 0;		// The number of times the an identical code is received in a row.
	static unsigned long edgeTimeStamp[3] = {0, };	// Timestamp of edges
	static unsigned int min1Period, max1Period, min5Period, max5Period;
	static bool skip;

	// Filter out too short pulses. This method works as a low pass filter.
	edgeTimeStamp[1] = edgeTimeStamp[2];
	edgeTimeStamp[2] = micros2();

	if (skip) {
		skip = false;
		return;
	}

	if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) {
		// Last edge was too short.
		// Skip this edge, and the next too.
		skip = true;
		return;
	}

	unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0];
	edgeTimeStamp[0] = edgeTimeStamp[1];

Best regards

Hi Alex,

I mistakenly thought that the micros2() function rolled over after approximately 9 minutes, but actually the roll over is the same as the micros() function, around 70 minutes (1us * 2^32). This coincidentally matches your 60-70min of run time.

I ran a test comparing the output of both micros() and micros2() functions for over 90 minutes. Both rolled over without any issues and remained in sync throughout.

This suggests that the issue is in the code that calls the micros2() function, rather than within the function itself.

Kind regards,
Martin

Hi Martin,

thank you very much for running tests to identify the problem!
I didn't found the problem yet, but I will let you know if I find something new.

With best regards
Alexander

Hi Martin,

at the moment I am using for the micros2() function the following .h file:

#ifndef micros2_h
#define micros2_h

#include <Arduino.h>

#ifdef __cplusplus
extern "C" {
#endif


// ...

extern unsigned long micros2( void );

// ...




#ifdef __cplusplus
}
#endif

#endif

and for the .cpp file:

#include "micros2.h"

//***********************************************************************************
// Micros2 function for ARDUINO MKR SAMD21 Processor
//***********************************************************************************

volatile unsigned long timer2Counter;

// Micros2 is used to measure the receiver pulsewidths down to 1us accuracy
unsigned long micros2( void ) 
{
  uint32_t m;
  uint8_t t;
     
  noInterrupts();                                 // Disable interrupts
  m = timer2Counter;                              // Get the number of overflows
  t = TC3->COUNT8.COUNT.reg;                      // Get the current TC3 count value

  if (TC3->COUNT8.INTFLAG.bit.OVF && (t < 255))   // Check if the timer has just overflowed (and we've missed it)
  {
    m++;                                          // Then in this case increment the overflow counter
  }  
  interrupts();                                   // Enable interrupts
  return ((m << 8) + t) / 2;                      // Return the number of microseconds that have occured since the timer started
}

// This ISR is called every 128us
void TC3_Handler()                    // ISR TC3 overflow callback function
{
  if (TC3->COUNT8.INTFLAG.bit.OVF)
  {
    timer2Counter++;                             // Increment the overflow counter
  }
  TC3->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF;      // Rest the overflow interrupt flag
}   

//***********************************************************************************
//***********************************************************************************

Do you think there is a mistake inside the code?
The thing is, I used for the receiver functions the micros() instead of the micros2() function with an Arduino YUN and it is working without any problems..
As soon as I am just using the micros2() and the Arduino MKR 1010 Wifi it is working but just for 60-70mins..

Thank you in advance.
With best regards
Alex

Hi Alex,

The micros2() code is essentially the same as the micros() code used by the Arduino Yun, except that the SAMD21's timer is running 8 times faster to provide an accuracy of 0.5us rather than 4us.

The timer will rollover after 71 minutes, 35 seconds.

Is your code failing at a roughly between 60-70 minutes, or does it occur at an exact moment everytime?

What is the output of the micros2() function at the time of failure?

Kind regards,
Martin

Hi Martin,

sorry for the late reply.
I tried out a very simple code. I called every second the micros2() function without any additional functions inside loop. (no attachInterrupt function and no receiver functions)

  calls++;

  t = micros2();

  Serial.println("calls of micros function: ");
  Serial.println(calls);

  Serial.println(" ");
  Serial.println("micros output: ");
  Serial.println(t);

  delay(1000);

The output looks like follows:

...
micros output:
2147413951
calls of micros function:
2144

micros output:
930303
calls of micros function:
2145
...

-> the first rollover occurred after about 35.79 seconds.

...
micros output:
2146930303
calls of micros function:
4291

micros output:
930303
calls of micros function:
4292

-> the second rollover occurred after about 35.78 seconds.

the micros2() function works without any problems and after several rollovers.
I do not know why it occurs at every 35.7 seconds and not every 71,3 seconds.
But it works.

So the next tests will be, to call the micros2() function inside the receiver libraries.
The whole code with the receiver libraries called via an attachInterrupt function fails roughly between 60-70 minutes.

I will let you know if I will find something new.

Hi Alex,

Yes you're right, the micros2() function is rolling over every 35.7 minutes.

I missed this in my first test, because I only looked the results only after 71.3 minutes. At which point both outputs had rolled over (the micros2() function for the second time) and were therefore the same.

The reason is the return value of the micros2() function:

return ((m << 8) + t) / 2;

In this instance we're counting the number of 0.5us timer ticks and dividing by 2. The problem is that the 32-bit unsigned integer output overflows before the division by 2 occurs.

The Arduino Yun by comparison is counting the number of 4us timer ticks, then multiplying by 4:

return ((m << 8) + t) * 4;

...therefore this overflow issue doesn't happen.

To make the micros2() and micro() function rollover at the same time, is necessary to adjust the micros2() function to count 1us increments.

Just change the micros2() return value line, to remove the divide by 2:

return ((m << 8) + t);

...and slow down the timer by increasing its prescaler divider from 8 to 16:

TC3->COUNT8.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16 |     // Set prescaler to 16, 16MHz/16 = 1MHz
                         TC_CTRLA_PRESCSYNC_PRESC |     // Set the reset/reload to trigger on prescaler clock
                         TC_CTRLA_MODE_COUNT8;          // Set the counter to 8-bit mode

I don't think that the rollover time is the reason for your code not functioning after 60-70 minutes though. The only time this could become an issue, is if your time between calling the micros2() function is greater than 35.7 minutes, (or 71.3 minutes with the code adjustments above).

Hi Martin,

I tried it out and changed the counting and the prescaler as you mentioned before.
The whole code incl. the receiver libraries still running for 15 hours without any problem now.

Thank you soo much for your help :smiley:

Do you think this settings influence the attachinterrupt function of the MKR1010 in some case?

With best regards,
Alex

Hi Alex,

Glad to hear that it's now working.

Do you think this settings influence the attachinterrupt function of the MKR1010 in some case?

I think the problem was caused by the micros2() function, but occured when subtracting the edgeTimeStamps[].

It's something that I hadn't considered until now, but subtracting two edgeTimeStamps[] unsigned long values to get the time difference (in microseconds), only works if the micros2() function also rolls over at the unsigned long maximum value. If the micros2() function rolls over too early and you subtract the unsigned long variables, you get some horrendously large value instead of the difference between them.

Now that the micros2() and the edgeTimeStamps[] variables are rolling over at the same point, your code should now function correctly.

Thanks Alex, looks like I'm going to have to change the micros2() function in my code as well.

Kind regards,
Martin

I am looking to count events using TCC2 (SAMD21), specifically I have a step and dir pin and would like the dir pin to change direction of count and the step pin to increment/decrease count.

I have not been able to get his working any if anyone might see my issue?

#define WAIT_TCC2_SYNC() while(TCC2->SYNCBUSY.reg)

void enableEIC(void)
{
PM->APBAMASK.reg |= PM_APBAMASK_EIC;
if (EIC->CTRL.bit.ENABLE == 0)
{
// Enable GCLK for IEC (External Interrupt Controller)
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC));

// Enable EIC
EIC->CTRL.bit.ENABLE = 1;
while (EIC->STATUS.bit.SYNCBUSY == 1) { }
}
}

void setupStepEvent(void)
{
//we will set up the EIC to generate an even on rising edge of step pin
//make sure EIC is setup
enableEIC();

// Assign step pin to EIC
// Step pin is PA11, EXTINT11
pinPeripheral(PIN_STEP_INPUT, PIO_EXTINT);

//set up the direction pin PA10 to trigger external interrupt
pinPeripheral(PIN_DIR_INPUT, PIO_EXTINT); //EXTINT10

//***** setup EIC ******
EIC->EVCTRL.bit.EXTINTEO11=1; //enable event for EXTINT11
EIC->EVCTRL.bit.EXTINTEO10=1; //enable event for EXTINT10
//setup up external interurpt 11 to be rising edge triggered
//setup up external interurpt 10 to be both edge triggered
EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE3_RISE | EIC_CONFIG_SENSE2_BOTH;

//diable actually generating an interrupt, we only want event triggered
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT11;
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;

//**** setup the event system ***
// Enable GCLK for EVSYS channel 0
PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;

GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EVSYS_CHANNEL_0));
while (GCLK->STATUS.bit.SYNCBUSY);
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EVSYS_CHANNEL_1));
while (GCLK->STATUS.bit.SYNCBUSY);

//setup the step pin to trigger event 0 on the TCC2 (step)
EVSYS->CHANNEL.reg=EVSYS_CHANNEL_CHANNEL(0)
| EVSYS_CHANNEL_EDGSEL_RISING_EDGE
| EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_11)
| EVSYS_CHANNEL_PATH_ASYNCHRONOUS;

EVSYS->USER.reg = EVSYS_USER_CHANNEL(1)
| EVSYS_USER_USER(EVSYS_ID_USER_TCC2_EV_0);

//setup the dir pin to trigger event 2 on the TCC2 (dir change)
EVSYS->CHANNEL.reg=EVSYS_CHANNEL_CHANNEL(1)
| EVSYS_CHANNEL_EDGSEL_RISING_EDGE
| EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10)
| EVSYS_CHANNEL_PATH_ASYNCHRONOUS;

EVSYS->USER.reg = EVSYS_USER_CHANNEL(2)
| EVSYS_USER_USER(EVSYS_ID_USER_TCC2_EV_1);

//**** setup the Timer counter ******
PM->APBCMASK.reg |= PM_APBCMASK_TCC2;
// Enable GCLK for TC4 and TC5 (timer counter input clock)
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3));
while (GCLK->STATUS.bit.SYNCBUSY);

TCC2->CTRLA.reg= TCC_CTRLA_SWRST; //reset TCC2
WAIT_TCC2_SYNC();
while(TCC2->CTRLA.bit.SWRST ==1);

TCC2->EVCTRL.reg=TCC_EVCTRL_EVACT0_COUNTEV | TCC_EVCTRL_EVACT1_DIR | TCC_EVCTRL_TCEI0 | TCC_EVCTRL_TCEI1;
WAIT_TCC2_SYNC();

TCC2->PER.reg=0x07FFFFF;
WAIT_TCC2_SYNC();

TCC2->COUNT.reg=0;
WAIT_TCC2_SYNC();

//TCC2->CTRLBSET.bit.CMD=TCC_CTRLBSET_CMD_RETRIGGER;
checkDirPin();

WAIT_TCC2_SYNC();
TCC2->CTRLA.reg |=TCC_CTRLA_ENABLE;
WAIT_TCC2_SYNC();

checkDirPin();
}