Cerberus Interrupt

I tried to mesure the time between the rising and falling edge of a signal.
I used an Extender at socket 3 / Pin 3 and did the following initialisation:

           _trigger= extender.CreateDigitalOutput(GT.Socket.Pin.Nine, false);

           _interrupt = extender.CreateInterruptInput(GT.Socket.Pin.Three, GT.SocketInterfaces.GlitchFilterMode.On, GT.SocketInterfaces.ResistorMode.PullDown, GT.SocketInterfaces.InterruptMode.RisingAndFallingEdge);

           _interrupt.Interrupt += _interrupt_Interrupt;

The Interrupt - service routine is the follwing:

       public static bool _firstEdge = true;

        void _interrupt_Interrupt(GT.SocketInterfaces.InterruptInput sender, bool value)
        {
            //Debug.Print(value.ToString());
            if (_firstEdge)
            {
                _start = DateTime.Now;
                _firstEdge = false;
            }
            else
            {
                _stop = DateTime.Now;
                _diffTime = _stop - _start;
                _showTime = _diffTime.Ticks;
                _firstEdge = true;
            }
        }

The var _showtime is displayed on a HD4470 display in a separate timer-event.
I found out that the minimum time between 2 interrupts is a little less than 50ms.
Is that true?
If yes: Is there a possibility the measure shorter time?
Thanks in advance

Format your code. There is a button for it (101010).

Try your code with disabled GlitchFilterMode .

Thank you, this works much better.
Sorry for the code-formatting.

In the m micro framework interrupts are queued. To determine the time of the interrupt you can not use the system clock. The native interrupt handler is passed the actual time of the interrupt. If you want accurate timings, you will have to use the native interrupt handler.

Do you have an example how to do this?
Thanks in advance!

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System;    
using System.Threading;



public class Program
{
    public static void Main()
    {
        InterruptPort IntButton = new InterruptPort(Cpu.Pin.GPIO_Pin1, false,
                                                    Port.ResistorMode.PullUp,
                                                    Port.InterruptMode.InterruptEdgeLow);

        IntButton.OnInterrupt += new NativeEventHandler(IntButton_OnInterrupt);
      
         // Other code can be added here
         // ...
         // We are just going to sleep in this example!
        Thread.Sleep(Timeout.Infinite);
    }

    static void IntButton_OnInterrupt(uint port, uint state, DateTime time)
    {
        Debug.Print("Button Pressed");
    }
}

Ok, I wrote the following program to use a HC-SR04 distance sensor like the one from GHI.
I wanted to measure the length of the pulse which comes as response after triggering the Sensor.
The Code I added works for several minutes and then the Display hangs as well as the Interrupt code.
The fallback timer keeps triggering every 10s and the sensor answers via the Echo - Pin.
I connected the Sensor with a breakout module on Socket X3 of the Cerberus.
The trigger is on Pin 9 the Echo goes to Pin 3 which is configured as an Interrupt - pin.
Please help…

Thanks in advance!


using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

//using Gadgeteer.Networking;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;

using Microsoft.SPOT.Hardware;
using Gadgeteer.Modules.GHIElectronics;


namespace Interrupt_02
{
    public partial class Program
    {

        public static GT.SocketInterfaces.DigitalOutput _trigger;
        public GT.Timer triggerTimer;

        void ProgramStarted()
        {
            Debug.Print("Program Started");
            long _test = TimeSpan.TicksPerMillisecond;
            Debug.Print(_test.ToString());

            triggerTimer = new GT.Timer(10000);

            characterDisplay.Clear();

            _trigger = extender.CreateDigitalOutput(GT.Socket.Pin.Nine, false);

            Cpu.Pin _myPin = GHI.Pins.Generic.GetPin('C', 0);
            InterruptPort IntPort = new InterruptPort(_myPin, false, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeBoth);
            IntPort.OnInterrupt += new NativeEventHandler(IntPort_OnInterrupt);

            triggerTimer.Tick += triggerTimer_Tick;
            triggerTimer.Start();

            GT.Timer dispTimer = new GT.Timer(1000);
            dispTimer.Tick += dispTimer_Tick;
            dispTimer.Start();
            _firstEdge = 0;
            _trigger.Write(false);
            Thread.Sleep(1);
            _trigger.Write(true);
            Thread.Sleep(1);
            _trigger.Write(false);

        }

        void dispTimer_Tick(GT.Timer timer)
        {
            characterDisplay.Clear();
            characterDisplay.CursorHome();
            characterDisplay.SetCursorPosition(0, 0);
            characterDisplay.Print(_showTime.ToString() + " Ticks    ");
            characterDisplay.SetCursorPosition(1, 0);
            double _distance = _showTime / (TimeSpan.TicksPerMillisecond / 1000.0) / 58.0;
            int _iDistance = (int)_distance * 100;
            _distance = _iDistance / 100.0;
            characterDisplay.Print(_distance.ToString() + " cm    ");
        }

        public static DateTime _start, _stop;
        public static TimeSpan _diffTime;
        public static long _showTime;
        public static int _firstEdge = 0;


