EmbeddedRelated.com
Forums

pulse counter using LPC1768 proving to very challenging

Started by navman June 7, 2011
Hi,
I'm trying to counter some pulses (2-10usec width) using the LPC1768
Cortex-M3 microcontroller. There are 2 channels on which I have count the
pulses on. I have to allow only pulses that are >=2us pulse width (so we
cannot simply use the counter function).  

But it is turning out to be an incredibly difficult feat to achieve this on
a 100MHz Cortex-M3. The problem arises when we try to measure the pulse
width to allow only pulses lasting 2us or higher. We are trying to use a
capture pin and the capture interrupt. First we set it for a falling edge
and capture the timer value, then set it to rising edge and again capture
the timer value. Then take the difference between two values to see if it
>2usec. But the processing itself is taking over 6-8usec. We also tried
simply using a external interrupt & reading timer registers with each edge, but with the same results. We cannot seem to understand how or why the processing is taking so long there are hardly 3-4 "C" statements in the interrupt routine (change edge of capture, take the difference in captured values and compare if it is
>=2us). Any ideas how this feat could be accomplished on a LPC1768?
--------------------------------------- Posted through http://www.EmbeddedRelated.com
"navman" <naveen_pn@n_o_s_p_a_m.yahoo.com> wrote in message 
news:rMadnYYXWcwzuXPQnZ2dnUVZ_oydnZ2d@giganews.com...
> Hi, > I'm trying to counter some pulses (2-10usec width) using the LPC1768 > Cortex-M3 microcontroller. There are 2 channels on which I have count the > pulses on. I have to allow only pulses that are >=2us pulse width (so we > cannot simply use the counter function). > > But it is turning out to be an incredibly difficult feat to achieve this > on > a 100MHz Cortex-M3. The problem arises when we try to measure the pulse > width to allow only pulses lasting 2us or higher. We are trying to use a > capture pin and the capture interrupt. First we set it for a falling edge > and capture the timer value, then set it to rising edge and again capture > the timer value. Then take the difference between two values to see if it >>2usec. But the processing itself is taking over 6-8usec. We also tried > simply using a external interrupt & reading timer registers with each > edge, > but with the same results. > > We cannot seem to understand how or why the processing is taking so long > there are hardly 3-4 "C" statements in the interrupt routine (change edge > of capture, take the difference in captured values and compare if it is >>=2us). Any ideas how this feat could be accomplished on a LPC1768? > > > --------------------------------------- > Posted through http://www.EmbeddedRelated.com
I can't help with this specific micro, but I've encountered the problem on various other platforms, and solved it by using polling rather than interrupts. Avoiding the context saving associated with interrupts can save you a significant amount of time if your processing task is otherwise reasonably trivial, as yours seems to be. This solution does depend on being able to sacrifice some processing time for the polling loop (interrupts disabled), that will depend on the pulse frequency and what else the device has to contend with. You might also consider doing your time-critical coding in asm, if that's possible. Have oyu checked your listings to see how many removeable instructions the compiler is inserting?
On Tue, 07 Jun 2011 08:16:30 -0500, "navman"
<naveen_pn@n_o_s_p_a_m.yahoo.com> wrote:

