Measure Frequency using TC

Hi everyone,

I couldn't find a library for measuring frequency's on a Arduino Due, so i tried to do it on my own. My plan was to use the TC in capture mode and TIOA as input for a signal. After saving the counter value of two following rising edges of the signal, it's easy to calculate the frequency.
Unfortunately it's not working. I don't know why but it seems that I get an infinite interrupt in the TC_Handler().
Whenn running the Sketch a lot "Error" lines appear in the Serial Monitor. That's the third case in the if structure in TC_Handler. That's what I don't understand because: as soon as the float measured turns 2 the while loop in measure() should end, the interrupts disabled and the frequency calculated.
I connected pin 12 with pin 2 to measure the pwm, which is configurated in setup().

Could someone please help me?

The sketch:

#include "MeasureFrequency.h"

void setup() {
  Serial.begin(115200);
  pinMode(12, OUTPUT);
  analogWrite(12,125);
  pinMode(2, INPUT);
}

void loop() {
  Serial.println();
  Serial.print("measured frequency: ");
  Serial.print(measure());
  Serial.println();
  delay(1000);
}

And MeasureFrequency.cpp :

#include <MeasureFrequency.h>
#include <Arduino.h>

//global variables
static int measured;
static int captured_ra_1;
static int captured_ra_2;
static float frequence;


#define Timer_CLOCK_1 (0 << 0)
#define Clock_Invert (0 << 2)
#define BURST (0 << 4)
#define LDBSTOP (1 << 6) //Timer stop b loaded
#define LDBDIS (0 << 7)  //diable clock b loaded
#define ETRGDG (1 << 8)	//falling edge
#define ABETRG (1 << 10) //TIOA as trigger
#define CPCTRG (0 << 11) //kein compare
#define WAVE (0 << 15) // capture mode
#define LDRA (1 << 16) //LDRA Rising
#define LDRB (0 << 18)	// LDRB none

#define interruptA (1 << 5)
#define interruptB (1 << 6)

#define TC_Handler  TC0_Handler
#define TC_IRQn     TC0_IRQn



// Configure TC0 in capture operating mode.

void tc_capture_initialize(void){
	// clock enable TC0 channel 0
	pmc_enable_periph_clk (TC_INTERFACE_ID + 0*3+0) ;  

	
	REG_TC0_WPMR = 0x54494D00; //WPKEY, disable
	REG_TC0_CCR0 = ((1 << 2) | (1 <<0)) ; //reset, enable clock
	
	//configure channel_mode_reg in capture mode
	REG_TC0_CMR0 = Timer_CLOCK_1 | ETRGDG | ABETRG | CPCTRG | WAVE | LDRA;

	REG_TC0_IDR0 = 0b11111111; //disable all interrupts

	REG_TC0_IER0 = interruptA; //enable interrupt: load register a
		
 }


//brief Interrupt handler 
 
void TC_Handler(void){
	
	if( ( REG_TC0_SR0 & ( 1 << 5 ) ) == ( 1 << 5 ) ){	
		if( measured == 0 ){
			captured_ra_1 = REG_TC0_RA0;	//save counter value of first edge
			measured = 1;
		}else if( measured == 1 ){
			captured_ra_2 = REG_TC0_RA0;	//save counter value of second edge
			measured = 2;
		}else{
			// Error, measured wasen't set to 0
			// no read out of result
			Serial.println("Error");
		}
	}	    
}

//method to measure frequency

float measure(){
	
	
	// Configure PIO Pins for TC0 
	PIOB -> PIO_ABSR = (1 << 25);

	//Disable IO to enable peripheral mode) 
	PIOB -> PIO_PDR = (1 << 25);

	//reset variables
	measured = 0;
	captured_ra_1 = 0;
	captured_ra_2 = 0;
	frequence = 0;

	// initialize TC0 Channel0
	tc_capture_initialize();

	//Configure TC interrupts for TC TC_CHANNEL_CAPTURE only
	NVIC_DisableIRQ(TC_IRQn);
	NVIC_ClearPendingIRQ(TC_IRQn);
	NVIC_SetPriority(TC_IRQn, 0);
	NVIC_EnableIRQ(TC_IRQn);
    
	while( measured != 2 ){
		//do nothing
		//Serial.println(measured);
	};	
	//disable interrupts
	REG_TC0_IDR0 = 0b11111111; //disable all interrupts
	NVIC_DisableIRQ(TC_IRQn);
	
	
	//measured = 2, calculate frequency, CLK = MST_CLK / 2
	frequence = 42000000 /	(captured_ra_2 - captured_ra_1);
	
	return frequence;
}

