Multiple timer interrupts on Due?

I'm trying to add oversampling capability to some old code that used a single timer interrupt using a second timer with an interrupt. I've been using this thread as reference: Arduino Due - Arduino Forum

So far from testing this it doesn't seem that TC4_Handler() ever gets called, as realTotal and imagTotal never get changed from zero. TC3_Handler() gets called as expected however. I feel like I must have made a silly mistake.

Relevant parts of code:

#define OVERSAMPLE 4

/* Pins for reading impedance */
#define REAL_1 A0
#define IMAG_1 A1

/* Impedance reading global variables */
volatile unsigned int real1 = 0;
volatile unsigned int imag1 = 0;
volatile unsigned int realTotal = 0;
volatile unsigned int imagTotal = 0;

/* Misc Global Variables */
volatile byte dataReady = 0;
volatile byte finished = 0;

void readImpedanceAvg()
{
	realTotal += analogRead(REAL_1);
	imagTotal += analogRead(IMAG_1);
}

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) 
{
	pmc_set_writeprotect(false);
	pmc_enable_periph_clk((uint32_t)irq);

	TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);

	uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
	TC_SetRA(tc, channel, rc/2); //50% high, 50% low
	TC_SetRC(tc, channel, rc);
	TC_Start(tc, channel);

	tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
	tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;

	NVIC_EnableIRQ(irq);
}

void setup()
{
	// ...

	currentDecade = 0;
	currentFreq = START_FREQ;
	updateFreq(START_FREQ);

	if(SWEEP)
	{
		// This timer will take multiple readings to average out
		startTimer(TC1, 1, TC4_IRQn, 1000/INTERVAL/OVERSAMPLE);

		delay(1);

		// Since the timer ISR begins with a read, I need to start the first
		// frequency before starting the timer, and the first call to this ISR
		// will update to the SECOND frequency, hence currentIncrement = 1
		currentIncrement = 1;
		startTimer(TC1, 0, TC3_IRQn, 1000/INTERVAL);
	}
	else
	{
		// Start TC5 to handle constant frequency impedance measurement at
		// 100 samples per second
		startTimer(TC1, 2, TC5_IRQn, 1000/10); // 10 ms period for timer
	}
}

void loop()
{
	if(dataReady)
	{
		sendReading();
		dataReady = 0;
	}
	if(finished)
	{
		// stop timer
		NVIC_DisableIRQ(TC3_IRQn);
		NVIC_DisableIRQ(TC4_IRQn);
		setup();
	}

        // ...
}

byte oversample_lookup(byte oversample_amount)
{
	switch(oversample_amount)
	{
		case 1: return 0;
		case 2: return 1;
		case 4: return 2;
		case 8: return 3;
		case 16: return 4;
		case 32: return 5;
		case 64: return 6;
		default: return 0;
	}
}

/* -----------------------------------------------------------------------------
	TC3_HANDLER
	---
	This is the ISR for when the 3rd timer runs out.
	This is specifically the ISR for the timer that is enabled if we are doing
	a frequency sweep.
----------------------------------------------------------------------------- */
void TC3_Handler()
{
	TC_GetStatus(TC1, 0); // accept interrupt

	// Since the frequency is about to be updated, I need to store
	// the frequency associated with the read immediately prior to this for
	// whenver the main loop gets to it
	sendFreq = currentFreq;

	// Average out the previous readings
	real1 = realTotal >> oversample_lookup(OVERSAMPLE);
	imag1 = imagTotal >> oversample_lookup(OVERSAMPLE);

	realTotal = imagTotal = 0;

	dataReady = 1; // lets the main loop know a reading is ready to send

	currentFreq = START_FREQ*pow(10, (double)currentIncrement/NUM_INCR + currentDecade);

	if(currentFreq <= END_FREQ)
	{
		updateFreq(currentFreq);
		++currentIncrement;
	}
	else
	{
		finished = 1;
	}

	// End of a decade
	if(currentIncrement >= NUM_INCR)	
	{
		++currentDecade;
		currentIncrement = 0;
	}			
}

/* -----------------------------------------------------------------------------
	TC4_HANDLER
	---
	The ISR to take readings at a single frequency to be averaged out in TC3 ISR
	before sending to LabVIEW in the main loop
----------------------------------------------------------------------------- */
void TC4_Handler()
{
	TC_GetStatus(TC1, 1); // accept interrupt
	readImpedanceAvg();
}

/* -----------------------------------------------------------------------------
	TC5_HANDLER
	---
	This is the ISR for when the 4th timer runs out. It should read the analog
	values for the impedances, then set the serial write flag that is checked
	in the main loop, as the Serial library does not work in an interrupt.
	This is specifically the ISR for the timer that is enabled if we are doing
	a constant frequency, so it simply reads the impedance and doesn't change
	any frequencies.
----------------------------------------------------------------------------- */
void TC5_Handler()
{
	TC_GetStatus(TC1, 2); // accept interrupt

	readImpedance();
	dataReady = 1;
}

Thanks in advance for any help!

Have you proved that the ISR is never being entered by just writing a hardcoded value into those variables (or setting a LED or something). If that works write the results of the analogRead()s into them, don't +=, maybe analogRead() is returning 0 for some reason.


Rob

Indeed, I tried both of those methods to determine the ISR isn't being entered.

Hmmm, is T4's interrupt(s) enabled, maybe the Arduino init code doesn't bother with T4 or has a bug.


Rob