How to use TCC (Timer Counter/Control)

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
noldwil
 
Posts: 15
Joined: Wed Jul 01, 2020 4:52 am

How to use TCC (Timer Counter/Control)

Post by noldwil »

I am using an Adafruit Feather M0 RFM69 Packet Radio 433MHz, Part-No.3177 (AT-SAMD21-G18 ARM Cortex M0)
and I am pretty helpless with the TCC (Timer Counter for Control Applications). I have found some code-examples on internet but can't understand the effects of some codelines due to the lack of a reasonable manual or learning script. Maybe you have an idea, where to find one? (The following document didn't really help me: http://ww1.microchip.com/downloads/en/D ... T07058.pdf)

What I would like to do with my Controller is a Timer-Interrupt-Routine, within this I can change the time (Duration). I don't understand the difference respectively impact of the Interrupt between TCC1->CC[0].reg = 0xFFFFFF; and TCC1->PER.reg = 0xFFFFFF; TCC1 has no influence on the interrupt call!?

Code: Select all

void setup()
{
  //Divide the 48MHz system clock by 1 = 48MHz. Set division on Generic Clock Generator (GCLK) 4
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) | GCLK_GENDIV_ID(4);
  while (GCLK->STATUS.bit.SYNCBUSY);
  
  //Set the duty cycle to 50/50 HIGH/LOW. Enable GCLK 4. Set the clock source to 48MHz. Set clock source on GCLK 4
  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(4);
  while (GCLK->STATUS.bit.SYNCBUSY);
  
  //Enable the generic clock on GCLK4. Feed the GCLK4 to TCC1 and TCC1
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK4 | GCLK_CLKCTRL_ID_TCC0_TCC1;
  while (GCLK->STATUS.bit.SYNCBUSY);
 
  //Set prescaler to 1, 48Mhz. Reload timer on next prescaler clock, use if prescaler DIV is more than 1
  TCC1->CTRLA.reg = TC_CTRLA_PRESCSYNC_PRESC | TCC_CTRLA_PRESCALER_DIV1;
  //Set the Nested Vector Interrupt Controller (NVIC) priority for TCC1 to 0 (highest)
  NVIC_SetPriority(TCC1_IRQn, 0);
  
  //Connect TCC1 to Nested Vector Interrupt Controller (NVIC)
  NVIC_EnableIRQ(TCC1_IRQn);
  
  //Enable TCC1 MC0-interrupt
  TCC1->INTENSET.reg = TCC_INTENSET_MC0;
  
  //Setup normal frequency operation on TCC1
  TCC1->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ;
  while (TCC1->SYNCBUSY.bit.WAVE);
 
  //Set the frequency of the timer
  TCC1->PER.reg = 0xFFFFFF;
  while(TCC1->SYNCBUSY.bit.PER);
  
  //Set counter compare to 58usec
  TCC1->CC[0].reg = 0xFFFFFF;
  //TCC1->CC[0].reg = 0x000000;
  while(TCC1->SYNCBUSY.bit.CC0);
 
  //Enable timer TCC1
  TCC1->CTRLA.bit.ENABLE = 1;             
  while (TCC1->SYNCBUSY.bit.ENABLE);

  pinMode(5, OUTPUT);
}

void loop(){}

void TCC1_Handler() {
  static boolean toggle = true;
  if (TCC1->INTFLAG.bit.MC0)    // Test if an MC0 interrupt has occured
  {
    TCC1->INTFLAG.bit.MC0 = 1;  // Clear the interrupt flag
    digitalWrite(5, toggle);      // Toggle the LED test output
    toggle = !toggle;                      
  }
}
I am grateful for a hint (also for existing Manuals ;-)

User avatar
noldwil
 
Posts: 15
Joined: Wed Jul 01, 2020 4:52 am

Re: How to use TCC (Timer Counter/Control)

Post by noldwil »

Solved (Thanks to Arduino-Forum-Member MartinL)

Code: Select all

