Main Site Documentation

[SOLVED] PWM Interfering with Interrupts - Is this a bug?


#1

I’m using this code here for a rotary encoder knob. On it’s own it seems to work pretty well and it gives me the results I expect without fail: https://www.ghielectronics.com/community/forum/topic?id=15231 (code towards bottom)

I started to add features to my device (Cerb 40 II) and the rotary encoder started to act up. I was able to narrow it down to PWM. By commenting out the 5 PWM lines, the problem goes away. In particular, the values are all wrong and it fires 16ish times the amount of interrupts :open_mouth: . The encoder is hardware debounced and I get a clean output.

Is there something I’m doing wrong?

Here’s the simplified code I’m using to reproduce the case:


using GHI.Hardware;
using GHI.Hardware.FEZCerb;

namespace PWMInterruptBugTest
{
    public class Program
    {
        static InterruptPort PinA; 
        static InterruptPort PinB;
        static InterruptPort RotaryButton;
        static int InterruptCountA;
        static int InterruptCountB;

        public static void Main()
        {
            InterruptCountA = 0;
            InterruptCountB = 0;


            PinA = new InterruptPort(Pin.PC10, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);//Pins are pulled high.
            PinB = new InterruptPort(Pin.PA14, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);//Interrupt Needed here.
            


            PinA.OnInterrupt +=PinA_OnInterrupt; 
            PinB.OnInterrupt +=PinB_OnInterrupt; 

            RotaryButton = new InterruptPort(Pin.PC11, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
            RotaryButton.OnInterrupt += RotaryButton_OnInterrupt;

            PWM PWMPin;

            
            PWMPin = new PWM(Cpu.PWMChannel.PWM_7, 100000, .5, false);
            PWMPin.Start();
            
            PWMPin.Frequency = 100000;
            PWMPin.DutyCycle = .5;

            while (true)
            {
                //do nothing wait for interrupts
            }

        }

        static void RotaryButton_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            Debug.Print("Button Interrupt");
            InterruptCountB = 0;
            InterruptCountA = 0;
        }

        private static void PinB_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            InterruptCountB++;
            Debug.Print(InterruptCountB.ToString() + " PinB Interrupt");
        }

        static void PinA_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            InterruptCountA++;
            Debug.Print(InterruptCountA.ToString() + " PinA Interrupt");
        }

    }
}


#2

@ Gismofx - While testing this – I do not have a suitible rotary encoder to test so I was testing interrupts with a button using your code – I was able to reproduce the issue of seeing more interrupts than we should. However, even though you say your encoder is hardware debounced, I was able to solve the issue by enabling the Glitch filter.

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHI.Hardware.FEZCerb;

namespace Topic_153345
{
    public class Program
    {
        static InterruptPort PinA;
        static InterruptPort PinB;
        static InterruptPort RotaryButton;
        static int InterruptCountA;
        static int InterruptCountB;

        public static void Main()
        {
            InterruptCountA = 0;
            InterruptCountB = 0;


            PinA = new InterruptPort(Pin.PC10, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);//Pins are pulled high.
            PinB = new InterruptPort(Pin.PA14, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);//Interrupt Needed here.



            PinA.OnInterrupt += PinA_OnInterrupt;
            PinB.OnInterrupt += PinB_OnInterrupt;

            RotaryButton = new InterruptPort(Pin.PC11, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
            RotaryButton.OnInterrupt += RotaryButton_OnInterrupt;

            PWM PWMPin;


            PWMPin = new PWM(Cpu.PWMChannel.PWM_7, 100000, .5, false);
            PWMPin.Start();

            PWMPin.Frequency = 100000;
            PWMPin.DutyCycle = .5;

            while (true)
            {
                //do nothing wait for interrupts
            }

        }

        static void RotaryButton_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            Debug.Print("Button Interrupt");
            InterruptCountB = 0;
            InterruptCountA = 0;
        }

        private static void PinB_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            InterruptCountB++;
            Debug.Print(InterruptCountB.ToString() + " PinB Interrupt");
        }

        static void PinA_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            InterruptCountA++;
            Debug.Print(InterruptCountA.ToString() + " PinA Interrupt");
        }
    }
}

#3

@ James Thanks! I feel a little more sane knowing you were able to reproduce the effect. I’ll give it a try on my end this afternoon and report back.

I was reading somewhere that glitch filter had no effect and I never really thought about it having an effect in this case. I’m really curious…do you have any idea what’s going on “under the hood” that would cause this? What’s glitch filter doing to remedy it?

Thanks!


#4

@ James,

Unfortunately, this didn’t resolve any of my problems. With glitch filter enabled, I’m still seeing the erratic interrupts. Disabling PWM does make the encoder/interrupts behave as expected.

I’ve attached an image of the hardware debounced rotary encoder circuit.


#5

Update:

It turns out, the PWM jumper wire(s) introduce some kind of noise or error in the interrupt jumper lines. When the PWM jumper gets within 1" of the interrupt jumper, the interrupts go haywire. So, I need to create a physical separation to get everything to work correctly. It’s isn’t ideal.

How can this PWM “noise” be eliminated in both the prototyping jumpers and with design PCB traces.

Thanks!