>Hi, >I'm trying to counter some pulses (2-10usec width) using the LPC1768 >Cortex-M3 microcontroller. There are 2 channels on which I have count the >pulses on. I have to allow only pulses that are >=2us pulse width (so we >cannot simply use the counter function). > >But it is turning out to be an incredibly difficult feat to achieve this on >a 100MHz Cortex-M3. The problem arises when we try to measure the pulse >width to allow only pulses lasting 2us or higher. We are trying to use a >capture pin and the capture interrupt. First we set it for a falling edge >and capture the timer value, then set it to rising edge and again capture >the timer value. Then take the difference between two values to see if it >>2usec. But the processing itself is taking over 6-8usec. We also tried >simply using a external interrupt & reading timer registers with each edge, >but with the same results. > >We cannot seem to understand how or why the processing is taking so long >there are hardly 3-4 "C" statements in the interrupt routine (change edge >of capture, take the difference in captured values and compare if it is >>=2us). Any ideas how this feat could be accomplished on a LPC1768? > > >--------------------------------------- >Posted through http://www.EmbeddedRelated.com
On 07/06/2011 15:33, Bruce Varley wrote:
> "navman"<naveen_pn@n_o_s_p_a_m.yahoo.com> wrote in message > news:rMadnYYXWcwzuXPQnZ2dnUVZ_oydnZ2d@giganews.com... >> Hi, >> I'm trying to counter some pulses (2-10usec width) using the LPC1768 >> Cortex-M3 microcontroller. There are 2 channels on which I have count the >> pulses on. I have to allow only pulses that are>=2us pulse width (so we >> cannot simply use the counter function). >> >> But it is turning out to be an incredibly difficult feat to achieve this >> on >> a 100MHz Cortex-M3. The problem arises when we try to measure the pulse >> width to allow only pulses lasting 2us or higher. We are trying to use a >> capture pin and the capture interrupt. First we set it for a falling edge >> and capture the timer value, then set it to rising edge and again capture >> the timer value. Then take the difference between two values to see if it >>> 2usec. But the processing itself is taking over 6-8usec. We also tried >> simply using a external interrupt& reading timer registers with each >> edge, >> but with the same results. >>
Can you connect the signal to two pins, so that one will capture times on a falling edge, and the other will capture times and cause an interrupt on the rising edge? Have you considered some analogue tricks, assuming you don't need too much accuracy for your measurements? A diode, a capacitor and a couple of resistors should let you charge up a capacitor during the pulse. Measure the voltage on the capacitor with the ADC when the pulse is complete. Or use an analogue comparator to trigger an interrupt on the processor once the capacitor voltage is over a certain level.
>> We cannot seem to understand how or why the processing is taking so long >> there are hardly 3-4 "C" statements in the interrupt routine (change edge >> of capture, take the difference in captured values and compare if it is >>> =2us). Any ideas how this feat could be accomplished on a LPC1768? > > I can't help with this specific micro, but I've encountered the problem on > various other platforms, and solved it by using polling rather than > interrupts. Avoiding the context saving associated with interrupts can save > you a significant amount of time if your processing task is otherwise > reasonably trivial, as yours seems to be. This solution does depend on being > able to sacrifice some processing time for the polling loop (interrupts > disabled), that will depend on the pulse frequency and what else the device > has to contend with. > > You might also consider doing your time-critical coding in asm, if that's > possible. Have oyu checked your listings to see how many removeable > instructions the compiler is inserting? > >
The compiler may be generating too much code for context saving. A common cause of that is to call external functions from within the interrupt function - since the compiler doesn't know what registers it uses, it must save everything. And are you using appropriate flags for the compiler? Many people complain their compiler code is poor, when it turns out they have disabled optimisation...
navman wrote:
>I'm trying to counter some pulses (2-10usec width) using the LPC1768 >Cortex-M3 microcontroller. There are 2 channels on which I have count the >pulses on. I have to allow only pulses that are >=2us pulse width (so we >cannot simply use the counter function). > ...
I have not used the LPC1768, so these are generic suggestions: a) If they are running in FLASH, make your interrupt routines RAM resident. Ditto for critical functions in normal code. b) Do the width computation/decision inside the rising edge interrupt handler. c) If possible, configure the capture to work on either edge to save the time needed to reconfigure it. -- Roberto Waltman [ Please reply to the group. Return address is invalid ]
In article <cqOdncM8Pd0YsXPQnZ2dnUVZ8tSdnZ2d@lyse.net>, 
david@westcontrol.removethisbit.com says...
> > On 07/06/2011 15:33, Bruce Varley wrote: > > "navman"<naveen_pn@n_o_s_p_a_m.yahoo.com> wrote in message > > news:rMadnYYXWcwzuXPQnZ2dnUVZ_oydnZ2d@giganews.com... > >> Hi, > >> I'm trying to counter some pulses (2-10usec width) using the LPC1768 > >> Cortex-M3 microcontroller. There are 2 channels on which I have count the > >> pulses on. I have to allow only pulses that are>=2us pulse width (so we > >> cannot simply use the counter function). > >> > >> But it is turning out to be an incredibly difficult feat to achieve this > >> on > >> a 100MHz Cortex-M3. The problem arises when we try to measure the pulse > >> width to allow only pulses lasting 2us or higher. We are trying to use a > >> capture pin and the capture interrupt. First we set it for a falling edge > >> and capture the timer value, then set it to rising edge and again capture > >> the timer value. Then take the difference between two values to see if it > >>> 2usec. But the processing itself is taking over 6-8usec. We also tried > >> simply using a external interrupt& reading timer registers with each > >> edge, > >> but with the same results. > >> > > Can you connect the signal to two pins, so that one will capture times > on a falling edge, and the other will capture times and cause an > interrupt on the rising edge? > > Have you considered some analogue tricks, assuming you don't need too > much accuracy for your measurements? A diode, a capacitor and a couple > of resistors should let you charge up a capacitor during the pulse. > Measure the voltage on the capacitor with the ADC when the pulse is > complete. Or use an analogue comparator to trigger an interrupt on the > processor once the capacitor voltage is over a certain level.
You might not even need the comparator if the input pin threshold level is consistent over the operating conditions. A simple RC filter might trigger the interrupt only if the pulse length is over the threshold. Using a comparator does make it easier to compute the trigger pulse width. If you fed the reference leg of the comparator with the output of one of the LPC1768 DAC outputs, you could tune the triggering pulse width in software.
>
<<Snip>> Mark Borgerson
On 6/7/2011 6:16 AM, navman wrote:
> I'm trying to counter some pulses (2-10usec width) using the LPC1768 > Cortex-M3 microcontroller. There are 2 channels on which I have count the > pulses on. I have to allow only pulses that are>=2us pulse width (so we > cannot simply use the counter function).
Can you *prevent* (filter) short pulses from ever getting to the pin? I.e., a simple digital filter can excise all short pulses without affecting any *longer* pulses.
> But it is turning out to be an incredibly difficult feat to achieve this on > a 100MHz Cortex-M3. The problem arises when we try to measure the pulse > width to allow only pulses lasting 2us or higher. We are trying to use a > capture pin and the capture interrupt. First we set it for a falling edge > and capture the timer value, then set it to rising edge and again capture > the timer value. Then take the difference between two values to see if it > 2usec. But the processing itself is taking over 6-8usec. We also tried > simply using a external interrupt& reading timer registers with each edge, > but with the same results.
Is the control logic "double buffered"? E.g., some devices would allow you to preload the *next* contents -- which would be transferred into the *real* hardware when the first condition had been satisfied. [sorry, I'm not familiar with the counter/timer channels on the device] Can you, instead, set up the device to *start* a counter on the "leading edge" (whether that is rising or falling) of the pulse (note NO interrupt generated, here!), program the counter (timer) for "2 us" and have the timer *overflow* trigger THE interrupt (which just polls the state of the pin to see if it is "still" at the right level to be countable) [there are flaws in this scheme -- depending on the actual nature of your input pulse stream] Some devices with double buffered logic will let you use this to enqueue the *next* set of controls for the channel so that the timeout/overflow can effectively reprogram the channel for you -- to generate an IRQ on the *trailing* edge of the pulse, for example. [see initial disclaimer]
> We cannot seem to understand how or why the processing is taking so long > there are hardly 3-4 "C" statements in the interrupt routine (change edge > of capture, take the difference in captured values and compare if it is > =2us). Any ideas how this feat could be accomplished on a LPC1768?
Rewrite it in ASM. This is clearly (IMO) a case where the "lack of clarity" of ASM is easily justified by its brevity. What do you need, a handful of instructions?? Don't do *any* work in the IRQ. Just grab the data that you need and make the decision about how to use it *later*. What guarantees do you have regarding the interarrival time of subsequent pulses, etc.? What happens to your system if, for example, a 100KHz signal suddenly appears on this pin? Will your system effectively "lock up" because it is dutifully catching interrupts (that probably are meaningless in this case)? Consider designing the code so that this is a self-limiting process...
I think the solution is obvious.

Configure for falling edge interrupt (I assume from your post that LOW
is ACTIVE).

In the interrupt, do the following:

1) Clear the interrupt flag
2) Verify that input pin is still ACTIVE.  If it is not, exit silently
(no event).
3) Do a CPU timed busy-wait for 2us (minus typ/max interrupt latency
up to this point).  You might need inline asm or a calibrated function
for this purpose.
4) When the busy-wait function returns, check the interrupt flag
again.  If there was another interrupt event, go back to 2).
5) Verify that input pin is still ACTIVE.  If it is not, exit silently
(no event).
6) Accept the event and exit the interrupt function.

