Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

dsPIC Frequency counter

Status
Not open for further replies.

scottlad

Newbie level 5
Joined
Jun 27, 2014
Messages
8
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
61
Hi, I have some experience with PIC programming but I'm new to using timer interrupts and Input capture. Would anyone have any idea where I'm going wrong. The values read from an input from a function generator seem to jump all over the place, any other info needed just ask and I'll provide it. Thanks in advance.

Code:
# include <p30f4011.h>
# include <math.h>
# include <stdio.h>
# include<InCap.h>
# include <xc.h>
# include <libpic30.h>

#define LED 	LATDbits.LATD0 


// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); 	// Fosc=16x7.5MHz, Fcy=30MHz
// (units are instruction cycles, Tcy=33.33ns @ 30 MIPS)
_FWDT(WDT_OFF);                  	// Watchdog timer off
_FBORPOR(MCLR_DIS);  				// Master Clear Pin disabled

/*************Global Variables and Constants*************/
/*Variables used for period calculation*/
unsigned int timePeriod= 0; 
unsigned int current_value=0,previous_value=0;
unsigned int new_value=0;

void __attribute__((__interrupt__)) _IC7Interrupt(void); 
void __attribute__((__interrupt__, __shadow__)) _T2Interrupt(void);


/****FUNCTION PROTOTYPES****/
void IC7_SETUP(void);
void TIMER2_SETUP (void);
void setup();

/******MAIN BODY******/
int main (void)
{
TRISD=0;                  			// Setting Port D pins as outputs
PORTD=0;                  			// Reset The LED
PORTD=0xff;				  			// Light The LED, to test the PIC is working
TRISB=0x003f; 				  		// Setting all PortB as inputs
ADPCFG=0xffff;						// Setting the analogue pin as digital inputs


TIMER2_SETUP();             		// Calling the Timer Setup Function
IC7_SETUP();				  		// Calling the Input Setup Function
setup();							// Calling the UART function


while(1)
{
}
return (0);
}

/***SETUP_IC****/
void IC7_SETUP (void)
{
// Register 13-1: ICxCON: Input Capture x Control Register in datasheet // 
IC7CONbits.ICM= 0b011;				// Input Capture Mode Select (Every rising edge)
IC7CONbits.ICBNE=0;					// Input Capture Buffer Empty Status (Read Only)
IC7CONbits.ICOV=0;					// Input Capture Overflow Status Flag (Read Only)
IC7CONbits.ICI= 00;					// Select Number of Captures per Interrupt bits (00 = Interrupt on every capture event)
IC7CONbits.ICTMR=1;					// Input Capture Timer Select bits (1=TMR2 contents are captured on captured event)
IC7CONbits.ICSIDL=0;    			// Input Capture Module Stop in Idle Control(0=Input capture module will continue to operate in CPU Idle mode)
// Register 6-6: IFS1: Interrupt Flag Status Register 1
IFS1bits.IC7IF = 0;       			// Input Capture Channel 7 Interrupt Flag Status )0=Interrupt bit is cleared
// Register 6-9: IEC1: Interrupt Enable Control Register 1
IEC1bits.IC7IE = 1;     			// Input Capture Channel 7 Interrupt Enable bit (1 = Interrupt request enabled) 
}


/****INTERRUPT FOR IC7****/
// Capture Interrupt Service Routine 
//unsigned int timePeriod= 0; 
void __attribute__((__interrupt__, no_auto_psv )) _IC7Interrupt(void)
{ 
	previous_value=current_value;
	current_value=IC7BUF;
	printf("Current value =%d \n, ",current_value);
	printf("Previous value =%d \n, ",previous_value);
	
	float time1 = 0;
	float time2 = 0;
	float time3 = 0;
	float time4 = 0;
	float frequency = 0;
	
	if(current_value>previous_value)
	{ 
		timePeriod = current_value-previous_value; 
		printf("timePeriod =%d \n, ",timePeriod);
		time1 = timePeriod*pow(33.33,-9);
		time2 = pow((float)time2, -9);
		frequency = 1/time2;
		printf("frequency=%f Hz \n, ",time1);
	}
	
}



/***TIMER_SETUP***/
void TIMER2_SETUP (void)
{
T2CON = 0x00; 				// Stops the Timer2 and reset control reg.
T2CONbits.TCS=0; 			// Using Internal Clock (Fosc/4)
T2CONbits.T32=0;			// TMR2 and TMR3 form separate 16-bit timer
T2CONbits.TCKPS=0;  		// Using 1:1 prescale value
T2CONbits.TGATE=0;			// Timer Gate Accumulation Disabled
T2CONbits.TSIDL=0;			// Continue in Idle Mode*/
TMR2 = 0x00; 				// Clear contents of the timer register
PR2 = 0xFFFF; 				// Load the Period register with the value 0xFFFF
IPC1bits.T2IP = 0x01; 		// Setup Timer2 interrupt for desired priority leve
							// (This example assigns level 1 priority)
IFS0bits.T2IF = 0; 			// Clear the Timer2 interrupt status flag
IEC0bits.T2IE = 1; 			// Enable Timer1 interrupts
T2CONbits.TON = 1; 			// Start Timer1 with prescaler settings at 1:1 and 
							// clock source set to the internal instruction cycle
}

