Curious about interrupt handling

Hi,

I’m monkeying about with some standard Alps encoders. These are a lot more difficult than maybe a standard sensor should be and could be usefully use a well debugged class in the GHIElectronics codebase. They generate a waveform like the attached image. One thing I’ve noticed about the interrupts is that they often seem to be missed. That is, when I’m supposed to be receiving both up and down edges, why do I sometimes receive on the same pin an up edge followed by another up edge without a down edge in between? Was it lost by the Domino? Do I not process the preceeding one fast enough?

Here’s some debug output from the code below when everything goes well:

B Down 48.746 0ms
A Down 48.763 16ms
B Up 48.770 23ms
A Up 48.790 43ms

  • which is what I expect. But often enough I get this kind of thing:

B Down 39.176 0ms
B Up 39.176 0ms
(B Up 39.176 0ms)
A Down 39.191 15ms
(B Up 39.203 27ms)
(B Up 39.203 27ms)
A Up 39.219 43ms

I can understand that I have glitches to deal with, either in software or hardware, but why do I get the repeated ‘B Up’ interrupts for instance without Down edges in between?

Regards,

Alan

public Encoder(Finger thisFinger, FEZ_Pin.Interrupt thisPinA, FEZ_Pin.Interrupt thisPinB)
{


a = new InterruptPort((Cpu.Pin)thisPinA, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
b = new InterruptPort((Cpu.Pin)thisPinB, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
a.OnInterrupt += new NativeEventHandler(HandleEdge);
b.OnInterrupt += new NativeEventHandler(HandleEdge);

  lastStateA = a.Read() == true ? 1u : 0u;
  lastStateB = b.Read() == true ? 1u : 0u;

  lastInterrupt = startTime = DateTime.Now;
}

void HandleEdge(uint port, uint state, DateTime time)
{
  lock (this)
  {
    // space out a new movement (within 0.5s) for readability
    long msFromLast = (time - lastInterrupt).Ticks / TimeSpan.TicksPerMillisecond;
    if (msFromLast >= 500)
    {
      startTime = time;
      Debug.Print("");
    }
    lastInterrupt = time;

    long msFromStart = (time - startTime).Ticks / TimeSpan.TicksPerMillisecond;

    // if it is the same state, ignore it because it's giving us no new information except the time
    if ((port == pinA && state == lastStateA) || (port == pinB && state == lastStateB))
    {
      Debug.Print("  (" + (port == pinA ? "A" : "B") + " " + (state == 1 ? "Up" : "Down") + " " + time.Second + "." + time.Millisecond + " " + msFromStart+"ms)");
      return;
    }
    else
    {
      Debug.Print((port == pinA ? "A" : "B") + " " + (state == 1 ? "Up" : "Down") + " " + time.Second + "." + time.Millisecond + " " + msFromStart+"ms");
    }

Please use code tags.

There is known issue I think. In your interrupt, read the pin status and ignore the pased argument. Better?

Hi,

Thanks for your response Gus and ah yes, I see now re code tags. To save everyone else some time and after reviewing the forum discussion, I think I now understand the following, even for slowish interrupts:

(a) There seems to be a known problem with InterruptEdgeBoth missing edges.
(b) Glitch processing apparently doesn’t apply to InterruptEdgeBoth.
(c) As you see from the debug below (corresponding to the scope trace attached) there are sometimes not only missing edges but repeated edge interrupts. I don’t think they’re solely due to waveform glitches.
(d) The delay between the timestamp made by the (real) ISR and receipt by the C# event can be anywhere between 0 and 80ms or so.
(e) The ISR timestamps are fairly accurate - by eyeball at least they look close to a ms accuracy compared with the scope trace. They’re maybe even better if I looked at the data more closely.
(f) InterruptEdgeLevelHigh/Low are not supported.

read the pin status and ignore the pased argument

I did try that but as the read happens anything up to 80ms after the edge, the status has usually changed. I was thinking about tidying up the waveform a bit in hardware. I’m also looking at specialised encoder handling chips and using a PICAXE running a fast poll with a state machine. Ehhh, a lot more complicated than I imagined for a dumbish sensor running slowly.

Alan

B Up 45.770 elapsed 0ms delta 10047ms receipt delay 0ms
A Down 45.789 elapsed 18ms delta 18ms receipt delay 3ms
A Up 45.789 elapsed 19ms delta 0ms receipt delay 20ms
A Up 45.789 elapsed 19ms delta 0ms receipt delay 38ms
A Up 45.789 elapsed 19ms delta 0ms receipt delay 55ms
A Down 45.789 elapsed 19ms delta 0ms receipt delay 72ms
B Up 45.811 elapsed 41ms delta 21ms receipt delay 68ms
A Up 45.848 elapsed 77ms delta 36ms receipt delay 49ms
A Up 45.848 elapsed 78ms delta 0ms receipt delay 66ms
A Up 45.848 elapsed 78ms delta 0ms receipt delay 83ms

BTW I forgot to say those results were with a 10ms loop in the main thread, although I have to say, the C# event receipt delay doesn’t seem to change much when I suspend the main thread completely. This is on an oldish Domino running:

ClrInfo.targetFrameworkVersion: 4.1.2821.0
SolutionReleaseInfo.solutionVersion: 4.1.8.0

Also, for anyone doing this kind of thing in the future: one idea I had was that I should process the C# event fairly quickly, like you would in an ISR, and I simply processed them by putting them on a (C#) Queue and then pumped the queue from the main loop. It dawned on me that the events have already been queued from the real ISR to a C# event queue so there’s no real need to process the event quickly. Obviously if you process the events in aggregate slower than they come in, eventually you will run out of memory, but in my case I’m only expecting little bursts of 4 to 12 events every second or so. What I did find out, of course, is that the Queue object is fairly heavyweight and you can run out of memory quite quickly if you don’t pump fast enough.

Alan

Gus, do you think there could be bugs in the interrupt code re edge direction and/or repeated edge detections and/or missed edges? The last two might be waveform glitches but the waveform actually looks quite clean to me. I see that the times reported in the debug look accurate re the scope but everything else is a bit odd. I’ll try some Schmitt triggers and see what difference that makes.

Alan

Not sure, but netmf does a lot of work to get the interrupt to transfer an event up to the system so high speed handling is not ideal.