Fast Interrupts on SCM20260D

I’m testing the response of the interrupts on the board.
We have really aggressive requirements in our products, it requires that interrupts should be server on less than 1ms and the delay between the interrupt signal and the service routing should be minimal and not moving too much.

To accomplish this we use a G120 with RLP code and the whole process takes less than 800 microseconds and is very stable.

We set up a simple test in the new development SCM20260D board installing an interrupt in one pin and toggling twice a second pin then exit the routine. This is without using RLP.

using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Pins;
using System.Threading;
    
namespace Test
{
    class Program
    {
        private static GpioController gpioController;
    
        private static GpioPin isrPin;
        private static GpioPin busyPin;
    
        static void Main()
        {
            gpioController = GpioController.GetDefault();
    
            isrPin = gpioController.OpenPin(SC20260.GpioPin.PJ0);
            isrPin.ValueChanged += IsrPin_ValueChanged;
            isrPin.ValueChangedEdge = GpioPinEdge.RisingEdge;
            isrPin.SetDriveMode(GpioPinDriveMode.InputPullDown);
    
            busyPin = gpioController.OpenPin(SC20260.GpioPin.PJ1);
            busyPin.SetDriveMode(GpioPinDriveMode.Output);
            busyPin.Write(GpioPinValue.Low);

            //Use "SC20100.GpioPin.PB0" on SC20100 Dev Board.
            //Use "SC20260.GpioPin.PH6" on SC20260D Dev Board.
            var LED = gpioController.OpenPin(SC20260.GpioPin.PH6);
            LED.SetDriveMode(GpioPinDriveMode.Output);

            while (true)
            {
                LED.Write(GpioPinValue.High);
                Thread.Sleep(200);

                LED.Write(GpioPinValue.Low);
                Thread.Sleep(400);
            }
        }

        private static void IsrPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
        {
            busyPin.Write(GpioPinValue.High);
            busyPin.Write(GpioPinValue.Low);
            busyPin.Write(GpioPinValue.High);
            busyPin.Write(GpioPinValue.Low);
        }
    }
}

We started with 100 Hz (we need at least 1KHz) and we notice that the interrupt is missed or served in the wrong edge of the trigger signal. Also, the interrupt is served after ~1 ms (minimum).

Yellow is the trigger signal.
Here is an example of a good serviced trigger (you can see the next is missing):

Another example of missed on the rising edge (but triggered on the falling?):

Another example of one missed completely:

We bring the frequency down to 50 Hz and started to show a pattern, 1 trigger is served properly then next is on the wrong edge and the next is missed, here is the screenshot with another analyzer that can capture longer (bottom signal is the trigger signal):

Questions:
Are there any errors in my interrupt setup (something that I’m missing)?
Why is there a minimum of 1 ms to respond?
Any idea why are missing pulses?
Is there any other technique that we can apply to fast service interrupts like RLP (this is the core of our product)?

It almost looks like there is a glitch filter or something playing with response time or the edge.

I can’t comment on anything - but I want to ask, what product(s) are you currently achieving your desired outcomes with? Netmf and a GHI product? Edit: I see, RLP and G120.

So why did you revert to RLP in the first place?

And do you think that there’s a major change from the non-deterministic approach in netmf with TinyCLR OS?

@Brett RLP is not supposed to be accessible anymore in the TinyCLR 2.0 and given that this is a replacement module for G120, we should make sure that we can achieve the same results.

@Gus_Issa suggested that they have an improved thread management on TinyCLR 2.0 that should give better results handling interrupt service routines but it is not profiled yet.
On top of that, a better microcontroller may have an impact on the ISR response and task scheduling but it may need some tweaking on the timings.

We have another application that is more demanding and I was hoping to use this microcontroller as well, it is to process some camera link data (behind a ChannelLink LVDS to parallel chip) but it feels like without low level code access will be out of reach.

Love seeing that because this is an important test. Before you go any further, we have just finished some changes that makes your board 3 times faster!! We are looking into releasing it quickly.

@Gus_Issa I’m looking forward to testing it, is there anything that you can comment on the current code regarding the missing pulses and edge response?
Is there anything that I can try or tweak?

yeah but the software is completely different, as is the hardware. You’re in “special cases” territory I’d suggest (but you know that :wink: ). The whole thing with RLP was that it was to avoid the managed overhead. It’s great to try to push the boundaries, and test whether things are capable, but I’d not seen any indication that things would be magnitudes different. I guess I was more surprised that you expected this to “just work”, but great to have an active test harness that might assist GHI in further optimisations that will help everyone

I hope that we can find a workaround, I don’t expect the same result as RLP but a little closer is not a big deal given the improvement in the hardware and the software over the G120 and NetMF.
I wish that I can have everything in the managed side, it would be ideal since most of the logic is there.

@Gus_Issa quick update:

I try today to set the DebounceTimeout = TimeSpan.Zero

The behavior got better with no missing pulses, but each interrupt is there twice.
Somehow is fired twice.

On the other side, do you think that it is doable to decrease the response time at least a half?
It is around 1.1 ms now.
Any other idea to work around this (not using RLP)?

@Dat_Tran please check that timeout zero doesn’t cause double interrupts… If it does, can we have it fixed in this release this week?

I will take a look

Looking forward to your comments @Dat_Tran

Sometime this week, but not today.

No rush at all.

As promised, come back with you by this week.

I used your example, just added PA15 as PWM 1KHz, duty 0.5 as source to trigger interrupt.
Set DebouceTime to 0.

Likely everything work correctly in my case.

You saw interrupt twice maybe bcause you raised the busyPin twice in your code. The first time I looked at scop I also saw twice. So just need to correct the code below.

private static void IsrPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
        {
            busyPin.Write(GpioPinValue.High);
            busyPin.Write(GpioPinValue.Low);
            // busyPin.Write(GpioPinValue.High);
            // busyPin.Write(GpioPinValue.Low);
        }

Also, I tried at 1KHz as your project expected, just fine.

1 Like

Just a note, I tried on new firmware v2.0.0.21000, which has been released out today. Not need RLP if 1KHz. But it depends on what you do on interrupt event. For now it is likely simple.

did is possible to test this code and to show at SCOPE
what movement cause this code :slight_smile:

this delays (it is less than 1 milliseconds fromThread.Sleep(1)) on managed code (but i can not figure how many microsecond is (in TinyCLR 1.0 it was about 400 - 500 microseconds on Nucleo F411) but no less than it.

Maybe on new platform faster …


using System;
using GHIElectronics.TinyCLR.Native;
using GHIElectronics.TinyCLR.Devices.Gpio;

namespace TinyMicrosecondsDelays
{
    class Program
    {
        static GpioPin myPin;
        static void Main()
        {
            myPin = GpioController.GetDefault().OpenPin(15); //PA15

            for(int i=0;i<=100;i++)
            {
                myPin.Write(GpioPinValue.High);
                WaitMicroseconds(10);
                myPin.Write(GpioPinValue.Low);
            }
        }
        
        static double ticksPerMicrosec = 10; 
        public static void WaitMicroseconds(double microseconds)
        {
            long ticks = SystemTime.GetTime().Ticks;
            while ((SystemTime.GetTime().Ticks - ticks) <= (microseconds * ticksPerMicrosec)) ;
        }
    }
}

Not sure this is a good test because the results will vary with the tiniest changes. And it is certainly not a speed test at you are only measuring a specific method speed, not the overall system.

That said, I am curious to see the results like you.

it is 60us instead of 10us

1 Like

perfect - 10 time faster on managed code as is - so we can catch 70 - 100 microseconds timing with this kind of delays.

what device do you compare to?