/* Example code for Timer1 ISR*/
void __attribute__((__interrupt__, no_auto_psv, __shadow__)) _T2Interrupt(void)
{
/* Interrupt Service Routine code goes here         */
IFS0bits.T2IF = 0; //Reset Timer1 interrupt flag and Return from ISR
}



 void setup()
{
    // Set up UART
	// Default is 8 data bits, 1 stop bit, no parity bit
	U1BRG = 48;            	// 38400 baud @ 30 MIPS
	U1MODEbits.UARTEN = 1; 	// Enable UART
	U1STAbits.UTXISEL = 1; 	// interrupt when TX buffer is empty
	U1STAbits.UTXEN = 1;   	// Enable TX
}
 

you have printf() statements in your interrupt service function which will slow everything down.

keep the interrupt service routines as short as possible, e.g. read an ADC and store the value in a global array, and do any logging and display of results in the main() function
 
Thanks for your reply, I made the following changes to the program, when viewing the UART on the PICKIT2 I can see the printf statement saying that the program is in the while loop but the moment I turn on the input into the IC7 pin on RB4 the PIC stops? any ideas?

Code:
# include <p30f4011.h>
# include <math.h>
# include <stdio.h>
# include<InCap.h>
# include <xc.h>
# include <libpic30.h>



// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); 	// Fosc=16x7.5MHz, Fcy=30MHz
// (units are instruction cycles, Tcy=33.33ns @ 30 MIPS)
_FWDT(WDT_OFF);                  	// Watchdog timer off
_FBORPOR(MCLR_DIS);  				// Master Clear Pin disabled

/*************Global Variables and Constants*************/
/*Variables used for period calculation*/
unsigned int timePeriod= 0; 
unsigned int current_value=0,previous_value=0;

/****FUNCTION PROTOTYPES****/
void __attribute__((__interrupt__)) _IC7Interrupt(void); 
void __attribute__((__interrupt__, __shadow__)) _T2Interrupt(void);
void IC7_SETUP(void);
void TIMER2_SETUP (void);
void setup();

/******MAIN BODY******/
int main (void)
{
TRISD=0b0000;                  		// Setting Port D pins as outputs						
PORTD=0b0000;				  		// Turn off all Port D outputs
TRISB=0b11111111; 				  	// Setting all PortB as inputs
// ADPCFG: A/D Port Configuration Register
ADPCFG= 0b11111111;					// 1 = Analog input pin in Digital mode

//*****Calling functions************* // 
TIMER2_SETUP();             		// Calling the Timer Setup Function
IC7_SETUP();				  		// Calling the Input Setup Function
setup();							// Calling the UART function

while(1)
{
printf("In while loop \n, ");
previous_value = current_value;
if(current_value > previous_value)
	{ 
		timePeriod = current_value-previous_value; 
		printf("timePeriod=%d Hz \n, ",timePeriod);
	}
}
return (0);
}

/***SETUP_IC****/
void IC7_SETUP (void)
{
// Register 13-1: ICxCON: Input Capture x Control Register in datasheet // 
IC7CONbits.ICM= 0b011;				// Input Capture Mode Select (Every rising edge)
IC7CONbits.ICBNE=0;					// Input Capture Buffer Empty Status (Read Only)
IC7CONbits.ICOV=0;					// Input Capture Overflow Status Flag (Read Only)
IC7CONbits.ICI= 00;					// Select Number of Captures per Interrupt bits (00 = Interrupt on every capture event)
IC7CONbits.ICTMR=1;					// Input Capture Timer Select bits (1=TMR2 contents are captured on captured event)
IC7CONbits.ICSIDL=0;    			// Input Capture Module Stop in Idle Control(0=Input capture module will continue to operate in CPU Idle mode)
// Register 6-6: IFS1: Interrupt Flag Status Register 1
IFS1bits.IC7IF = 0;       			// Input Capture Channel 7 Interrupt Flag Status )0=Interrupt bit is cleared
// Register 6-9: IEC1: Interrupt Enable Control Register 1
IEC1bits.IC7IE = 1;     			// Input Capture Channel 7 Interrupt Enable bit (1 = Interrupt request enabled) 
}

/****INTERRUPT FOR IC7****/
// Capture Interrupt Service Routine 
//unsigned int timePeriod= 0; 
void __attribute__((__interrupt__, no_auto_psv )) _IC7Interrupt(void)
{ 
	current_value=IC7BUF;
}



