chipKIT® Development Platform

Inspired by Arduino™

Input capture

Created Wed, 28 Dec 2011 05:28:18 +0000 by Sleepy


Sleepy

Wed, 28 Dec 2011 05:28:18 +0000

I'm trying to use the input capture to measure the period of a signal. The problem im having is that when given a constant signal the code below returns random numbers on the serial monitor. This is code is based on a code example for peripheral library input capture on the pic32. I'm thinking it may have something to do with the uart interupt I have tryed different baud rates with the same results any suggestions would be appreciated. unsigned int CaptureTime; void setup() {

#define FOSC 80E6 #define PB_DIV 8 #define PRESCALE 256 #define MSEC 10E-3 #define T1_TICK (500 * MSEC * FOSC)/(PB_DIV * PRESCALE) Serial.begin(9600); //Clear interrupt flag mIC1ClearIntFlag();

// Setup Timer 3
OpenTimer3(T3_ON | T1_PS_1_256, T1_TICK);

// Enable Input Capture Module 1
// - Capture Every edge
// - Enable capture interrupts
// - Use Timer 3 source
// - Capture rising edge first
OpenCapture1(IC_EVERY_RISE_EDGE | IC_INT_1CAPTURE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON);

} void loop(){ //Now Read the captured timer value if ( mIC1CaptureReady() ){

	CaptureTime = mIC1ReadCapture();
	//process data
	// ...
    Serial.println(CaptureTime, DEC);

} }


GeneApperson

Wed, 28 Dec 2011 22:21:05 +0000

The Input Capture unit 'captures' the value in the timer when the triggering event occurs. (In this case a rising edge on the pin). What should be printing out are the successive values in T3 on each capture event.

If you want to determine the time between rising edges, for example, you have to subtract the first capture from the second to get the time delta. The result will be in units of the period of the timer.

I noticed also, in you code, that you are assuming that the peripheral bus clock divider is 8. It is actually 1, unless you have modified the code in init(). By default, the peripheral bus is run at 80Mhz.

The Serial object doesn't do interrupt drive i/o for transmit, only for receive, so there shouldn't be any UART interrupts happening. However, keep in mind that at 9600 baud, it takes about a millisecond per character written for the writes to the serial port. Depending on the frequency of the signal you are trying to sample, you could easily be missing edges because of the time spent in Serial.println.

Gene Apperson Digilent


CNCaddict

Thu, 29 Dec 2011 05:48:02 +0000

Hey Sleepy...thanks for the proper notation on "readcapture" I've been sweating this for days!!!!


Sleepy

Fri, 30 Dec 2011 07:08:21 +0000

Thank you for the information Gene. I didn't realize the timer was not being cleared. I didn't want any issues with overflow so instead of subtraction I just added TMR3 = 0x0; after the capture read and it seems to work. I need to make this into an isr so that the time taken by the loop doesn't affect when the timer is cleared since this is going to be part of a fairly large code. I'm not quite sure the syntax of an input capture isr I've read through the input capture section of the peripheral library guide and I'm still not clear on this.


CNCaddict

Fri, 30 Dec 2011 18:58:05 +0000

I might be mistaken but if you zero the timer after the capture read there will be lost time depending on how long after the capture event you actually read the buffer.

On a side note I seem to be getting 32bit numbers (setup with only one timer) when I read the buffer. Don't want to derail the thread..but I figured it's related. Here is the code

unsigned int CurrentRxPulse = 0;

CloseTimer3(); OpenTimer3(T3_ON | T3_PS_1_1, 4000); OpenCapture2( IC_EVERY_EDGE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON );

CurrentRxPulse = mIC2ReadCapture();

Serial.println(CurrentRxPulse,DEC);

and I'm getting numbers on the serial that look like this.... Does anyone know where I've gone wrong, these should be 16bit values.....

147458250 221908282 132122592 206900309 206900309 124847985 199756776 199756776 116655860 191630188 191630188 116590323 191236966 101123591 176032382 176032382


