External Interrupt handler BUG? G120E (custom board) / SDK2016-R1

Hi,

The following code demonstrates the false execution of an external interrupt handler while the external interrupt is and remains low.
It seems that if some disk io (SD card) takes place the handler is called. The handler is called only one time after each (cold)start. However the handler is properly called on the rising edge of the external interrupt.

The code should run on a G120E


using System;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Threading;
using GHI.IO.Storage;
using GHI.Networking;
using GHI.Pins;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.IO;

public static class Program
{
    private static SDCard _sdCard;
    private static InterruptPort _powerDownInterrup;
    private static VolumeInfo _v;
    private static readonly OutputPort ScopeChannel2 = new OutputPort(G120.P1_5, false);
    private static SerialPort _s;

    private static void Rs232Write(string message)
    {
        var buffer = Encoding.UTF8.GetBytes(message);
        _s.Write(buffer, 0, buffer.Length);
        _s.WriteByte(0xA);
        _s.WriteByte(0xD);
    }

    public static void Main()
    {
        _s = new SerialPort("COM1", 115200);
        _s.Open();

        Rs232Write("Hi");

        // lets consume some power
        var nic = new EthernetBuiltIn();
        nic.Open();

        try
        {
            _sdCard = new SDCard();
            _sdCard.Mount();
            Rs232Write("SD card mounted");
        }
        catch (Exception ex)
        {
            Rs232Write("SDCard Init/Mount error : " + ex.Message);
            Thread.Sleep(Timeout.Infinite);
        }

        _v = VolumeInfo.GetVolumes()[0];

        _powerDownInterrup = new InterruptPort(G120.P2_21, false, Port.ResistorMode.PullDown,Port.InterruptMode.InterruptEdgeHigh);
        _powerDownInterrup.DisableInterrupt();
        _powerDownInterrup.OnInterrupt += powerDownInterrup_OnInterrupt;

        // Create some Disk IO threads
        var t1 = new Thread(WriteFile);
        t1.Start();

        var t2 = new Thread(WriteFile);
        t2.Start();

        var t3 = new Thread(WriteFile);
        t3.Start();

        var t4 = new Thread(WriteFile);
        t4.Start();

        var t5 = new Thread(WriteFile);
        t5.Start();

        var t6 = new Thread(WriteFile);
        t6.Start();

        _powerDownInterrup.EnableInterrupt();

        Rs232Write("Idle");
        Thread.Sleep(Timeout.Infinite);
    }

    private static void WriteFile()
    {
        var r = new Random();
        var fileName = @ "SD\T" + r.Next(1000) + ".txt";
        if (File.Exists(fileName))
            File.Delete(fileName);
        try
        {
            var buffer = Encoding.UTF8.GetBytes("Some text in file " + fileName);
            var bufLen = buffer.Length;
            using (var fs = new FileStream(fileName, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read, 512))
            {
                while (true)
                {
                    fs.Write(buffer, 0, bufLen);
                    Thread.Sleep(r.Next(200));
                }
            }
        }
        catch (Exception ex)
        {
            Rs232Write(ex.Message + " Related to file: " + fileName);
        }
    }


    private static void powerDownInterrup_OnInterrupt(uint data1, uint data2, DateTime time)
    {
        ScopeChannel2.Write(true);
        _v.FlushAll();
        ScopeChannel2.Write(false);

        Rs232Write("INTERRUPT.............");
        _powerDownInterrup.ClearInterrupt();
    }
}

How is the layout of your board in relation to P2_21 and the SD card connections? Do you have a pulldown or pullup on the P2_21 GPIO line?

P2_21 is driven by an external 8 bit micro controller (analog comparator part) I am sure he keeps the pin low all the time… :think:

@ RobvanSchelven - does the issue remain if you take out the Ethernet and RS232 parts?

@ John - Yes the issue remain without both RS232 and Ethernet

I added the following code but that did NOTchange the behaviour


_powerDownInterrup = new InterruptPort(G120.P2_21, false, Port.ResistorMode.PullDown,Port.InterruptMode.InterruptEdgeHigh);
_powerDownInterrup.DisableInterrupt();
_powerDownInterrup.ClearInterrupt();
_powerDownInterrup.OnInterrupt += powerDownInterrup_OnInterrupt;

@ RobvanSchelven - So we can try to quickly narrow down the cause, can you take as much out of your program as possible?