void setup()  //TCC1 Timer-Setup AT-SAMD21-G18 ARM Cortex M0
{
  pinMode(LED_BUILTIN, OUTPUT);

  //Divide 48MHz Systemclock by1 =48MHz. Set Division on GenericClockGenerator (GCLK) 4
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) | GCLK_GENDIV_ID(4);
  while (GCLK->STATUS.bit.SYNCBUSY);

  //Set DutyCycle 50/50 HI/LO. Enable GCLK 4. Set ClockSource 48MHz. Set ClockSource GCLK 4
  GCLK->GENCTRL.reg=GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(4);
  while (GCLK->STATUS.bit.SYNCBUSY);

  //Enable the generic clock on GCLK4. Feed the GCLK4 to TCC1 and TCC1
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK4 | GCLK_CLKCTRL_ID_TCC0_TCC1;
  while (GCLK->STATUS.bit.SYNCBUSY);

  //Set prescaler to 1, 48Mhz. Enable TCC1
  //Reload timer on next prescaler clock, use if prescaler DIV is more than
  //TCC1->CTRLA.reg = TC_CTRLA_PRESCSYNC_PRESC | TCC_CTRLA_PRESCALER_DIV1;
  
  //Set the Nested Vector Interrupt Controller (NVIC) priority for TCC1 to 0 (highest)
  NVIC_SetPriority(TCC1_IRQn, 0);

  //Connect TCC1 to Nested Vector Interrupt Controller (NVIC)
  NVIC_EnableIRQ(TCC1_IRQn);

  //Enable TCC1 OVF and MC0-Interrupt
  TCC1->INTENSET.reg = TCC_INTENSET_OVF | TCC_INTENSET_MC0;

  //Setup normal frequency operation on TCC1
  TCC1->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ;
  while (TCC1->SYNCBUSY.bit.WAVE);

  //Set the frequency of the timer
  //Timer-Frequency = Generic-Clock-Frequency / (Timer-Prescaler * (Value-PER-Register + 1))
  TCC1->PER.reg = 0xFFFFFF;
  while(TCC1->SYNCBUSY.bit.PER);

  //Set CounterCompare. Increasing Value of CC0-Register, increases the On-Time of the LED.
  TCC1->CC[0].reg = 0x00056F;
  while(TCC1->SYNCBUSY.bit.CC0);

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

//Timer TCC1 ISR. LED is cleared to LOW at the Beginning of the TimerCycle during an Overflow (OVF)
//and set to HIGH during a Match-Compare on channel 0 (MC0).
void TCC1_Handler()
 
{
  if (TCC1->INTFLAG.bit.OVF) //Test if an OVF-Interrupt has occured
  {
    TCC1->INTFLAG.bit.OVF = 1;  //Clear the Interrupt-Flag
    digitalWrite(LED_BUILTIN, LOW);  //Clear the LED-Output
  }
  if (TCC1->INTFLAG.bit.MC0)  //Test if an MC0-Interrupt has occured
  {
    TCC1->INTFLAG.bit.MC0 = 1;  //Clear the Interrupt-Flag
    digitalWrite(LED_BUILTIN, HIGH);  //Set the LED-Output
  }
}

void loop() {}

User avatar
MOlrich
 
Posts: 3
Joined: Mon Nov 27, 2017 4:23 pm

Re: How to use TCC (Timer Counter/Control)

Post by MOlrich »

I have a feather M4 Express board
I am looking to set up TCC0 W05 as a capture input
I was not getting the interrupt to trigger
looking at your code sample I forgot the NVIC Enable

when I added it I received a compile error on the NVIC lines
void setup() {
Ser.begin(9600);

pinMode(PIN_LED, OUTPUT);
pinMode(5, OUTPUT);
pinMode(16,OUTPUT);
pinMode(6,INPUT);
pinMode(0,INPUT);

TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1; // Divide GCLK0 by 1

TCC0->CTRLA.reg |= TCC_CTRLA_CPTEN5; // enable capture on chcannel 6
TCC0->EVCTRL.reg |= TCC_EVCTRL_MCEO5;

TCC0->EVCTRL.reg |= TCC_EVCTRL_MCEI5;

TCC0->INTENSET.reg |= TCC_INTENSET_MC5;

TCC0->CTRLA.reg |= TCC_CTRLA_ENABLE; // enable tcc0
while (TCC0->SYNCBUSY.bit.ENABLE);
NVIC_SetPriority(TCC0_IRQn, 0);
NVIC_EnableIRQ(TCC0_IRQn);


//TC.startTimer(100000, myISR); // 100000 usec

the TCC0_IRQn was not declared in this scope

where is this defined at?
Thanks

User avatar
noldwil
 
Posts: 15
Joined: Wed Jul 01, 2020 4:52 am

Re: How to use TCC (Timer Counter/Control)

Post by noldwil »

Have a look in your ArduinoData-Directory:
e.g.:
Homedirectory->Documents->ArduinoData->adafruit->hardware->samd->Versionsnumber->bootloaders->mzero->Bootloader_D21->src->ASF->sam0->utils->cmsis->samd21->include
samd21xxx.h

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”