Pin Capture vs Interrupt on Panda II

Hello all,
I have a problem with my Panda II board: when capturing a pin I get for a signal regular changes of state (~ 4 per 1.5 secs). The timing remains constant within ±1 ms.

Now I am trying to do the same, using the same pin with an interrupt handler.

Barrier = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di3, false, 
            Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
Barrier.OnInterrupt += new NativeEventHandler(Barrier_Capture);

Using the interrupt I get roughly every 8 ms an interrupt with no state change of the line. Why?
Tested this on Di0 and Di3. Do I need to use another pin for it? 3-4 changes per sec should not be a problem, I guess. I just want to have a precise time code of the change time.

SteH

Search here for previous threads on interrupt edge detection, InterruptEdgeBoth I don’t think works as you think (ie it doesnt).

All I found is that a glitch filter does not work with (both) edge detection. That general edge detection does not work, I have found no entry. But I will continue to search

I suspect this may be a limitation - I’ve not seen a failsafe way to achieve what you want, and the threads on this don’t really seem to have concluded with anything worthwhile.

If you think the timing is always close/repeatable, perhaps there’s something GHI can look at. Do you have a short sharp repro program that they can use to test this? What is your input source as well, for your end application?

Try connected to a different interrupt pin if you can. I got very different behavior on Di3 to Di13 for instance - Di3 seemed “inverted” to what Di13 was (this was with a simple test program and a simple magnetic reed switch). Either way I couldn’t get the “State” in the event handler to represent a correct state transition; I pretty much always got a 1 returned in that even when I moved the magnet away from the reed switch)

This is the read-out of a photoelectric sensor. With the light path interrupted I don’t get extra interrupts, whereas with light passing I get them.

The sensor is occluded by a pendulum swinging through the light path. I want to measure the swinging period of the pendulum. So the signal is - beside friction - constant. Within a minute - using pinCapture - I get a deviation of less than 4 ms for a 1.5 s period.

Is it worth to test all digital pins? Then I have to switch back to the bread board to be able to switch without soldering. Perhaps I will try it during the week and report back.

Is it a state change every about 200ms or it is a pulse and how wide is the pulse?

No, the time of each pulse is not 200 ms. It is originating from a pendulum swinging through a photoelectric sensor. One pulse is about 450 ms, with 30 - 100 ms in between pulses, depending on the actual definition of a pulse. I am now not exactly sure when the FEZ pin is high, during the crossing or during the “free” swing.

Will check at home also whether it the 5V tolerance is not true for the low value: There is a logic buffer between the sensor and the FEZ pin with 5V supply. I will try to change the supply of this buffer to 3.3 V and check the low voltage on the pin.
Checked that: low is 5 mV, high is ~4.5 V

Also checked on Di5: the same problem that the interrupt handler is called every ~ 6.5 ms during the swing period of 450 ms. Using PinCapture I get 4 state changes per period:

found on MSDN that the default time span for the glitch filter is 7.68 ms. My re-occuring interrupts come every 6-8 ms.
May I use a button interrupt handler with glitch filtering (EdgeLow) and an interrupt for the photoelectric sensor without glitch filter (EdgeBoth)? Or will the glitch filtering hooked to all interrupt handlers? Looks close to what I see, as the interrupts come only for one state with a similar time.

Anyhow I will test it tonight or tomorrow if a changed Timespan for the glitch filter changes also the time span of the additional interrupts.

There’s only one (universal) glitch filter setting.

My question is more if this settings is applied to all interrupt pins, even if I construct them with glitch filter disabled:


            InterruptPort Button2 = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di2 , true,
            Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            // Add a button event
            Button2.OnInterrupt += new NativeEventHandler(Button_Stop);

            LightBarrier = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di5, false, 
            Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
            LightBarrier.OnInterrupt += new NativeEventHandler(Barrier_Capture);

should have no filtering for the LightBarrier. But I get this additional interrupts also when disabling the filter for the button(s).

No, the glitch filter wouldn’t be applied to LightBarrier. But…“additional interrupts” are exactly what the glitch filter prevents. Try turning it on and they will go away.

But where do the additional interrupts (or interrupt handler calls) originate? When using pin capture I get state changes every 50/450/50/450 ms. Using interrupt handling one state remains whereas in the other state the handler gets called every 6-8 ms. As the pin capture returns the expected timing I assume that the hardware is OK and there is some software problem. The frequency the handler gets called is very close to the default value of the glitch filter timing.

Disabling the glitch filter also for the buttons did not change anything.

I will try with the newest firmware and will post the entire code later today or in the weekend

You can add an RC filter (hardware filter) to help out.

You don’t have to use the same handler for both ports. Try creating two different handlers. Maybe there’s something here that will help you.