The interrupt function will consume 2us plus overhead.  It will be as
accurate, as your prediction of typ/max interrupt latency is.  That
depends mostly on the usage of "critical section" primitives in the
rest of your code.  The LPC1768 contains an ARM core, so you could
reserve the FIQ (fast interrupt) for this purpose only, and use IRQ
(slow interrupt) throughout the rest of your code (including OS).
That would allow you to never disable interrupts (FIQ) and thus never
suffer software-induced latency.  You could also move the vector table
and the FIQ handler code (which is the function described above) and
all of its variables / subfunctions, in an area that has predictable
memory timing.  I'm not aware of the LPC1768 details, but on other
archs you can use the TCM or disable i-cache via MMU for the memory
area in question.  The memory access doesn't have to be fast, it must
just be very very predictable.

Using these tips, you can achieve very reliable acception/rejection.
The imperfections are:

A) There is a "blind window" which is from detection of the edge to
the clear interrupt flag.  If there is a spurious HIGH in this window,
it will not be detected.  You could possibly extend the proposal,
using your counter mode to improve on this imperfection.

B) That most chips (and certainly the LPC1768 too) synchronize the
input pin before detecting edges.  Thus, some very fast flicker might
happen completely unnoticed by the hardware (and software).   You
would need to move the pulse detection into a specially designed
hardware circuit to handle this better.