I found the problem: the variable "measure" has to be declared as "volatile". Otherwise a change of this variable (interrupt) won't be recognized in the function.

A good explanation could be found here: http://arduino.cc/en/Reference/Volatile

Here is the code to measure a frequency (Arduino PIN 2) maybe this helps someone...

Greets

#include <MeasureFrequency.h>
#include <Arduino.h>

/** Capture status*/
volatile bool measured;
volatile float frequence;

#define TC TC0			//0 to 2
#define TC_N 0
#define TC_Channel 0	//0 to 2
#define TC_Handler  TC0_Handler
#define TC_IRQn     TC0_IRQn


TcChannel * tc = &(TC->TC_CHANNEL)[TC_Channel] ;    // pointer to TC0 registers for its channel 0


#define Timer_CLOCK_1 (0 << 0) //MSTCLK / 2
#define ETRGDG  (1 << 9)	//falling edge, counter restarts at this edge
#define ABETRG (1 << 10)  //TIOA as trigger
#define WAVE (0 << 15) // capture mode
#define LDRA (1 << 16) //load LDRA rising(1), falling(10)
#define LDRB (1 << 18)	//load LDRB rising(1), falling(10)

#define WPKEY 0x54494D00
#define TC_CONF_CLK 5	//clk enable + software reset

#define interruptA (1 << 5)	
#define interruptB (1 << 6)

#define Periph_A 0
#define Periph_B 1

// Configure TC in capture operating mode.

void tc_capture_initialize(void){

	// clock enable 
	pmc_enable_periph_clk (TC_INTERFACE_ID + TC_N*3+TC_Channel) ;  

	REG_TC0_WPMR = 0x54494D00; //WPKEY, disable
	tc -> TC_CCR = TC_CONF_CLK;
			
	tc -> TC_CMR = 0; //clear all
	tc -> TC_IDR = 0b11111111; //clear all interrupts
	
	//configure channel_mode_reg in capture mode
	tc -> TC_CMR = Timer_CLOCK_1 | ABETRG | WAVE | LDRA | LDRB;
	// read int status reg to clear pending
	tc -> TC_SR ;                   
 }


// Interrupt handler 
 
void TC_Handler(void){
	int status = tc -> TC_SR;
	
	if( ( ( status & interruptB ) == interruptB ) ){	
		frequence = 42000000.0 / (float)(tc -> TC_RB - tc  -> TC_RA);
		measured = true;
	}	    
}

//method to measure frequency

float measureFrequency(){
	
	
	// Configure PIO Pins for TC0 
	PIOB -> PIO_ABSR = (1 << 25);

	//Disable IO to enable peripheral mode) 
	PIOB -> PIO_PDR = (1 << 25);
/*
	//TC2 CH 2
	PIOD -> PIO_ABSR = (1 << 7);
	PIOD -> PIO_PDR = (Periph_B << 7);
	*/
	
	//reset variables
	measured = false;
	frequence = 0;

	// initialize TC0 Channel0
	tc_capture_initialize();

	//Configure TC interrupts for TC TC_CHANNEL_CAPTURE only
	NVIC_DisableIRQ(TC_IRQn);
	NVIC_ClearPendingIRQ(TC_IRQn);
	NVIC_SetPriority(TC_IRQn, 0);
	NVIC_EnableIRQ(TC_IRQn);
	
	//enable interrupt
	tc -> TC_IER = interruptB;	
	
	//wait until measured: one period = time between two rising edges
	while( !measured );
	
	//disable interrupts
	tc -> TC_IDR = 0b11111111; //disable all interrupts
	NVIC_DisableIRQ(TC_IRQn);
	
	return frequence;
}

Thanks for posting.