SAM3X8E Timer Counters

Discussion around product based on ARM Cortex M3 core.

Moderators: nferre, ncollot

TungstenCarbide
Posts: 2
Joined: Mon Apr 20, 2015 4:11 pm

SAM3X8E Timer Counters

Mon Apr 20, 2015 10:52 pm

I'm using an ATMEL ATSAM3X8E microcontroller on the Arduino Due model R3-E board.

I'm trying to get timer counter TC2 to CPCS interrupt on a XC2 (TCLK8) edge.
  • TC2's CPCS interrupts when using an internal clock source
  • TC2's ETRGS interrupts when using an external clock source
  • But CPCS just doesn't want to interrupt when TC2 is configured to use an external clock source.
The external clock source is a function generator outputting a square wave at 3 Hz. Has anyone gotten this feature to work on any SAM3 microcontroller? Here's the code and log for those interested (note that I do not have permission to attach files--see discussions/faq.php.html#f27)

Code: Select all

/***************************************************************
 * This program demonstrates the operation of TC2
 *
 * Board is the Arduino Due R3-E with the Atmel ATSAM3X8E microcontroller
 *
 * External clock is attached to PD9 (Arduino pin 30)
 *
 * External clock source is a function generator with the following settings:
 *     Waveform:       Square
 *     Frequency:      3.0 Hz (a 1/3 second period)
 *     Amplitude:      1.500 Vpp
 *     Offset:         750 mV (mV = millivolts, in other words 0.750 V)
 *     Channel output: On
 ***************************************************************/

#define TC2_CHANNEL_FOR_TCLK8 2  /* presumed to correspond to XC2 */

enum Phase
	{
		TC2_INTERNAL,
		PIOD_EXTERNAL,
		TC2_EXTERNAL,
		DONE
	};

Phase phase;
int pioIRQsServiced;
int tc2IRQsServiced[3];
unsigned int status;


/****************************************************************/

void PIOD_Handler(void)
{
	/* clear interrupt */
	status = REG_PIOD_ISR;
	pioIRQsServiced++;
}


/****************************************************************/

void TC8_Handler()
{
	/* clear interrupt */
	status = TC_GetStatus(TC2, TC2_CHANNEL_FOR_TCLK8);
	if (status & TC_SR_CPCS)
	{
		if (phase == TC2_INTERNAL)
		{
			tc2IRQsServiced[0]++;
		}
		else
		{
			tc2IRQsServiced[1]++;
		}
	}
	if (status & TC_SR_ETRGS)
	{
		tc2IRQsServiced[2]++;
	}
}


/****************************************************************/

void SetupPIOD(void)
{
	int result;

	/* power on PIO ("Parallel Input/Output Controller") controller D */
	pmc_enable_periph_clk(ID_PIOD);
	/* enable interrupts for PIOD */
	NVIC_EnableIRQ(PIOD_IRQn);
	/* configure PD9 as general-purpose IO pin as opposed to the TCLK8 peripheral */
	result = PIO_Configure(PIOD, PIO_INPUT, PIO_PD9, PIO_IT_RISE_EDGE);
	printf("%d <- PIO_Configure\n", result);
	/* ensure we're interrupting on the rising edge of the external clock */
	REG_PIOD_AIMER = PIO_PD9;
	REG_PIOD_ESR = PIO_PD9;
	REG_PIOD_REHLSR = PIO_PD9;
	/* enable interrupts */
	REG_PIOD_IER = PIO_PD9;
}


/****************************************************************/

void TakeDownPIOD(void)
{
	TC_Stop(TC2, TC2_CHANNEL_FOR_TCLK8);
	TC_SetRC(TC2, TC2_CHANNEL_FOR_TCLK8, 0);
	REG_PIOD_IDR = PIO_PD9;
	NVIC_DisableIRQ(TC8_IRQn);
	pmc_disable_periph_clk(ID_PIOD);
}


/****************************************************************/

void SetupTC2(bool useInternalClock)
{
	int result;

	/* "The user must configure the Power Management Controller before any access to the input line information." per 34.4.2 */
	pmc_enable_periph_clk(ID_TC8);
	/* "Using the PIO Controller requires the NVIC to be programmed first." per 34.4.3 */
	NVIC_EnableIRQ(TC8_IRQn);
	result = PIO_Configure(PIOD, PIO_PERIPH_B, PIO_ABSR_P9, PIO_DEFAULT);
	printf("%d <- PIO_Configure\n", result);
	if (useInternalClock)
	{
		TC_Configure(TC2,
					 TC2_CHANNEL_FOR_TCLK8,
					 TC_CMR_TCCLKS_TIMER_CLOCK4 | TC_CMR_WAVSEL_UP_RC | TC_CMR_WAVE);
	}
	else
	{
		TC_Configure(TC2,
					 TC2_CHANNEL_FOR_TCLK8,
					 (TC_CMR_TCCLKS_XC2 |
					  TC_CMR_BURST_XC2 |
					  TC_CMR_EEVTEDG_RISING |
					  TC_CMR_EEVT_XC2 |
					  TC_CMR_ENETRG |
					  TC_CMR_WAVSEL_UP_RC |
					  TC_CMR_WAVE));
	}
	/* load counter register */
	TC_SetRC(TC2, TC2_CHANNEL_FOR_TCLK8, 13);
	/* start the timer */
	TC_Start(TC2, TC2_CHANNEL_FOR_TCLK8);
	/* enable the timer-specific interrupts */
	REG_TC2_IER2 = TC_IER_CPCS | TC_IER_ETRGS;
}


