TC/TCC Timer for SAMD21
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

TC/TCC Timer for SAMD21

by MJHanagan on Sun May 22, 2022 10:01 am

I have a basic understanding of setting up TC/TCC timers on the 32u4 processor but I am having trouble understanding the complexities of doing the same thing on the M0/SAMD21 processor (Feather Bluefruit board). It seems the timers on the SAMD21 are more plentiful and have a lot more capabilities so there are more registers to be set in order to get a timer to function.

My basic timer need is this: wait "x" microseconds then turn on pin A5 for about 50 µsec then turn it off. The timer gets restarted periodically in another ISR which gets triggered on the falling edge of pins A1 and A2. The value of "x" ranges from 2000 to 6000 µsec and changes occasionally depending on other stuff going on. I don't need much precision, ±50 µsec is plenty. With the main clock speed of 48 MHz even a 1024 prescaler would overflow an 8-bit counter in 5300 µsec, so it looks like I need to use a 16-bit counter.

I need some help in selecting which of the many TC/TCC to use for this timer, and which of the many registers need to be configured to trigger an ISR on a matching value condition. And is there a timer feature I can use to turn off that same pin about 50 µsec later? This isn't necessary because I can also use another A1/A2 pin event ISR to turn it off.

Any help would be appreciated.

This is the basic code I wrote for the 32u4 processor:
Code: Select all | TOGGLE FULL SIZE
ISR( TIMER3_COMPA_vect ) { // interrupt service routine (ISR) is called when timer3 TCNT3 = OCR3A 
  // if this is a powered cycle then turn on the opto output driver to turn on the triac
  if (onCycle) {
    digitalWrite( triacPin, HIGH );
    triacOn = true;     
  TIMSK3 &= ~(1 << OCIE3A); // clear the compare interrupt bit to disable timer3 compare interrupt.
void initTimer3() { // initialize timer3 (16-bit counter) with a prescaler of 8 (1 count equals 1 µsec).
  // NOTE: this routine does not enable the timer - this is done in "setISRtrigger()"
  cli();  // disable all interrupts
  TCCR3A = 0; // Clear timer3 register A
  TCCR3B = 0; // Clear timer3 register B 
  TCCR3B |= (1 << CS31);    // 8 prescaler (8 clock ticks = 1 count).  So 8 ticks of an 8 MHz clock is 1 µsec in time.
  TCNT3  = 0;  // Initialize counter register to 0
  sei(); // enable interupts
void setISRtrigger( int delayCount ) { // Enables timer3 to trigger the ISR when TCNT3 counts up to match the value in OCR3A
  TCNT3 = 0;   // Reset counter to 0
  OCR3A = delayCount;  // Count up to value
  TIMSK3 |= (1 << OCIE3A);  // Enable timer3 compare interrupt bit (interrupt is triggered when TCNT3=OCR3A)

Posts: 34
Joined: Tue Dec 09, 2014 5:25 pm

Re: TC/TCC Timer for SAMD21

by adafruit_support_mike on Tue May 24, 2022 9:39 pm

The TC/TCC peripherals really aren't the best tools for what you're trying to do. They're made to produce repeating signals, not single variable pulses.

The '32u4's clock runs at 16MHz, putting each tick of the clock at about 63ns. That's about 0.1% of the 50us gap you want, so it will probably be easier to bit-bang the pulses using the microseconds() counter in a tight loop.

Posts: 64793
Joined: Thu Feb 11, 2010 2:51 pm

Re: TC/TCC Timer for SAMD21

by MJHanagan on Sun May 29, 2022 11:45 am

This isn't just a one-off timer event. The timer will trigger 120X per second, the only thing that changes periodically is the actual timer interval. There is a section in the loop() code that needs to process a bunch of serial I/O code that interferes with the ±50 µsec timing if I am bit banging. I need to keep the triac triggering in sync with the 60 Hz power cycle. Using a timer ISR would enable the triac to keep doing its thing at the right instance in time regardless of that other stuff is going on in the loop() code.

The timer ISR method works well with the 32u4 chip, but with the SAMD21 chip on the Feather M0 board there seems to be a lot more functionality to the hardware timers. I am having a hard time deciphering which registers I need to use to setup a 16-bit counter that will trigger and ISR and change the value of the counter as needed. I have an ISR that gets called at the beginning of each AC half cycle which is where I will update the 16-bit counter with its new value.

The specific help I am looking for is which special registers do I need to set to get this TC/TCC functionality in the SAMD21? I think most of the programming setup is done with the CTRLA register but I can't seem to find a simple explanation of all the specific bits that need to be set to get the timer function I am looking for. Is there a beginner's "how to guide" to setting the various registers and bits in Table 29-3 of the SAMD21 datasheet?

I also need to know which timer should I use so I don't accidentally interfere with any millis(), micros(), SERCOM or I2C functionality.

Posts: 34
Joined: Tue Dec 09, 2014 5:25 pm

Please be positive and constructive with your questions and comments.