Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Interrupt Port and Input Port Read Values are Wrong on First Interrupt.

interruptport read

Best Answer gismo, 24 March 2014 - 01:38 AM

Thanks for that! It's still odd behavior, but I ditched those Read call. I was actually thinking about it, but then was wondering how to capture both pin states at the time of interrupt...Because I saw used that method used in some examples.

 

Here's what I came up with in my driver:

void RotationInterrupt(uint data1, uint data2, DateTime time)//Data1 Is Pin Data 2 Is Pin.Read()
        {

            if (data1 == (uint)PinA.Id && data2 == 0)//Pin A Goes LOW
            {
                State[StateCount] = 1;
            }
            else if (data1 == (uint)PinA.Id && data2 == 1) //Pin A Goes HIGH
            {
                State[StateCount] = 2;
            }
            else if (data1 == (uint)PinB.Id && data2 == 0) //Pin B Goes LOW
            {
                State[StateCount] = 3;
            }
            else if (data1 == (uint)PinB.Id && data2 == 1) //Pin B Goes HIGH
            {
                State[StateCount] = 4;
            }

            StateCount++;
            if (StateCount == 2)//we've collected two states. Let's compare them and return a rotation direction
            {
                StateCount = 0;  //reset the state count              
                //COUNTERCLOCKWISE
                if (!SkipFirstInterrupt)
                {
                    if ((State[0] == 1 && State[1] == 3) || (State[0] == 2 && State[1] == 4))
                    {
                        //do counterclockwise
                        RotationEventHandler(COUNTERCLOCKWISE, 0, DateTime.Now);
                    }

                    else if ((State[0] == 3 && State[1] == 1) || (State[0] == 4 && State[1] == 2))
                    {
                        //do clockwise
                        RotationEventHandler(CLOCKWISE, 0, DateTime.Now);
                    }
                }
                SkipFirstInterrupt = !SkipFirstInterrupt;
            }

        } 

 Seems to be working pretty well!

Go to the full post


  • Please log in to reply
4 replies to this topic

#1 gismo

gismo

    Advanced Member

  • Members
  • PipPipPip
  • 110 posts

Posted 23 March 2014 - 03:50 PM

I'm noticing some funny behavior with some rotary encoder code that I have. It's for a quadrature encoder knob where I have device hardware debounced. The code does not work correctly ONLY on the first event. After the first event, results are consistent and correct.

 

Both PinA.Read() and PinB.Read() return TRUE on the first event. PinA() should always be FALSE due to the InterruptMode.InterruptEdgeLow and PinB() will vary depending on direction, but also ALWAYS returns TRUE on the first

interrupt that's triggered.

 

Also, the logic analyzer shows the encoder performing as it should.

 

I've really simplified the code and maybe someone else can test it out. I've also tried this on several pins with the same results.

public class Program
    {
        static RotaryEncoder RE;
        static int RotCount=0;
        static InterruptPort PinA;
        static InputPort PinB;
        
        static bool PinAVal;
        static bool PinBVal;


        public static void Main()
        {
            PinA = new InterruptPort(Pins.GPIO_PIN_D0, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            PinB = new InputPort(Pins.GPIO_PIN_D1, false, Port.ResistorMode.Disabled);
            PinA.OnInterrupt += PinA_OnInterrupt;
            while (true)
            {
                Thread.Sleep(Timeout.Infinite);
            }

       
        }

        static void PinA_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            PinBVal = PinB.Read();
            PinAVal = PinA.Read();
            if (PinBVal)
            { Debug.Print("CounterClockwise!"); }
            else { Debug.Print("Clockwise!"); }

        }

analogdeb.jpg

 

 

Subsequent interrupts return correct values.

 

I've experienced this in both 4.2 and 4.3 firmwares.



#2 gismo

gismo

    Advanced Member

  • Members
  • PipPipPip
  • 110 posts

Posted 23 March 2014 - 07:30 PM

Well, a work around is to change InterruptMode to InterruptEdgeBoth and trap the FIRST interrupt and do nothing. The Second interrupt is inevitable due to the nature of the encoder and this time around the read values are correct and I can get consistent results.

 

I think there is something wrong in Netmf and/or the firmware. I've found the same problem with a GHI Netmf device also.

 

Can anyone else reproduce this?



#3 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 23 March 2014 - 08:44 PM

I have not tried to reproduce the behavior, but there is one fundamental issue with using port.Read() in the interrupt handler: because the interrupts are queued, the handler is executed after a certain period of time, thus port.Read() returns the port state at the time the interrupt handler is being executed, not when the interrupt occurred. This can cause incorrect results, especially when the pulse duration or frequency is close to execution time of the interrupt handler (managed code).

 

I guess a better way is to use two interrupt ports, both set up for falling and rising edge (InterruptEdgeBoth) and use the handler parameters data1 (port number), data2 (port state, 1/0) and timestamp in a state machine (you can reuse one xxx_OnInterrupt handler).



#4 gismo

gismo

    Advanced Member

  • Members
  • PipPipPip
  • 110 posts

Posted 24 March 2014 - 01:38 AM   Best Answer

Thanks for that! It's still odd behavior, but I ditched those Read call. I was actually thinking about it, but then was wondering how to capture both pin states at the time of interrupt...Because I saw used that method used in some examples.

 

Here's what I came up with in my driver:

void RotationInterrupt(uint data1, uint data2, DateTime time)//Data1 Is Pin Data 2 Is Pin.Read()
        {

            if (data1 == (uint)PinA.Id && data2 == 0)//Pin A Goes LOW
            {
                State[StateCount] = 1;
            }
            else if (data1 == (uint)PinA.Id && data2 == 1) //Pin A Goes HIGH
            {
                State[StateCount] = 2;
            }
            else if (data1 == (uint)PinB.Id && data2 == 0) //Pin B Goes LOW
            {
                State[StateCount] = 3;
            }
            else if (data1 == (uint)PinB.Id && data2 == 1) //Pin B Goes HIGH
            {
                State[StateCount] = 4;
            }

            StateCount++;
            if (StateCount == 2)//we've collected two states. Let's compare them and return a rotation direction
            {
                StateCount = 0;  //reset the state count              
                //COUNTERCLOCKWISE
                if (!SkipFirstInterrupt)
                {
                    if ((State[0] == 1 && State[1] == 3) || (State[0] == 2 && State[1] == 4))
                    {
                        //do counterclockwise
                        RotationEventHandler(COUNTERCLOCKWISE, 0, DateTime.Now);
                    }

                    else if ((State[0] == 3 && State[1] == 1) || (State[0] == 4 && State[1] == 2))
                    {
                        //do clockwise
                        RotationEventHandler(CLOCKWISE, 0, DateTime.Now);
                    }
                }
                SkipFirstInterrupt = !SkipFirstInterrupt;
            }

        } 

 Seems to be working pretty well!



#5 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 25 March 2014 - 07:30 AM

To confirm:

As CW2 mentioned, the interrupt pin state is passed in as the data1 parameter--0 for low/false and 1 for true/high. If you call the Read() function, you'll get the current state of the pin--which could have changed since the interrupt was queued/fired.

Chris





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.