Arduino Zero SAM(D21) hardware counter as simple input counter intialization?

Hi Helium328PU,

Your options are to either simply count the number of incoming pulses using the attachInterrupt() function and an interrupt service routine (ISR), or alternatively route the pulses through the SAMD21's External Interrupt Controller (EIC) and on to a TC timer using the Event System. The TC timer is configured to count the incoming pulses. The Event System is a 12-channel highway for peripheral-to-peripheral communications without CPU intervention. The latter option has the advantage that it isn't necessary to call the ISR each time a pulse is received; the whole process occurs without any CPU intervention, apart from reading the timer's COUNT register.

Here's some example code that takes the incoming pulses on D12 (on the Arduino Zero) a.k.a port pin PA19 and routes these through the EIC to timer TC4 via the Event System. TC4 is configured to count the incoming pulses and is set to 32-bit mode in conjunction with TC5. The number or counts is output to the console every second:

// Setup TC4 in 32-bit mode to count incoming pulses on digital pin D12 using the Event System
void setup()
{
  // Serial Communication /////////////////////////////////////////////////////////////////
  
  SerialUSB.begin(115200);                        // Send data back on the Zero's native port
  while(!SerialUSB);                              // Wait for the SerialUSB port to be ready
  
 // Generic Clock /////////////////////////////////////////////////////////////////////////
 
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |        // Enable the generic clock...
                      GCLK_CLKCTRL_GEN_GCLK0 |    // On GCLK0 at 48MHz
                      GCLK_CLKCTRL_ID_TC4_TC5;    // Route GCLK0 to TC4 and TC5
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Port Configuration ///////////////////////////////////////////////////////////////////

  // Enable the port multiplexer on digital pin D12 (port pin PA19)
  PORT->Group[g_APinDescription[12].ulPort].PINCFG[g_APinDescription[12].ulPin].bit.PMUXEN = 1;
  // Set-up the pin as an EIC (interrupt) peripheral on D12
  PORT->Group[g_APinDescription[12].ulPort].PMUX[g_APinDescription[12].ulPin >> 1].reg |= PORT_PMUX_PMUXO_A;

  // External Interrupt Controller (EIC) ///////////////////////////////////////////////////

  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO3;                                // Enable event output on external interrupt 3 (D12)
  EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE3_HIGH;                           // Set event detecting a HIGH level on interrupt 3
  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT3;                               // Disable interrupts on interrupt 3
  EIC->CTRL.bit.ENABLE = 1;                                               // Enable the EIC peripheral
  while (EIC->STATUS.bit.SYNCBUSY);                                       // Wait for synchronization

  // Event System //////////////////////////////////////////////////////////////////////////

  PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;                                  // Switch on the event system peripheral

  EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) |                               // Attach the event user (receiver) to channel 0 (n + 1)
                    EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU);               // Set the event user (receiver) as timer TC4
  
  EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |               // No event edge detection
                       EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                  // Set event path as asynchronous
                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_3) |   // Set event generator (sender) as external interrupt 3
                       EVSYS_CHANNEL_CHANNEL(0);                          // Attach the generator (sender) to channel 0                                 
  
  // Timer Counter TC4 /////////////////////////////////////////////////////////////////////

  TC4->COUNT32.EVCTRL.reg |= TC_EVCTRL_TCEI |              // Enable asynchronous events on the TC timer
                             TC_EVCTRL_EVACT_COUNT;        // Increment the TC timer each time an event is received

  TC4->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32;          // Configure TC4 together with TC5 to operate in 32-bit mode
                      
  TC4->COUNT32.CTRLA.bit.ENABLE = 1;                       // Enable TC4
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Wait for synchronization

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

void loop()
{
  SerialUSB.println(TC4->COUNT32.COUNT.reg);               // Output the results
  delay(1000);                                             // Wait for 1 second
}