@ John - I could not reproduce the problem on a CobraII with minimal code :-[ … continue to search… :think:

@ RobvanSchelven - The first program you posted works fine on the G120 based Cobra II?

@ John - I only tested with minimized code on cobraII, but this minimized code on my custom board still shows the problem.

However, enabling the glitch filter on the interrupt port solved the problem , although i don’t understand yet why. to be continued…

I ran into the same problem on the same pin. I’m using the G120 not the G120E. I added an external pull up resistor with a capacitor just in case as well as setting internal pull up resistor of the chip. The problem seem to be a bit more stable… however, it still fired false interrupt once in a while. If an actual interrupt happened, it will fired multiple times… I’m using a Reed switch to connect to the external interrupt pin.

I hope it’s not a bug, but I’ve tried everything… the code I have works without a problem on the Fez Cerb 40.

Cheers,

@ hunghp - interesting observation… I also use a G120 but added the ethernet PHYTER which makes it more or less compatible with the G120E

Its worth to try another port/pin…to be continued…

The glitch filtering would indicate a possible noise issue.

How well is the board decoupled, especially around that external microcontroller?

@ Dave McLaughlin - I agree with you. The whole board is pretty well decoupled and i can assume but not proof yet that the noise is a result of SD card write actions (power consumption). In the interrupt handler i write to a port to generate a pulse for the oscilloscope. The other scope channel is used to monitor the interrupt line… The fact is that i can’t see any pulse or nSec spike on the interrupt line… Even i can’t trigger on the interrupt line, the scope doesn’t see anything to trigger on. to be continued…

Probably of no help but I thought I would mention something I have seen on button presses.

I have a G120E Dev board and I am having a terrible time with multiple events when a button is pressed.
I put in a debug message(“Button X pressed”); and I have noticed that sometimes the interrupts count up.

Lets say I press the button and I get two “Button X pressed” messages. I press the button again and I receive 3 or four messages, press again
I may get an increase count of messages. The most I have seen is 8.

It seems like the events are queuing up?

Interrup.Disable and Interrup.Clear in the button event do not seem to help.

For what it’s worth…

@ willgeorge - Thanks for sharing… WIth a button i can imagine that its because of contact bounce. A low pass filter (simpel R/C) on the input would help i guess.

I have been testing whole day now related to this interrupt issue and discovered that an interrupt is sometimes not triggered… Which in my case is a worse condition because the interrupt indicates an early warning for a power down cycle

@ willgeorge, I agree with you, yes I see that too, I sometimes get 2 interrupt for one push, I use a reed switch which is just like a button that closes with a magnet. This problem can be solve much easier if the Clear Interrupt function works as it should, I would assume the clear interrupt would immediately clear/de-registered any interrupts so far.

@ hunghp - It should also be possible to implement a “filter” in software, in the interrupt handler… test the time between 2 interrupts and if less then xx mSec ignore the second… something like that… :think:

@ RobvanSchelven, I have ignore all interrupt requests except the first one, but still doesn’t work. I believe ClearInterrupt() method is odd as you can see the code I have below.
I only accept the first interrupt request and ignore whatever come in next until I have finished sending/processing my task.


 static void _send_package_interrupt_OnInterrupt(uint data1, uint data2, DateTime time)
        {            
            if (SpecialGlobalVar._TCPTransmissionInProcess == true)  //Transmission in process
            {
               //ignore this interrupt request and clear the interrupt
                _send_package_interrupt.ClearInterrupt();
                return;
            }
                                   
            //Set flag to true so anymore interrupts comes in will be ignore
            SpecialGlobalVar._TCPTransmissionInProcess = true;
          
            //Trasmit one complete data package through TCP/IP
            TransmitDeviceDataPackage();
                      
            //Transmit complete, reset flag to false so we can again process interrupt
            SpecialGlobalVar._TCPTransmissionInProcess = false;

           //Clear the interrupt     
            _send_package_interrupt.ClearInterrupt();            
        }

@ hunghp - Yes, you are right, ClearIinterrupt() does not seem to do anything :frowning:

Be careful by changing variables in the interrupt routine… Interrupt handlers in managed code are deferred interrupt handlers. I am not sure if write/reads on a variable can overlap. I am using the following construct to make sure the int. handler is completely finished before the next could modify or interfere.


int _readyFlag;
private void InterruptHandler(uint data1, uint data2, DateTime time)
{
    if (Interlocked.CompareExchange(ref _readyFlag, 0, 1) == 1)
        return;

    // Handler code...

    Interlocked.Decrement(ref _readyFlag);
     ....ClearInterrupt(); // Although this call does not seems to do anything :(
}

@ RobvanSchelven, thank you, I’ll give it a try. Hmm… good to know that interrupt handlers in managed code are deferred interrupt.