Go Down

Topic: OneShot timer on pin rising edge (Read 2248 times) previous topic - next topic

MartinL

Hi LeCrAm,

The easiest way is probably to set the TCC0's duty-cycle to 0, using the counter compare (CC0) register. The timer will retrigger as usual, but no pulse will be output:

Code: [Select]
TCC0->CC[0].reg = 0;             // Set the duty-cycle to 0
while(TCC0->SYNCBUSY.bit.CC0);   // Wait for synchronization

LeCrAm

#16
Jul 01, 2020, 11:28 am Last Edit: Jul 01, 2020, 12:17 pm by LeCrAm
Hi Martin, maybe I didn't explained well, The only thing I would like to achieve is to prevent that TC4_Handler will be fired by resetting/clearing/restarting the counter with higher frequency signal, this means if this higher frequency signal is dissapears, the counter will not be resetted anymore and TC4 will fire with a frequency of 10KHz:

Code: [Select]

void init_start_timer()
{
// Set up the generic clock (GCLK4) used to clock timers
  REG_GCLK_GENDIV = 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

  REG_GCLK_GENCTRL = 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 TC4 and TC5
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TC4 and TC5
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TC4_TC5;     // Feed the GCLK4 to TC4 and TC5
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
 
  REG_TC4_COUNT16_CC0 = 0x12C0;                   // Set the TC4 CC0 register as the TOP value in match frequency mode
  while (TC4->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization

  //NVIC_DisableIRQ(TC4_IRQn);
  //NVIC_ClearPendingIRQ(TC4_IRQn);
  NVIC_SetPriority(TC4_IRQn, 0);                  // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
  NVIC_EnableIRQ(TC4_IRQn);                       // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

  REG_TC4_INTFLAG |= TC_INTFLAG_OVF;              // Clear the interrupt flags
  REG_TC4_INTENSET = TC_INTENSET_OVF;             // Enable TC4 interrupts
  // REG_TC4_INTENCLR = TC_INTENCLR_OVF;          // Disable TC4 interrupts
 
  REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV1 |      // Set prescaler to 1, 48MHz/1024 = 46.875kHz
                   TC_CTRLA_WAVEGEN_MFRQ |        // Put the timer TC4 into match frequency (MFRQ) mode
                   TC_CTRLA_ENABLE;               // Enable TC4
  while (TC4->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization
 
}

void TC4_Handler()                              // Interrupt Service Routine (ISR) for timer TC4
{     
  // Check for overflow (OVF) interrupt
  if (TC4->COUNT16.INTFLAG.bit.OVF && TC4->COUNT16.INTENSET.bit.OVF)             
  {
      // Manual triggering     
      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
      }
     
    REG_TC4_INTFLAG = TC_INTFLAG_OVF;         // Clear the OVF interrupt flag
  }
}

LeCrAm

I figured out in the meantime, by disabling/enabling again, the counter resets:

Code: [Select]

  // Reset 10KHz timer counter
  TC4->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; // disable
  while (TC4->COUNT16.STATUS.bit.SYNCBUSY);                             // Wait for synchronization
  TC4->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; // enable
  while (TC4->COUNT16.STATUS.bit.SYNCBUSY);                             // Wait for synchronization

MartinL

Quote
I figured out in the meantime, by disabling/enabling again, the counter resets:
But disabling the timer will also float (or tri-state) its outputs.

It's possible to turn off the TC4_Handler function by clearing the overflow bit in the INTENCLR register:

Code: [Select]
TC4->COUNT16.INTENCLR.reg = TC_INTENCLR_OVF;  // Disable overflow (OVF) interrupts

LeCrAm

#19
Jul 27, 2020, 09:50 am Last Edit: Jul 27, 2020, 09:51 am by LeCrAm
Martin,

Thanks for your support!

An additional question, I'm using TCC0 for the oneshot functionality, is it also possible to use an additional/independent oneshot timer on TCC1? This oneshot timer on TCC1 should be triggered by software only, without external trigger by digital input.

The oneshot output should be D8 (PA06).

LeCrAm

#20
Jul 27, 2020, 10:07 am Last Edit: Jul 27, 2020, 10:10 am by LeCrAm
Seems I have answered my own question....

Code: [Select]

PORT->Group[g_APinDescription[8].ulPort].PINCFG[g_APinDescription[8].ulPin].bit.PMUXEN = 1;
PORT->Group[g_APinDescription[8].ulPort].PMUX[g_APinDescription[8].ulPin >> 1].reg |= PORT_PMUX_PMUXE_E;

TCC1->CTRLA.reg = TC_CTRLA_PRESCALER_DIV8 |        // Set prescaler to 8, 48MHz/8 = 6MHz
                  TC_CTRLA_PRESCSYNC_PRESC;        // Set the reset/reload to trigger on prescaler clock                 

TCC1->CTRLBSET.reg = TCC_CTRLBSET_ONESHOT;         // Enable one shot
while (TCC1->SYNCBUSY.bit.CTRLB);                  // Wait for synchronization

TCC1->DRVCTRL.reg |= TCC_DRVCTRL_NRE2;             // Continue to drive the output on TCC1/WO[2] when timer has stopped (rather than becoming tri-state)
TCC1->DRVCTRL.reg |= TCC_DRVCTRL_INVEN2;           // Invert the output to generate an active low pulse on TCC1/WO[2]

TCC1->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;             // Set-up TCC1 timer for Normal (single slope) PWM mode (NPWM)
while (TCC1->SYNCBUSY.bit.WAVE)                    // Wait for synchronization

TCC1->PER.reg = 8999;                              // Set-up the PER (period) register for 1500us pulse period
while (TCC1->SYNCBUSY.bit.PER);                    // Wait for synchronization

TCC1->CC[0].reg = 8999;                            // Set-up the CC (counter compare), channel 2 register for 1500us pulse width
while (TCC1->SYNCBUSY.bit.CC0);                    // Wait for synchronization

TCC1->CTRLA.bit.ENABLE = 1;                        // Enable timer TCC1
while (TCC1->SYNCBUSY.bit.ENABLE);                 // Wait for synchronization


Still I don't understand these registers:
- TCC_DRVCTRL_NRE2
- TCC_DRVCTRL_INVEN2

How is this number 2 linked to the pin?

LeCrAm

After the init of the oneshot timer, a pulse is generated, how can I prevent this first pulse after init?

Juraj

After the init of the oneshot timer, a pulse is generated, how can I prevent this first pulse after init?
see the datasheet. I have in my code

TCC->CTRLBSET.reg = TCC_CTRLBSET_ONESHOT | TCC_CTRLBSET_DIR; //one shot and count down


LeCrAm


LeCrAm

The oneshot timer works OK, but sometimes I need to update the values:

Code: [Select]

  TCC1->PER.reg = new_value;                        // Set the new value
  while (TCC1->SYNCBUSY.bit.PER);                          // Wait for synchronization       
  TCC1->CC[0].reg = (new_value>>1);                 // Set-up the CC (counter compare)
  while (TCC1->SYNCBUSY.bit.CC0);                          // Wait for synchronization   


Only the first time I fire the oneshot timer after updating the values:

Code: [Select]

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


The timing doesn't seem to be right, the second time I fire the oneshot, it is OK. It seems the period is several ms late/early.

What can be wrong here?

Go Up