Cannot get Timer/Counter 1 to work

Discussion around product based on ARM Cortex M4 core.

Moderators: nferre, ncollot

jma
Posts: 7
Joined: Wed Oct 22, 2014 4:04 am

Cannot get Timer/Counter 1 to work

Mon Mar 30, 2015 10:52 pm

I am able to successfully use the following code to generate a 1 ms clock using TC0:

Code: Select all

//This will initialize needed timers
static void TimerInit(void)
{
	uint32_t ul_div;
	uint32_t ul_tcclks;
	uint32_t ul_sysclk = sysclk_get_cpu_hz();
	uint32_t counts;
	uint32_t freq;
	
	//Timer 0, 1ms intervals
	freq = 1000;
	
	//Configure PMC
	pmc_enable_periph_clk(ID_TC0);

	//Configure TC for a 1000Hz frequency and trigger on RC compare
	tc_find_mck_divisor(
		(uint32_t)freq,			//The desired frequency as a uint32
		ul_sysclk,				//Master clock freq in Hz
		&ul_div,				//Pointer to register where divisor will be stored
		&ul_tcclks,				//Pointer to reg where clock selection number is stored
		ul_sysclk);				//Board clock freq in Hz
	tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
	
	//Find the best estimate of counts, then write it to TC register C
	counts = (ul_sysclk / ul_div) / freq;
	tc_write_rc(TC0, 0, counts);

	tc_enable_interrupt(TC0, 0, TC_IER_CPCS); //Enable interrupt
	tc_start(TC0, 0); // Start the TC
}

Code: Select all

//This will initialize interrupts, set priorities, assign handler functions, etc
static void InterruptInit(void)
{
	//Configure TC0 interrupts
	NVIC_DisableIRQ(TC0_IRQn);
	NVIC_ClearPendingIRQ(TC0_IRQn);
	NVIC_SetPriority(TC0_IRQn, 1); //This is top priority interrupt, to control timing of system operations and display updates
	NVIC_EnableIRQ(TC0_IRQn);
}

Code: Select all

//Interrupt service routine for TC0, 1ms interval
void TC0_Handler(void)
{
	//Get timer status, this appears to clear the interrupt and allows interrupts to continue every 1ms
	tc_get_status(TC0, 0);
	
	//Update timers
	Timer0++; //This is general purpose timer 0
	Timer1++; //This is general purpose timer 1
	TimerA++; //This timer is used for animation
	USBReportTimer++; //This will space out USB reports that are sent to the host
	SystemTimeoutTimer++; //Main system timeout timer for turning off the screen
	LEDBlinkTimer++; //This is used to blink the LED in sleep mode
}
When I use the same code but replace TC0 with TC1, in TimerInit(), replace TC0_IRQn with TC1_IRQn in InterruptInit() and change the name of the handler to "TC1_Handler" and get the status for TC1, the interrupt handler never fires!!!!

Any ideas?
bptech
Posts: 25
Joined: Fri Jul 18, 2014 3:08 pm

Re: Cannot get Timer/Counter 1 to work

Wed Apr 01, 2015 2:43 pm

Did you also replace ID_TC0 with ID_TC1 in the call to set up the clock (pmc_enable_periph_clk(ID_TC0);)?
jma
Posts: 7
Joined: Wed Oct 22, 2014 4:04 am

Re: Cannot get Timer/Counter 1 to work

Thu Apr 02, 2015 3:05 am

Yes, I did.
Thanks for your reply.
cwunder
Posts: 34
Joined: Fri Jul 01, 2011 9:39 pm

Re: Cannot get Timer/Counter 1 to work

Thu Apr 02, 2015 9:55 pm

I am not a fan of the ASF. Perhaps it is easier to see code that is outside of the ASF to understand the TimerCouter coding realization. If you refer to the block diagram (Figure 2-1) in the datasheet you can see that there are two Timer Counter Peripherals (TC0/TC1) which include three identical 16-bit Timer Counter channels. TC0 contains the first three channels (TC0, TC1, TC2) and TC1 module contains another three channels (TC3, TC4, and TC5). When you are coding this you want the channel number to match the interrupts. So if you want TC1 this is would be TC0->TC_CHANNEL[1].x (which is not obvious). Here is a very simple example for Studio 6 that is a bare metal GCC project. The default clock after reset is 4MHz. So the TC's are clocked by MCLK/2 (2MHz).