/***TIMER_SETUP***/
void TIMER2_SETUP (void)
{
T2CON = 0x00; 				// Stops the Timer2 and reset control reg.
T2CONbits.TCS=0; 			// Using Internal Clock (Fosc/4)
T2CONbits.T32=0;			// TMR2 and TMR3 form separate 16-bit timer
T2CONbits.TCKPS=0;  		// Using 1:1 prescale value
T2CONbits.TGATE=0;			// Timer Gate Accumulation Disabled
T2CONbits.TSIDL=0;			// Continue in Idle Mode*/
TMR2 = 0x00; 				// Clear contents of the timer register
PR2 = 0xFFFF; 				// Load the Period register with the value 0xFFFF
IPC1bits.T2IP = 0x01; 		// Setup Timer2 interrupt for desired priority leve
							// (This example assigns level 1 priority)
IFS0bits.T2IF = 0; 			// Clear the Timer2 interrupt status flag
IEC0bits.T2IE = 1; 			// Enable Timer1 interrupts
T2CONbits.TON = 1; 			// Start Timer1 with prescaler settings at 1:1 and 
							// clock source set to the internal instruction cycle
}

/* Example code for Timer1 ISR*/
void __attribute__((__interrupt__, no_auto_psv, __shadow__)) _T2Interrupt(void)
{
/* Interrupt Service Routine code goes here         */
IFS0bits.T2IF = 0; //Reset Timer1 interrupt flag and Return from ISR
}



 void setup()
{
    // Set up UART
	// Default is 8 data bits, 1 stop bit, no parity bit
	U1BRG = 48;            	// 38400 baud @ 30 MIPS
	U1MODEbits.UARTEN = 1; 	// Enable UART
	U1STAbits.UTXISEL = 1; 	// interrupt when TX buffer is empty
	U1STAbits.UTXEN = 1;   	// Enable TX
}
 

I guess you forgot to clear the interrupt flag, resulting in a never ending interrupt.
 
Hey thanks for that, I got the program working qand added a pull down resistor to the input signal, at 100kHz it has an error of 1.4%. at 500Hz it has an error of 1.8%. Once I reduce the input frequency below 452 Hz my calculated frequency jumps to 80kHz and constantly changes to mad numbers. Any ideas, most of my program is below. Edit: I looked at the values of the timePeriod variable in the program its roughly at 65535 when then frequency values go astray..as its a 16bit chip. I guess if I reduce my PLL to 8 instead of 16 I might avoid overflow?
Code:
/*************Global Variables and Constants*************/
/*Variables used for period calculation*/
float timePeriod= 0; 
unsigned int current_value=0,previous_value=0;

/****FUNCTION PROTOTYPES****/
// Function prototype for Input capture 7 (IC7) interrupt service routine
void __attribute__((__interrupt__)) _IC7Interrupt(void); 

// Function prototype for Timer 2 interrupt service routine
void __attribute__((__interrupt__, __shadow__)) _T2Interrupt(void);

// Function prototype for IC7 setup
void IC7_SETUP(void);

// Function prototype for timer2 setup
void TIMER2_SETUP (void);

// Function prototype for UART setup
void setup();

/******MAIN BODY******/
int main (void)
{
TRISD=0b0000;                  		// Setting Port D pins as outputs						
PORTD=0b0000;				  		// Turn off all Port D outputs
TRISB=0b11111111; 				  	// Setting all PortB as inputs
// ADPCFG: A/D Port Configuration Register
ADPCFG= 0b11111111;					// 1 = Analog input pin in Digital mode

//*****Calling functions*************8 // 
TIMER2_SETUP();             		// Calling the Timer Setup Function
IC7_SETUP();				  		// Calling the Input Setup Function
_IC7Interrupt();
_T2Interrupt();
setup();							// Calling the UART function

while(1)
{
// printf("current value=%04d \n,",current_value);
// printf("previous_value=%04d \n,",previous_value);
float frequency = 0;
float time3=0;
float time4=0;
	
if(current_value > previous_value)
	{ 
		timePeriod = current_value-previous_value; 
		// printf("timePeriod (if) =%f \n, ",timePeriod);
		// Multiply number of unstruction cycles by time per instruction cycle (33.33ns)
		time3 = timePeriod * 0.0000000333;
		// printf("time3 =%f \n, ",time3);
		// Calculate frequency: 1/time
		frequency = 1/time3;
		printf("frequency =%f Hz \n, ",frequency);	
	}

}
 

you are probably getting overflow on the timer counts at low frequencies

I assume you are using 16 bit timers
I seem to remember the DSPIC30f4011 has two 32bit timers
 

Code:
previous_value = current_value;
if(current_value > previous_value)

Not sure that makes sense either!

Brian.
 

Code:
previous_value = current_value;
if(current_value > previous_value)

Not sure that makes sense either!

Brian.

I meant to take out the If statement it was left over from a previous route I went down, it isn't doing any harm the way it is but its not needed. I see the 30F4011 has a feature to pair up two 16 bit timers to create a 32 bit timer so I'll have a go at it tomorrow. Thanks for the help
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top