Go Down

Topic: one shot timer with external trigger (Read 432 times) previous topic - next topic


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

set countdown value
start countdown irq

countdown_irq() { clr pins }

anyone know a quick way to do this


Jan 21, 2019, 09:23 am Last Edit: Jan 21, 2019, 09:26 am by MartinL
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:

Code: [Select]
// 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
  // 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

Go Up