Try enabling the gclck source before enabling tc. Also probably a good idea to disable (or reset, which will disable also) tc before doing any tc setup, even if you most likely only setup once (if done the second time in the future, you will wonder why it does not work so may as well take care of that now).
Simple example for a samd10 on an xplained mini-
#include <sam.h>
#include <stdbool.h>
//samd10 xplained mini
//'inline' to eliminate unused function warnings
typedef struct { port_group_registers_t* pt; uint8_t pn; bool onval; } pin_t;
static const pin_t LED = { &PORT_IOBUS_REGS->GROUP[0],9,1 }; //led, PA09, high=on
inline static void
pin_toggle (pin_t p)
{
p.pt->PORT_DIRSET = 1<<p.pn;
p.pt->PORT_OUTTGL = 1<<p.pn;
}
//tc clock sources
typedef enum { TC_GCLK0,TC_GCLK1,TC_GCLK2,TC_GCLK3,TC_GCLK4,TC_GCLK5 }
tc_gclk_t;
inline static void
tc_gclksel (tc_registers_t* tcN, tc_gclk_t e)
{
uint8_t id; //get clk id from tcN
if( tcN == TC1_REGS ) id = 0x12; //same tc1,tc2 same on samd
else if( tcN == TC2_REGS ) id = 0x12; //etc.
GCLK_REGS->GCLK_CLKCTRL = (1<<14)|(e<<8)|id; //clken,gclkN,tcN
}
inline static void
tc_busclk (tc_registers_t* tcN, bool tf)
{ //tcN already limited by manufacturer's defines, so should not see an invalid tcN
uint8_t tcbm; //tcN clock bitmask
if( tcN == TC1_REGS ) tcbm = (1<<6); //TC1
else if( tcN == TC2_REGS ) tcbm = (1<<7); //TC2
if(tf) PM_REGS->PM_APBCMASK |= tcbm; else PM_REGS->PM_APBCMASK &= ~tcbm;
}
//tc functions for any mode (8/16/32)
inline static void //also enables bus clock
tc_reset (tc_registers_t* tcN) { tc_busclk(tcN,true); tcN->COUNT8.TC_CTRLA = 1; }
inline static void //set ctrla to v, we set the enable bit
tc_enable (tc_registers_t* tcN, uint16_t v) { tcN->COUNT8.TC_CTRLA = v|2; }
inline static bool //also clears if set
tc_isOvf (tc_registers_t* tcN) { uint8_t v = tcN->COUNT8.TC_INTFLAG & 1; tcN->COUNT8.TC_INTFLAG = v; return v; }
typedef enum { TC_COUNT16, TC_COUNT8, TC_COUNT32 }
tc_mode_t;
typedef enum { TC_DIV1,TC_DIV2,TC_DIV4,TC_DIV8,TC_DIV16,TC_DIV64,TC_DIV256,TC_DIV1024 }
tc_prescale_t;
//tc count8 mode functions
inline static void
tc_per8 (tc_registers_t* tcN, uint8_t v) { tcN->COUNT8.TC_PER = 0xFF; } //count8 mode
//init tc, specific modes
static void
tc_NFRQ8 (tc_registers_t* tcN, tc_gclk_t gclk, tc_prescale_t pre, uint8_t period)
{
//reset/disable before changing
tc_reset( tcN ); //will also enable bus clock
tc_gclksel( tcN, gclk );
tc_per8( tcN, period );
tc_enable( tcN, (TC_COUNT8<<2)|(pre<<8) );
}
#define TC1 TC1_REGS //a nicer name to use
int
main ()
{
tc_NFRQ8( TC1, TC_GCLK0, TC_DIV8, 0xFF ); //TC1,GCLK0,div8,per=0xFF
for( int n = 0; ;n++ ){
while( ! tc_isOvf(TC1) ){}
if( n >= 1000000/256/8/2 ){ n = 0; pin_toggle(LED); } //1Hz
}
}
This example will fail (no led blink) if the gclk source is set after the tc is enabled. I'm not sure what version these defines are, so may look different, and of course a samd is different than a samc so things are somewhat different, but still similar enough.
Also note that these functions are designed to work for any tc instance, so you do not end up with a truckload of defines for each instance. You can also create specific init functions to lessen the need to pass info in (tc_init_NFRQ8 is nfrq/count8). These functions are static, so will be optimized, and inline so if any are unused you do not get a warning about unused functions. So you move the creation of defines to specify things you want over to the init arguments instead. Do whatever you want, though.