TC0 will have an interrupt every 1msec, TC1=2msec, and TC3=5msec.
I hope this example helps
-Chris

Code: Select all

#include "sam.h"

volatile uint32_t status_TC0;
volatile uint32_t status_TC1;
volatile uint32_t status_TC3;

volatile uint32_t cnt_TC0;
volatile uint32_t cnt_TC1;
volatile uint32_t cnt_TC3;

volatile uint32_t cnt;

void TimerCounter0Init(void);
void TimerCounter1Init(void);

void TimerCounter0Init(void)
{
  //Configure PMC, TC0,  and TC1
  PMC->PMC_PCER0 = (1 << ID_TC0) | (1 << ID_TC1);
  
  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_CPCTRG;
  TC0->TC_CHANNEL[0].TC_RC = 2000;
  TC0->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
  
  TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_CPCTRG;
  TC0->TC_CHANNEL[1].TC_RC = 4000;
  TC0->TC_CHANNEL[1].TC_IER = TC_IER_CPCS;

  //Configure TC0 interrupts
  NVIC_DisableIRQ(TC0_IRQn);
  NVIC_ClearPendingIRQ(TC0_IRQn);
  NVIC_SetPriority(TC0_IRQn, 1);
  NVIC_EnableIRQ(TC0_IRQn);
  
  //Configure TC1 interrupts
  NVIC_DisableIRQ(TC1_IRQn);
  NVIC_ClearPendingIRQ(TC1_IRQn);
  NVIC_SetPriority(TC1_IRQn, 1);
  NVIC_EnableIRQ(TC1_IRQn);  

  // Start the TC0
  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;;
  // Start the TC1
  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;;
}

void TimerCounter1Init(void)
{
  //Configure PMC for TC3, TC4, and TC5
  PMC->PMC_PCER0 = 1 << ID_TC3;
  //Trigger on RC compare
  TC1->TC_CHANNEL[0].TC_CMR = TC_CMR_CPCTRG;
  TC1->TC_CHANNEL[0].TC_RC = 10000;
  //Enable interrupt
  TC1->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
  //Configure TC1[0] which TC3
  NVIC_DisableIRQ(TC3_IRQn);
  NVIC_ClearPendingIRQ(TC3_IRQn);
  NVIC_SetPriority(TC3_IRQn, 1);
  NVIC_EnableIRQ(TC3_IRQn);

  // Start the TC3
  TC1->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
}

/* handle TimerCounter 0 channel 0 (TC0) */
void TC0_Handler(void)
{
  status_TC0 = TC0->TC_CHANNEL[0].TC_SR;
  cnt_TC0++;
}

/* handle TimerCounter 0 channel 1 (TC1) */
void TC1_Handler(void)
{
  status_TC1 = TC0->TC_CHANNEL[1].TC_SR;
  cnt_TC1++;
}

/* handle TimerCounter 1 channel 0 (TC3) */
void TC3_Handler(void)
{
  status_TC3 = TC1->TC_CHANNEL[0].TC_SR;
  cnt_TC3++;
}

/**
 * \brief Application entry point.
 *
 * \return Unused (ANSI-C compatibility).
 */
int main(void)
{
  SystemInit();
  TimerCounter0Init();
  TimerCounter1Init();

  while (1)
  {
    cnt++;
  }
}
Last edited by cwunder on Thu Apr 02, 2015 10:23 pm, edited 1 time in total.
jma
Posts: 7
Joined: Wed Oct 22, 2014 4:04 am

Re: Cannot get Timer/Counter 1 to work

Wed Apr 08, 2015 1:42 am

Thanks Chris! Your example helped me to understand that I was using TC1, ch1 but was incorrectly coupling this with TC1_IRQn and TC1_Handler when I should have been using TC4_IRQn and TC4_Handler.  It all works now!

Return to “SAM4 Cortex-M4 MCU”

Who is online

Users browsing this forum: No registered users and 3 guests