CNCaddict

Sat, 31 Dec 2011 04:14:47 +0000

I've done more digging and it seems like it's reading in 32bit mode no matter what I do. The only way I can get it to read 16bits is if I change to Timer2 and make sure Timer3 is not running. Anyone have some ideas?


Sleepy

Mon, 02 Jan 2012 04:15:32 +0000

Im using this for the ISR and I keep geting the error bellow void __ISR(_INPUT_CAPTURE_1_VECTOR , ipl1) IC1Handler(void)

rpm.cpp.o: In function __vector_dispatch_5': rpm.cpp:(.vector_5+0x0): undefined reference to IC1Handler' collect2: ld returned 1 exit status

I got the isr from a post on the microchip pic 32 forum. I have no idea where the documentation for this is. The periferal library guid shows how to set up an input capture inturupt but not the ISR. reading through the inturupt section didn't help much either. If someone could show me where to find this information that would be helpful.


GeneApperson

Fri, 06 Jan 2012 00:29:50 +0000

@sleepy

Have you provided a definition for the IC1Handler function? The linker is trying to bind the vector dispatcher to IC1Handler and the function is not defined.

Your code should look something like:

void __ISR(_INPUT_CAPTURE_1_VECTOR , ipl1) IC1Handler(void) { your isr code goes here }

The __ISR(...) macro tells the compiler that the IC1Handler function is an interrupt service routine and the compiler then generates slightly different code than it would for a normal function. You are, however, defining a function and need to provide the code for that function somewhere.

If you were to do this:

void __ISR(_INPUT_CAPTURE_1_VECTOR , ipl1) IC1Handler(void);

What you will have done is give the compiler a function prototype (or forward declaration), which tells it that somewhere there will be a function with this name and it will have these properties. This allows you to refer to that function someplace other than where it is defined (or before it has been defined), but there still needs to be a definition for the function somewhere.

Gene Apperson Digilent


CNCaddict

Sun, 05 Feb 2012 23:30:05 +0000

I figured out the problem. It seems like Microchip has a flaw in the PIC32 when reading the input capture so that no matter what it outputs 32 bits. The upper 16 bits are from Timer3. Please see Errata 25

http://ww1.microchip.com/downloads/en/DeviceDoc/80440F.pdf

The fix is to mask off the upper bits e.g. result = 0xFFFF & IC1BUF

I hope this saves someone a lot of time...when things seem to be going haywire.


Taygan

Sat, 03 Mar 2012 17:50:23 +0000

I had the same frustration with 32 bit read on ICXBUFF, took me a while to figure out it was still reading timer3. But masking worked great.

Also another issue that was causing me grief was in the way i setup the input capture:

OpenCapture2(IC_EVERY_EDGE | IC_FEDGE_RISE | IC_TIMER2_SRC | IC_INT_2CAPTURE | IC_ON);

This captures every edge not waiting for rising edge first even though you specified that with IC_FEDGE_RISE.

What i meant to use was this: IC_SP_EVERY_EDGE

OpenCapture2(IC_SP_EVERY_EDGE | IC_FEDGE_RISE | IC_TIMER2_SRC | IC_INT_2CAPTURE | IC_ON);

Just thought i would share of few of my issues and fixes in case you having the same problem.


maszkows

Sun, 29 Jul 2012 14:20:11 +0000

Pls excuse my rookie question.

based on Sleepy code (first post) which pin in Uno32 i should use to input signal to capture?

how to read code to refer to documentation to find pin number.

br Dan


maszkows

Mon, 30 Jul 2012 06:56:29 +0000

ok i think i now

OpenCapture1 -> IC1 -> PIC32 42 -> ChipKit Pin2


GeneApperson

Mon, 13 Aug 2012 23:18:12 +0000

Correct, input capture IC1 is on digital pin 2.

Gene Apperson Digilent