SAMD21 with 96MHz counter?

I have this ingenious code from MartinL that counts clocks on pin PA20. That even goes up to 20MHz. I have now read in the manual on page 939 (36.5 Maximum Clock Frequencies) that the timers TCC0, TCC1, TCC2 and TC3 even work up to 96 MHz input clock frequency. Do I understand this in the right manner? Can I do this with a code change?

  ////////////////////////////////////////////////////////////////////////////////////////
  // Event system peripheral
  ////////////////////////////////////////////////////////////////////////////////////////

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

  GCLK->GENDIV.reg =  GCLK_GENDIV_DIV(1) |          // Select clock divisor to 1                     
                      GCLK_GENDIV_ID(4);            // Select GLCK4         
 
  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |            // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |          // Enable GCLK                   
                      GCLK_GENCTRL_SRC_XOSC32K |    // Select GCLK source as external 32.768kHz crystal (XOSC32K)                         
                      GCLK_GENCTRL_ID(4);           // Select GCLK4             
  while (GCLK->STATUS.bit.SYNCBUSY);                // Wait for synchronization

  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |          // Enable generic clock
                      GCLK_CLKCTRL_GEN_GCLK0 |      // GCLK0 at 48MHz
                      GCLK_CLKCTRL_ID_TC4_TC5;      // As a clock source for TC4 and TC5
 
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |          // Enable generic clock
                      GCLK_CLKCTRL_GEN_GCLK4 |      // GCLK4 at 32.768kHz
                      GCLK_CLKCTRL_ID_TCC2_TC3;     // As a clock source for TCC2 and TC3

  ////////////////////////////////////////////////////////////////////////////////////////
  // TC4 Initialisation - measurement counter: counts the number incoming of pulses
  ////////////////////////////////////////////////////////////////////////////////////////

  //---D6 (PA20)--------------------------------
  PORT->Group[PORTA].PINCFG[20].bit.PMUXEN = 1;                            // Enable the port multiplexer on port pin PA20 (D6)
  PORT->Group[PORTA].PMUX[20 >> 1].reg |= PORT_PMUX_PMUXE_A;               // Set-up PA20 (D6) as an EIC (interrupt)
 
  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO4;                                 // Enable event output on external interrupt 4
  EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;                            // Set event detecting a HIGH level
  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4;                                // Clear the interrupt flag on channel 4
  EIC->CTRL.bit.ENABLE = 1;                                                // Enable EIC peripheral
  while (EIC->STATUS.bit.SYNCBUSY);                                        // Wait for synchronization
 
  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 event
                   
  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_4) |    // Set event generator (sender) as external interrupt 4
                       EVSYS_CHANNEL_CHANNEL(0);                           // Attach the generator (sender) to channel 0  
  //-------------------------------------

  TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |         // Enable TC4 event input
                            TC_EVCTRL_EVACT_COUNT;   // Increment the TC4 counter upon receiving an event
                                                               
  TC4->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32;    // Chain TC4 with TC5 to create a 32-bit timer

  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

Hi @rsardu

Yes you can.

Post number #8 on the Arduino forum thread here: https://forum.arduino.cc/t/generating-varying-frequencies-on-pin-pa21-for-atsamd21g18au/897380/7, details how to set up the 96MHz fractional digital locked loop.

Once DPLL has achieved lock, it's possible to route the 96MHz clock on to one of the spare generic clocks, to act as a clock source for one of the faster timers. Note that according to the datasheet (same maximum clock frequency table), the generic clock should remain undivided at this higher speed.

1 Like

Hello Martin, thanks for your endless help. At the moment I don't have a setup to try that out. But I will definitely try it in the future!