Forums

Software question: Capturing a servo PPM using a PIC24FJ64GA002...

Started by frenchy March 17, 2008
Howdy,
What input capture mode is best for capturing a servo PPM using a
PIC24FJ64GA002?  I need to capture every edge (ICM2:ICM0 =3D 001), but
then the time between two captures isn't necessarily always the pulse
I am looking for....it might be the 18ms "dead time" between pulses.
I wish I could set it to capture the falling, then rising edges and
interrupt on the latter (my polarity is reversed if I use an inverting
common emitter buffer for interfacing).  But according to the below
choices, if I want to detect both rising AND falling, it has no
intelligence as to whether the interrupt was caused by rising or
falling.  Using a hardware peripheral like this, I didnt think I had
to implement all kinds of software checking to see what I ended up
with (to keep the ISR short)..

any comments would be helpful.
respectfully,
frenchy

bit 15-14 Unimplemented: Read as =910=92

bit 13 ICSIDL: Input Capture x Module Stop in Idle Control bit
1 =3D Input capture module will halt in CPU Idle mode
0 =3D Input capture module will continue to operate in CPU Idle mode

bit 12-8 Unimplemented: Read as =910=92

bit 7 ICTMR: Input Capture x Timer Select bit
1 =3D TMR2 contents are captured on capture event
0 =3D TMR3 contents are captured on capture event

bit 6-5 ICI1:ICI0: Select Number of Captures per Interrupt bits
11 =3D Interrupt on every fourth capture event
10 =3D Interrupt on every third capture event
01 =3D Interrupt on every second capture event
00 =3D Interrupt on every capture event

bit 4 ICOV: Input Capture x Overflow Status Flag bit (read-only)
1 =3D Input capture overflow occurred
0 =3D No input capture overflow occurred

bit 3 ICBNE: Input Capture x Buffer Empty Status bit (read-only)
1 =3D Input capture buffer is not empty, at least one more capture value
can be read
0 =3D Input capture buffer is empty

bit 2-0 ICM2:ICM0: Input Capture x Mode Select bits(1)
111 =3D Input capture functions as interrupt pin only when device is in
Sleep or Idle mode (rising edge
detect only, all other control bits are not applicable)
110 =3D Unused (module disabled)
101 =3D Capture mode, every 16th rising edge
100 =3D Capture mode, every 4th rising edge
011 =3D Capture mode, every rising edge
010 =3D Capture mode, every falling edge
001 =3D Capture mode, every edge (rising and falling) =96 ICI<1:0> bits do
not control interrupt generation
for this mode
000 =3D Input capture module turned off


thx,
frenchy
On 2008-03-17, frenchy <deja@houseofharmonystudios.com> wrote:
> Howdy, > What input capture mode is best for capturing a servo PPM using a > PIC24FJ64GA002? I need to capture every edge (ICM2:ICM0 = 001), but > then the time between two captures isn't necessarily always the pulse > I am looking for....it might be the 18ms "dead time" between pulses. > I wish I could set it to capture the falling, then rising edges and > interrupt on the latter (my polarity is reversed if I use an inverting > common emitter buffer for interfacing). But according to the below > choices, if I want to detect both rising AND falling, it has no > intelligence as to whether the interrupt was caused by rising or > falling. Using a hardware peripheral like this, I didnt think I had > to implement all kinds of software checking to see what I ended up > with (to keep the ISR short)..
I'm not familar with the PIC24 chips so I'll limit my comments to general notes only. It seems as though you are getting lost in details and losing sight of general principals anyway. You don't need a lot of specialised peripherals to do this in a fairly straightforward manner, just a timer and a reasonably simple ISR. The first requirement is a free running timer. The speed of the timer is not critical provided that it does not wrap around within the maximum pulse length, say 2.5ms (it's supposed to be 2ms but some manufacturers have apparently started to take liberties there). However since you're using a 16 bit machine that shouldn't be a problem. At the other end of the scale you need it to be fast enough to give sufficent resolution. The receiver is designed with servos in mind that typically have a resolution of around 7 bits, so an equivalent resolution in your device would imply a minimum timer frequency of around 100kHz. Obviously, faster would give you better resolution. Set your input to interrupt on change. In your ISR the first thing to do is check the state of the pin - you need both rising and falling edges of the pulse. If it is high you have found the rising edge of the pulse. Stash the timer value in a variable somewhere, eg riseTime, and return from interrupt. If it is low then you have the falling edge. Copy the timer into another variable fallTime. Subtract fallTime from riseTime to give the pulse duration. If the timer was at a fairly high count at riseTime it is possible that the timer has overflowed during the pulse but don't worry about it - if that is the case then the subtraction will underflow and the duration will still be correct. Store the duration into another variable where it can be accessed by the surrounding program and return from interrupt. Bear in mind that the value recorded using the method described here is the pulse duration, including the initial 1ms that is simply there to denote the presence of the pulse. This is may need some further conversion into a logical value to go from 0 to whatever maximum value you want, or a signed value centred on 1.5ms. However, what is appropriate depends on your circumstances and preferences so I'll leave it to you to decide what to do with the value obtained. -- Andrew Smallshaw andrews@sdf.lonestar.org
On 2008-03-18, Andrew Smallshaw <andrews@sdf.lonestar.org> wrote:
> > If it is low then you have the falling edge. Copy the timer into > another variable fallTime. Subtract fallTime from riseTime to give > the pulse duration.
Subtract riseTime from fallTime... -- Andrew Smallshaw andrews@sdf.lonestar.org
On Mar 18, 8:47 am, Andrew Smallshaw <andr...@sdf.lonestar.org> wrote:
> On 2008-03-18, Andrew Smallshaw <andr...@sdf.lonestar.org> wrote: > > > > > If it is low then you have the falling edge. Copy the timer into > > another variable fallTime. Subtract fallTime from riseTime to give > > the pulse duration. > > Subtract riseTime from fallTime... > > -- > Andrew Smallshaw > andr...@sdf.lonestar.org
Andrew, Thank you very much. Like you said in your response, I was caught up in the whole concept of using the "input capture" peripheral and I was blinded to the much simpler solution of using a free-running timer and just looking at the timer values every-time the internal comparator switched state. I already had 2 comparators sitting there and didnt even realize it!! This solved my software problem (timing and interrupts) and also my hardware problem (undetermined voltage levels due to battery sag). It worked great. Thank you. respect, frenchy