Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SAMD21 Arduino Timer Example
/*
This sketch illustrates how to set a timer on an SAMD21 based board in Arduino (Feather M0, Arduino Zero should work)
*/
uint32_t sampleRate = 10; //sample rate of the sine wave in Hertz, how many times per second the TC5_Handler() function gets called per second basically
#define LED_PIN 13 //just for an example
bool state = 0; //just for an example
void setup() {
pinMode(LED_PIN,OUTPUT); //this configures the LED pin, you can remove this it's just example code
tcConfigure(sampleRate); //configure the timer to run at <sampleRate>Hertz
tcStartCounter(); //starts the timer
}
void loop() {
//tcDisable(); //This function can be used anywhere if you need to stop/pause the timer
//tcReset(); //This function should be called everytime you stop the timer
}
//this function gets called by the interrupt at <sampleRate>Hertz
void TC5_Handler (void) {
//YOUR CODE HERE
if(state == true) {
digitalWrite(LED_PIN,HIGH);
} else {
digitalWrite(LED_PIN,LOW);
}
state = !state;
// END OF YOUR CODE
TC5->COUNT16.INTFLAG.bit.MC0 = 1; //don't change this, it's part of the timer code
}
/*
* TIMER SPECIFIC FUNCTIONS FOLLOW
* you shouldn't change these unless you know what you're doing
*/
//Configures the TC to generate output events at the sample frequency.
//Configures the TC in Frequency Generation mode, with an event output once
//each time the audio sample frequency period expires.
void tcConfigure(int sampleRate)
{
// Enable GCLK for TCC2 and TC5 (timer counter input clock)
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ;
while (GCLK->STATUS.bit.SYNCBUSY);
tcReset(); //reset TC5
// Set Timer counter Mode to 16 bits
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
// Set TC5 mode as match frequency
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
//set prescaler and enable TC5
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE;
//set TC5 timer counter based off of the system clock and the user defined sample rate or waveform
TC5->COUNT16.CC[0].reg = (uint16_t) (SystemCoreClock / sampleRate - 1);
while (tcIsSyncing());
// Configure interrupt request
NVIC_DisableIRQ(TC5_IRQn);
NVIC_ClearPendingIRQ(TC5_IRQn);
NVIC_SetPriority(TC5_IRQn, 0);
NVIC_EnableIRQ(TC5_IRQn);
// Enable the TC5 interrupt request
TC5->COUNT16.INTENSET.bit.MC0 = 1;
while (tcIsSyncing()); //wait until TC5 is done syncing
}
//Function that is used to check if TC5 is done syncing
//returns true when it is done syncing
bool tcIsSyncing()
{
return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
}
//This function enables TC5 and waits for it to be ready
void tcStartCounter()
{
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //set the CTRLA register
while (tcIsSyncing()); //wait until snyc'd
}
//Reset TC5
void tcReset()
{
TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
while (tcIsSyncing());
while (TC5->COUNT16.CTRLA.bit.SWRST);
}
//disable TC5
void tcDisable()
{
TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
while (tcIsSyncing());
}
@csmith105

This comment has been minimized.

Copy link

commented Jul 22, 2017

Could you comment on what TC5->COUNT16.INTFLAG.bit.MC0 = 1; //don't change this, it's part of the timer code does?

@richdrich

This comment has been minimized.

Copy link

commented Sep 16, 2017

As posted you are setting the counter to e.g. 64M / 10 which is >65535 and hence basically random.

If you set e.g. SampleRate=1000 and TC_CTRLA_PRESCALER_DIV1024 it will (on a Zero) blink at about 1Hz, which is more usable.

@michaelmegliola

This comment has been minimized.

Copy link

commented Oct 11, 2017

thanks for the post, this is helpful.

@funwithbots

This comment has been minimized.

Copy link

commented Dec 17, 2017

Compiling for a Feather M0, I get a clean compile on your code AS IS but when I try to add it to my own code, the compiler gives me:
'TC5' was not declared in this scope
I moved everything after the loop() function to tc5timer.cpp and created tc5timer.h to predefine the needed functions. tc5timer.h was included in the main sketch. Not sure where I messed this one up.

@danieldeesousa

This comment has been minimized.

Copy link

commented May 19, 2018

@funwithbots
Make sure that your code before the TC5 deceleration has semi colons. Same thing happened to me.

@gergelytakacs

This comment has been minimized.

Copy link

commented Feb 8, 2019

Thank you for this example, helped a lot. Implemented something similar in a timing routine for feedback control, see the AutomationShield project.

@mjunior-fitec

This comment has been minimized.

Copy link

commented Jun 24, 2019

As posted you are setting the counter to e.g. 64M / 10 which is >65535 and hence basically random.

If you set e.g. SampleRate=1000 and TC_CTRLA_PRESCALER_DIV1024 it will (on a Zero) blink at about 1Hz, which is more usable.

Very well observed!
It took me quite a while to realize what the actual blinking frequency would be in the example. This idea helps a lot to understand and make the example usable.
I compiled it as an independent module on my MKRWAN1300, and its working fine, so far!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.