pulseIn Taking "Too Long"

I'm modifying a project that was originally built for an Arduino using 0018 to run on an Arduino Mega2560 using 1.0. I'm using pulseIn to measure the length of a series of pulses, but pulse in is taking too long to return and missing pulses. It looks like pulseIn is running longer than it should, by "one pulse length." For instance, I record a 40 uS pulse, it will begin running, record the 40 uS pulse, and the run for an additional 40 uS, masking the next pulse.

This does not appear to be happening on the older hardware/software combination, and I can't explain it. It doesn't look like pulseIn has changed, so I'm at a loss. I'll have more time next week to look into this, but I'm curious if anyone else has seen similar behavior?

Thanks.

Post code.

If you had the polarity of the input pulse wrong, I suspect you could get effects like these i.e. measuring the length of the 'space' rather than the 'mark' iyswim.

Here's the meat of the code for the pulseIn function:

// wait for any previous pulse to end
    while ((*portInputRegister(port) & bit) == stateMask)
        if (numloops++ == maxloops)
            return 0;

    // wait for the pulse to start
    while ((*portInputRegister(port) & bit) != stateMask)
        if (numloops++ == maxloops)
            return 0;

    // wait for the pulse to stop
    while ((*portInputRegister(port) & bit) == stateMask) {
        if (numloops++ == maxloops)
            return 0;
        width++;
    }

So, it busywaits for one "on" pulse to stop, busywaits for the "off" pulse, then busywaits for the "on" pulse, THEN returns. So, if you just have a perfectly "square" pulse with ons and offs the same lengths, it can take up to three pulse lengths for pulsein() to return.

WizenedEE:
So, it busywaits for one "on" pulse to stop, busywaits for the "off" pulse, then busywaits for the "on" pulse, THEN returns. So, if you just have a perfectly "square" pulse with ons and offs the same lengths, it can take up to three pulse lengths for pulsein() to return.

In that case, it sounds like the wrong method to use to measure the length of a pulse that has already started.

The code is pretty simple:

digitalWrite(X, HIGH);
pulseIn(Y, LOW);
digitalWrite(X, LOW);

I can watch pins X and Y with an oscilloscope. X goes HIGH, the pulse starts Y goes LOW), after Y goes HIGH (pulse ends) it takes an additional "pulse length" for X to go low. This appeared repeatable with different length pulses, though I didn't get a chance to test this too much yet. I understand pulseIn has some pretty severe limitations, particularly since they don't appear to be made obvious in the Arduino reference documents, but I don't understand why it's taking so long to "reset" and be able to capture a new pulse.

I'm actually completely ok working in C, this is a modification to an existing project that already has the code written in Arduino, and I didn't feel like rewriting it in C.

measure the length of a pulse that has already started.

Pulsein() can't do that, it can only measure the next pulse. Mostly that's OK but for one-off pulses it's sometimes not appropriate.

X goes HIGH, the pulse starts Y goes LOW), after Y goes HIGH (pulse ends) it takes an additional "pulse length" for X to go low.

How long from X HIGH to Y LOW? That's the critical part. If it's too quick the code will miss the leading edge of Y and have to wait for the next one.


Rob

iwoloschin:
I'm actually completely ok working in C, this is a modification to an existing project that already has the code written in Arduino, and I didn't feel like rewriting it in C.

Everything in the Arduino core is just C-functions, so I don't see what you would be "re-writing". Perhaps it makes sense to look at the existing pulseIn()"function to see if it can be better adapted to what you are doing.

For timing, all I can say is that this code worked, and now I'm trying to modify it to work with an updated shield. For some reason, now it isn't working, and I can't figure out why, because pulseIn does not appear to have changed (at least according to the changelogs) in any significant ways.

I can probably post a scope capture tomorrow showing the timing.

As far as rewriting, I was hoping to simply update a shield and call the project done. However, I'm wondering if I would have been better off just designing my own hardware completely, I'm already doing that for another project with far more complex hardware requirements. The only problem, apart from the hardware design effort, is I would need to completely rewrite the code in "pure" C, which isn't hard, but is somewhat annoyingly time consuming.

I can probably post a scope capture tomorrow showing the timing.

Yes that may help.


Rob

I've tried attaching a PNG showing the trace, but the forum is rejecting me with the following error:

The upload folder is full. Please try a smaller file and/or contact an administrator.

I've uploaded the PNG to imgur, I have no idea how long they maintain images for, so I'm sorry if the link is dead (mostly thinking if anyone stumbles upon this in a few years).

Here is the code that is running:

  noInterrupts();
  digitalWrite(Y, HIGH);
  P = pulseIn(X, LOW, usLong);
  digitalWrite(Y, LOW);
  a = pulseIn(X, LOW, usLong);
  digitalWrite(Y, HIGH);
  b = pulseIn(X, LOW, usLong);
  digitalWrite(Y, LOW);
  c = pulseIn(X, LOW, usLong);
  digitalWrite(Y, HIGH);
  d = pulseIn(X, LOW, usLong);
  digitalWrite(Y, LOW);

  interrupts();

Taking a look at the plot, you can see the data line is held at 3V normally, to communicate you short it to ground. A short pulse is a 1, a long pulse is a 0. You can ignore the first set of pulses, where the RED trace is held LOW. That's me sending a "power on" command to the device. It responds with a short 40 uS pulse (the first time that RED goes HIGH). As you can see, pulseIn does not immediately return after the pulse ends (BLUE goes HIGH), instead it holds for approximately another 40 uS. This causes the next pulseIn command to misfire, missing the next short pulse, but catching the first long pulse. This pattern repeats, with pulseIn not resetting for about 50 uS, missing the second long pulse.

This is of concern to me because this code worked fine with an older Arduino board and Arduino 0018. As I've mentioned before, I'm updating some "back of the napkin" hardware to something a little more robust, which required some minor code modifications (essentially inverting inputs/outputs), but now the code is failing to run properly. The big differences I can think of are I'm using an Arduino MEGA2560 and Arduino 1.0, but I can't imagine this would result in worse performance.

I'm beginning to think the proper way to do this would be to hook up my data line to an interrupt and just use the timers to figure out pulse lengths, but that would require some hardware rework since the data line is not connected to an interrupt capable pin.

sigh

On a complete whim, I decided to take Arduino 0018 for a spin, and lo and behold, pulseIn works as expected, ending as soon as the pulse ends. I'm guessing that someone has broken pulseIn, which is extra frustrating because it's not mentioned in the changelog at all. All I can see that mentions pulseIn, between 0018 and 1.0 is the following, as part of 0022:

* Applying the timeout parameter of pulseIn() during measurement of the
  pulse, not just while waiting for it.

As far as I can tell this is a bug, and a pretty bad one at that if it's causing wildly different (and undesirable!) behavior between different versions of the Arduino library. I hope it gets fixed, in the meantime, looks like I have to go write my own library, or figure out how to rip the pulseIn code from 0018 and replace it in 1.0.

Hi
lots of stuf changed in 1.0 maybe you are watching some side effect.
Have you tried version 23?
Best regards
Jantje

I started going down that path and found that 0021 appears to work. Going through the changelog now, I'm suspecting this is a bug that's not specific to pulseIn, but I'm not sure.