one shot timer with external trigger

ok so i have gone over the data sheets a ton and i just can't figure out how to setup a
one shot timer

i have an external interrupt running some code and turning a few pins on (no digital write, setting ports directly)
but have a set time (50ms) i need to turn the pins off but i have serial + i2c data going on so need to get in and out and mills is just nowhere near reliable I need 50ms pulse 100% of the time but still need to change it at times.

pseudo code

ext_irq()
{
set_pin_high:
set countdown value
start countdown irq
}

countdown_irq() { clr pins }

anyone know a quick way to do this

Hi techmasterjoe24,

Probably the easiest way to do this is to use the oneshot function on the TCC0 timer.

The following code sets up a RISING edge interrupt on digital pin D12, using the attachInterrupt() function. The TCC0 timer is then configured for oneshot operation and to output a 50ms pulse on digital pin D7, each time the oneshot is triggered.

When the interrupt function is called, it simply triggers the oneshot, causing the TCC0 timer to output a 50ms pulse:

// Output a 50ms pulse on D7 when a RISING interrupt is received on D12
void setup()
{
  attachInterrupt(12, interrupt, RISING);         // Set-up an interrupt on digital pin D12
  
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) |         // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
                     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

  // Enable the port multiplexer for the TCC0 PWM channel 3 (digital pin D7), SAMD21 pin PA21
  PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;
  
  // Connect the TCC0 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
  // F & E specify the timers: TCC0, TCC1 and TCC2
  PORT->Group[g_APinDescription[7].ulPort].PMUX[g_APinDescription[7].ulPin >> 1].reg |= /*PORT_PMUX_PMUXO_F |*/ PORT_PMUX_PMUXO_F;

  // Feed GCLK4 to TCC0 and TCC1
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  // Normal (single slope) PWM operation: timer countinuouslys count up to PER register value and then is reset to 0
  TCC0->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;         // Setup single slope PWM on TCC0
  while (TCC0->SYNCBUSY.bit.WAVE);                 // Wait for synchronization
  
  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation:
  TCC0->PER.reg = 2399999;                         // Set the frequency of the PWM on TCC0 to 20Hz or 50ms
  while (TCC0->SYNCBUSY.bit.PER);

  // The CCBx register value corresponds a 50ms pulsewidth
  TCC0->CC[3].reg = 2399999;                        // TCC0 CCB3 - 100% duty cycle on D7
  while (TCC0->SYNCBUSY.bit.CC3);

  TCC0->CTRLBSET.reg = TCC_CTRLBSET_ONESHOT;        // Enable oneshot
  while (TCC0->SYNCBUSY.bit.CTRLB);                 // Wait for synchronization

  // Set oneshot operation to output 0V when the timer is stopped on PA21, channel W0[7] = TCC0 channel 3 output
  TCC0->DRVCTRL.reg |= TCC_DRVCTRL_NRE7;
  
  // Divide the 48MHz signal by 1 giving 48MHz (20.8ns) TCC0 timer tick and enable the outputs
  TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1;      // Divide GCLK4 by 1

  // Divide the 48MHz signal by 1 giving 48MHz (20.8ns) TCC0 timer tick and enable the outputs
  TCC0->CTRLA.bit.ENABLE = 1;                       // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);                // Wait for synchronization
}

void loop() {}

void interrupt()
{
  if (TCC0->STATUS.bit.STOP)                                 // Check if the previous pulse is complete
  {
    TCC0->CTRLBSET.reg = TCC_CTRLBSET_CMD_RETRIGGER;         // Retrigger the timer's One/Multi-Shot pulse
    while (TCC0->SYNCBUSY.bit.CTRLB);                        // Wait for synchronization
  }
}

it works as written and thank you
based on your code I'm going to see if it can be tweaked to run on TC4(1) aka PB09 on d21J as this is a custom board kinda my take on an Industrial Arduino
I can use it as is just learn more from messing with it