C) The sampling of step 4 and 5 are not taken from the same-moment-in-
time.  Therefore the pulse must be longer than X to be accepted
reliably, but smaller than Y to be rejected reliably.  There is a
window in which a pulse may or may not be rejected.  This is the crux
of using software instead of hardware.  Again, you can only handle
this better in a specially designed hardware circuit.

Best regards
Marc
On Tue, 07 Jun 2011 15:49:22 +0200, David Brown wrote:

> On 07/06/2011 15:33, Bruce Varley wrote: >> "navman"<naveen_pn@n_o_s_p_a_m.yahoo.com> wrote in message >> news:rMadnYYXWcwzuXPQnZ2dnUVZ_oydnZ2d@giganews.com... >>> Hi, >>> I'm trying to counter some pulses (2-10usec width) using the LPC1768 >>> Cortex-M3 microcontroller. There are 2 channels on which I have count >>> the pulses on. I have to allow only pulses that are>=2us pulse width >>> (so we cannot simply use the counter function). >>> >>> But it is turning out to be an incredibly difficult feat to achieve >>> this on >>> a 100MHz Cortex-M3. The problem arises when we try to measure the >>> pulse width to allow only pulses lasting 2us or higher. We are trying >>> to use a capture pin and the capture interrupt. First we set it for a >>> falling edge and capture the timer value, then set it to rising edge >>> and again capture the timer value. Then take the difference between >>> two values to see if it >>>> 2usec. But the processing itself is taking over 6-8usec. We also >>>> tried >>> simply using a external interrupt& reading timer registers with each >>> edge, >>> but with the same results. >>> >>> > Can you connect the signal to two pins, so that one will capture times > on a falling edge, and the other will capture times and cause an > interrupt on the rising edge? > > Have you considered some analogue tricks, assuming you don't need too > much accuracy for your measurements? A diode, a capacitor and a couple > of resistors should let you charge up a capacitor during the pulse. > Measure the voltage on the capacitor with the ADC when the pulse is > complete. Or use an analogue comparator to trigger an interrupt on the > processor once the capacitor voltage is over a certain level. > >>> We cannot seem to understand how or why the processing is taking so >>> long there are hardly 3-4 "C" statements in the interrupt routine >>> (change edge of capture, take the difference in captured values and >>> compare if it is >>>> =2us). Any ideas how this feat could be accomplished on a LPC1768? >> >> I can't help with this specific micro, but I've encountered the problem >> on various other platforms, and solved it by using polling rather than >> interrupts. Avoiding the context saving associated with interrupts can >> save you a significant amount of time if your processing task is >> otherwise reasonably trivial, as yours seems to be. This solution does >> depend on being able to sacrifice some processing time for the polling >> loop (interrupts disabled), that will depend on the pulse frequency and >> what else the device has to contend with. >> >> You might also consider doing your time-critical coding in asm, if >> that's possible. Have oyu checked your listings to see how many >> removeable instructions the compiler is inserting? >> >> >> > The compiler may be generating too much code for context saving. A > common cause of that is to call external functions from within the > interrupt function - since the compiler doesn't know what registers it > uses, it must save everything. > > And are you using appropriate flags for the compiler? Many people > complain their compiler code is poor, when it turns out they have > disabled optimisation...
This is almost everything that I was going to suggest. Look at the assembly that your compiler is generating, and make sure that it's really as efficient as can possibly be. If it isn't, just go to the well and write the ISR in assembly language. Even on a 100MHz processor, 2us is an awfully short period of time. Doing some sort of preconditioning makes a lot of sense to me, although Schmitt trigger logic is rarely accurate enough for any practical purpose beyond glitch reduction. It should be possible to use a multivibrator (74xx126??) and some gates to do this if an RC and a Schmitt isn't accurate enough. An asynchronous clear counter would do the trick as well -- hold it in reset when the pulse is inactive, and trigger the micro whenever it counts to it's 'carry out' value. Then you just need to feed it an appropriate clock to hit your "more than 2us" criterion. If your ISR pops off quickly enough, and if it doesn't waste too much time, spin in the ISR until the signal goes inactive, and check the time. If that ">2us" can mean "sometimes _much_ greater than 2us" then this obviously won't work. I like the "two pins" approach, if you can make it unambiguous. Make that microcontroller hardware work for you, if you can. -- http://www.wescottdesign.com
"navman"  wrote:
>We cannot seem to understand how or why the processing is taking so long >there are hardly 3-4 "C" statements in the interrupt routine ...
Is flash prefetch enabled? -- Roberto Waltman [ Please reply to the group. Return address is invalid ]