http://blog.ianlee.info/2011/08/using-external-button-led-with-netmf.html


    public class Program
    {
        static long[] bufferl = new long[102];
        static uint[] buffers = new uint[102];
        static bool[] bufferr = new bool[102];
        static long firstTick = -1L;
        static long tt1;
        static int edges = 0;
        static bool measure = false;
        static InterruptPort LightBarrier;

        static OutputPort LED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di6, false);
        
        static uint lognum = 0;
        static uint count = 0;
        static bool bStop = false;
        static string rootDirectory;
        
        public static void Main()
        {
            InterruptPort Button = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di1, false,
            Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            Button.OnInterrupt += new NativeEventHandler(Button_OnInterrupt);

            InterruptPort Button2 = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di2 , false,
            Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            Button2.OnInterrupt += new NativeEventHandler(Button_Stop);

            LightBarrier = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di5, false, 
            Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
            LightBarrier.OnInterrupt += new NativeEventHandler(Barrier_Capture);
            LightBarrier.DisableInterrupt();
            uint LastDisp = 0;
            uint i;
            while(!bStop)
            {
                Thread.Sleep(100);
                if (measure)
                {
                    if (edges > LastDisp)
                    {
                        for (i = LastDisp + 1; i < edges; i++)
                        {
                            Debug.Print("List "+ i + ": " + buffers[i] + " - " + bufferr[i] + " - " + bufferl[i]);
                        }
                        LastDisp = i;
                    }
                    else if (edges == 0)
                    {
                        for (i = LastDisp + 1; i < 100; i++)
                        {
                            Debug.Print("List " + i + ": " + buffers[i] + " - " + bufferr[i] + " - " + bufferl[i]);
                        }
                        LastDisp = i;
                    }

                }
            }
            Debug.Print("Start disposing variables");
            LightBarrier.DisableInterrupt();
            LightBarrier.Dispose();
            Button.DisableInterrupt();
            Button.Dispose();
            Button2.DisableInterrupt();
            Button2.Dispose();
        }

        static void Button_Stop(uint data1, uint data2, DateTime time)
        {
            Debug.Print("Stopping...");
            bStop = true;
        }


        static void Barrier_Capture(uint data1, uint data2, DateTime time)
        {
            if (firstTick == -1L)
            {
                firstTick = time.Ticks;
            }
            long dtime = time.Ticks - firstTick;
            buffers[edges] = data2;
            bufferl[edges] = dtime;
            bufferr[edges] = LightBarrier.Read();
            edges++;
            if (edges >= 100)
            {
                LightBarrier.DisableInterrupt();
                edges = 0;
                measure = false;
                LED.Write(measure);
                Debug.Print("ending measure");
            }
            double msec = dtime / 10000.0;
            Debug.Print(edges-1 + ": " + msec.ToString()+" - " + data2.ToString() + " - " + data1.ToString());
        }
        
        static void Button_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            if ((tt1 != -1L) && (time.Ticks - tt1 < 2000000L))
                return;         // return if last interrupt is less than 20 ms apart
            if (measure)
            {
                LightBarrier.DisableInterrupt();
                measure = false;
                LED.Write(measure);
                Debug.Print("... end Capturing");
                tt1 = -1L;
            }
            else
            {
                tt1 = time.Ticks;
                measure = true;
                LED.Write(measure);
                Debug.Print("Capturing...");
                firstTick = -1L;
                LightBarrier.EnableInterrupt();
            }
        }
    }
}


Won’t an RC filter cause a problem before a digital input? As the capacitor charges, its voltage would pass through the forbidden band between a one and a zero at too slow of a rate. ???

I don’t see that you’re setting the Cpu.GlitchFilterTime anywhere. I’ve found the default value to be too small for use with push buttons. Try playing with higher values.

Cpu.GlitchFilterTime = new TimeSpan(TimeSpan.TicksPerSecond / 2); 

Of course, the problem being that you may need more responsiveness from LightBarrier depending on your application.

@ Mike

You can add a buffer after the RC filter to take care of the rise time. But this is not my problem.

@ ianlee74

As the glitch filter is disabled in all constructors I don’t see why it should make a difference what value the glitch filter timespan has.


InterruptPort Button = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
 
InterruptPort Button2 = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di2 , false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
 
LightBarrier = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di5, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);

But …

I now added the adaption of the GlitchFilterTime as promised


            Cpu.GlitchFilterTime = new TimeSpan(1000000L);

As the filter is disabled for all InterruptPin’s I would not expect any difference, but the difference is that I now get two calls on one edge and one on the other. This seems to be (acceptable) managable.

Sorry, I was implying that you also enable the glitch filter. Not sure why you’re seeing a difference now… :o If you enable the glitch filter (with an appropriate GlitchFilterTime) you should be able to get that down to just one event/interrupt being fired most of the time.