/****************************************************************/

void TakeDownTC2(void)
{
	TC_Stop(TC2, TC2_CHANNEL_FOR_TCLK8);
	TC_SetRC(TC2, TC2_CHANNEL_FOR_TCLK8, 0);
	REG_TC2_IDR2 = TC_IER_CPCS | TC_IER_ETRGS;
	NVIC_DisableIRQ(TC8_IRQn);
	pmc_disable_periph_clk(ID_TC8);
}


/****************************************************************/

void setup(void)
{
	Serial.begin(9600);
	printf("start with TC2 internal\n");
	SetupTC2(true);
}


/****************************************************************/

void loop(void)
{
	switch (phase)
	{
		case TC2_INTERNAL:
			if (tc2IRQsServiced[0] > 250000)
			{
				phase = PIOD_EXTERNAL;
				TakeDownTC2();
				printf("PASSED\nswitch to PIOD\n");
				SetupPIOD();
			}
			break;
		case PIOD_EXTERNAL:
			if (pioIRQsServiced > 20)
			{
				phase = TC2_EXTERNAL;
				TakeDownTC2();
				printf("PASSED\nswitch to TC2 external\n");
				SetupTC2(false);
			}
			break;
		case TC2_EXTERNAL:
			if (tc2IRQsServiced[1] > 20)
			{
				printf("PASSED!!!\n");
				for ( ; ; );
			}
			break;
		default:
			break;
	}
	delay(1000);
	printf("PIO IRQs: %d, CPCS internal IRQs: %d, CPCS external IRQs: %d, ETRGS external IRQs: %d, status: %08x, CV2: %d\n", pioIRQsServiced, tc2IRQsServiced[0], tc2IRQsServiced[1], tc2IRQsServiced[2], status, REG_TC2_CV2);
	if (Serial.available() > 0)
	{
		char choice = Serial.read();
		if (choice == 'z')
		{
			REG_TC2_BCR = TC_BCR_SYNC;
		}
	}
}

#if 0
/* translation to non-Arduino should be straightforward */
int main(void)
{
	setup();
	for ( ; ; )
	{
		loop();
	}
}
#endif

Code: Select all

start with TC2 internal
1 <- PIO_Configure
PIO IRQs: 0, CPCS internal IRQs: 50437, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00050010, CV2: 10
PIO IRQs: 0, CPCS internal IRQs: 106723, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00050010, CV2: 10
PIO IRQs: 0, CPCS internal IRQs: 163060, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00050010, CV2: 4
PIO IRQs: 0, CPCS internal IRQs: 219346, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00050010, CV2: 5
PIO IRQs: 0, CPCS internal IRQs: 275632, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00050010, CV2: 6
PASSED
switch to PIOD
1 <- PIO_Configure
PIO IRQs: 4, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00000200, CV2: 7
PIO IRQs: 7, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00000200, CV2: 7
PIO IRQs: 11, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00000200, CV2: 7
PIO IRQs: 14, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00000200, CV2: 7
PIO IRQs: 17, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00000200, CV2: 7
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 0, status: 00000200, CV2: 7
PASSED
switch to TC2 external
1 <- PIO_Configure
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 3, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 7, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 10, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 13, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 17, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 20, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 23, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 27, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 30, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 33, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 37, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 40, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 43, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 47, status: 00010080, CV2: 0
PIO IRQs: 21, CPCS internal IRQs: 281473, CPCS external IRQs: 0, ETRGS external IRQs: 50, status: 00010080, CV2: 0
TungstenCarbide
Posts: 2
Joined: Mon Apr 20, 2015 4:11 pm

Re: SAM3X8E Timer Counters

Wed Apr 22, 2015 7:42 pm

:oops: Can't Atmel change the data sheet to explicitly read that one should only use TC_CMR_BURST_XC2 when configuring TC2 to use an internal clock source? Post withdrawn!
youthreewire
Posts: 8
Joined: Wed Jun 10, 2015 5:21 pm

Re: SAM3X8E Timer Counters

Mon Jun 22, 2015 7:42 am

I am trying to measure the CLKOUT signal using the Due from a Codec.I ran you code but the print gets stuck at 2nd phase (i.e switch to PIOD). Any simpler way that I can measure clkout? The CLKOUT signal from the codec is a 11Mhz signal.

Return to “SAM3 Cortex-M3 MCU”

Who is online

Users browsing this forum: No registered users and 4 guests