        static void IntPort_OnInterrupt(uint port, uint state, DateTime time)
        {
            if (_firstEdge == 0)
            {
                _start = time;
                _firstEdge = 1;
            }
            else if (_firstEdge == 1)
            {
                _stop = time;
                _diffTime = _stop - _start;
                _showTime = _diffTime.Ticks;
                Thread.Sleep(400);
                _firstEdge = 0;
                _trigger.Write(false);
                Thread.Sleep(1);
                _trigger.Write(true);
                Thread.Sleep(1);
                _trigger.Write(false);
            }
        }

        // Trigger if selftrigger fails
        void triggerTimer_Tick(GT.Timer timer)
        {
            _firstEdge = 0;
            _trigger.Write(false);
            Thread.Sleep(1);
            _trigger.Write(true);
            Thread.Sleep(1);
            _trigger.Write(false);
        }
    }

}

@ mflume - It looks like you’re sleeping for close to half a second in the interrupt handler. That isn’t a good idea since events are queued in NETMF. Try to rework your program so that you do not remain in the interrupt/tick handlers for more than a few milliseconds and see if the issue remains.

@ John - This should be no problem as the distance sensor only fires two egdes after triggering and the thread.sleep comes after the second interrupt.
So there no further interrupt should be queued.
The problem seems to be, that from time to time one interrupt is dropped.
I try to rewrite the code without the sleep and post it later.

I found a solution which works o.k. most of the time.
I connected the HC-SR04 distance sensor like the one from GHI at socket X2 this time but it works at socket X3 the same way.
The trigger is on Pin 9 the Echo goes to Pin 3 which is configured as an Interrupt - pin.
As I said before, the interrupt gets lost from time to time.
In this case I do a retrigger, or in worst case a reboot by the watchdog but this seems to be not necessary in this state of the program as it runs since quite a while without reboot now.
The biggest problem now is that on long distances (above 3m) I get false values but this maybe come from the sensor.
If anybody has further improvements I would be thankful.

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;

using Microsoft.SPOT.Hardware;
using Gadgeteer.Modules.GHIElectronics;
using GHI.Processor;


namespace HC_SR04_Int_01
{
    public partial class Program
    {

        public static GT.SocketInterfaces.DigitalOutput _trigger;
        public static GT.Timer triggerTimer;

        public InterruptPort IntPort;

        void ProgramStarted()
        {
            Debug.Print("Program Started");
            long _test = TimeSpan.TicksPerMillisecond;
            Debug.Print(_test.ToString());

            characterDisplay.Clear();

            _trigger = extender.CreateDigitalOutput(GT.Socket.Pin.Nine, false);

            triggerTimer = new GT.Timer(500);
            triggerTimer.Tick += triggerTimer_Tick;
            Cpu.Pin _myPin = GHI.Pins.Generic.GetPin('A', 6);
            IntPort = new InterruptPort(_myPin, false, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeBoth);
            IntPort.OnInterrupt += new NativeEventHandler(IntPort_OnInterrupt);

            Mainboard.SetDebugLED(false);

            triggerTimer.Start(); // Fire the first trigger signal
            GHI.Processor.Watchdog.Enable(5000); // if nothing else helps....
        }

        // Display the results of measuring and hide trash values
        void showResults()
        {
            // Error!
            if (_showTime < 3000)
            {
                Mainboard.SetDebugLED(true);
                //Debug.Print(_distance.ToString() + ":" + _showTime.ToString());
            }
            else
            {
                double _distance = _showTime / (TimeSpan.TicksPerMillisecond / 1000.0) / 58.0;
                ulong _iDistance = (ulong)_distance * 100;
                _distance = _iDistance / 100.0;
                characterDisplay.SetCursorPosition(0, 0);
                characterDisplay.Print(_showTime.ToString() + " Ticks         ");
                characterDisplay.SetCursorPosition(1, 0);
                characterDisplay.Print(_distance.ToString() + " cm            ");
            }
        }

        public static DateTime _start, _stop;
        public static TimeSpan _diffTime = new TimeSpan();
        public static ulong _showTime;

        // Trigger the sensor then Stop
        void triggerTimer_Tick(GT.Timer timer)
        {
            triggerTimer.Stop();
            showResults();
            GHI.Processor.Watchdog.ResetCounter();// Watchdog Reset
            Mainboard.SetDebugLED(false);
            _trigger.Write(false);
            //Thread.Sleep(1);
            // Wait ~0.3 ms
            for (int i = 0; i < 10; i++)
            {
                _trigger.Write(true);
            }
            _trigger.Write(false);
        }

        public static uint _lastState = 1;

        static void IntPort_OnInterrupt(uint port, uint state, DateTime time)
        {
            // This occurs if one interrupt is dropped
            if (state == _lastState)
            {
                state = 2; // Prepare Retry
            }
            else
            {
                _lastState = state;  // Ok!
            }
            //Debug.Print(port.ToString() + ":" + state.ToString());
            if (state == 1)  // First edge
            {
                _start = time;
            }
            else if (state == 0)  // Second edge
            {
                _stop = time;
                _diffTime = _stop - _start;
                _showTime = (ulong) _diffTime.Ticks;
                // Prepare next trigger
                triggerTimer.Start(); 
            }
            else // Retry!
            {
                Debug.Print("Error!");
                Mainboard.SetDebugLED(true);
                _trigger.Write(false);
                Thread.Sleep(1);
                _trigger.Write(true);
                Thread.Sleep(1);
                _trigger.Write(false);
            }
        }
    }
}

I think I’ll make a snippet from this, if I get no more suggestions.

P.S.: Thanks for all the help I got!