Main Site Documentation

Reading Encoder - OutOfMemoryException problem


#1

Hi,

I’ve been trying to read a rotary encoder with no success in the long term…
Attached channels A and B to interrupt ports, put almost anything under comments, but after few turns of the encoder the program hangs and I get the OutOfMemory exception.
I can get it to work for only short time, I don’t understand what is eating all the memory each time the interrupts raises.
BTW The encoder has 1024 ppr, but it’s rotated by hand so it shouldn’t go over 1 revolution per second

Help would be much appreciated.


using System;
using Microsoft.SPOT;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
using System.Threading;
using Microsoft.SPOT.Hardware;
using System.IO.Ports;
using System.Text;

namespace EncoderReader
{
    public class Program
    {
        //static SerialPort UART = new SerialPort("COM1", 57600);
        static OutputPort LED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);
        //InputPort Button = new InputPort((Cpu.Pin)FEZ_Pin.Interrupt.LDR,false,Port.ResistorMode.PullUp);
        static InterruptPort Encoder1A = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.An0, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
        static InterruptPort Encoder1B = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.An1, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
        
        static int encoder1Pos = 0;
        static bool encoder1A_Set = false;
        static bool encoder1B_Set = false;
        static byte[] buffer = new byte[64];

        static void Main()
        {
            //UART.Open();
            LED.Write(true);

            Encoder1A.OnInterrupt += new NativeEventHandler(Encoder1A_OnInterrupt);
            Encoder1B.OnInterrupt += new NativeEventHandler(Encoder1B_OnInterrupt);

            Timer MyTimer = new Timer(new TimerCallback(RunMe), null, 0, 1000);

            while (true)
            {
                Thread.Sleep(Timeout.Infinite);
            }
        }

        static void RunMe(object o)
        {
            //buffer = Encoding.UTF8.GetBytes("Index = " + encoder1Pos.ToString() + "\r\n");
            //UART.Write(buffer, 0, buffer.Length);
            //UART.Flush();
            LED.Write(!LED.Read());
        }

        static void Encoder1A_OnInterrupt(uint port, uint state, DateTime time)
        {
            encoder1A_Set = Encoder1A.Read();
            encoder1Pos += (encoder1A_Set != encoder1B_Set) ? +1 : -1;
        }

        static void Encoder1B_OnInterrupt(uint port, uint state, DateTime time)
        {
            encoder1B_Set = Encoder1B.Read();
            encoder1Pos += (encoder1A_Set == encoder1B_Set) ? +1 : -1;
        }

    }
}



#2

hello ofir.

First do a check of the encoder1Pos value is not going to be behind the max and min int value.
And use debug.print(encoder1Pos .ToString()); to see what the current value of that value is

succes

Niels


#3

Hi Niels,

The values i’m getting for the encoder are correct, but only when turning it very slowly.
I suspect it can’t handle the interrupts at high rate, as it would go to about 2 [kHz] per channel when turning at 1 revolution per sec.
Is there a way to make it work?

thanks,
ofir


#4

Try this first:

static void Main()
        {
            //UART.Open();
            LED.Write(true);
 
            Encoder1A.OnInterrupt += new NativeEventHandler(Encoder1A_OnInterrupt);
            Encoder1B.OnInterrupt += new NativeEventHandler(Encoder1B_OnInterrupt);
 
            while (true)
            {
                LED.Write(!LED.Read());
                Thread.Sleep(1000);
            }
        }

And get rid of the RunMe() method.


#5

The following code makes no sense:


while (true)
{
     Thread.Sleep(Timeout.Infinite);
}

instead use


Thread.Sleep(Timeout.Infinite);

[line]

instead of reading the state

encoder1A_Set = Encoder1A.Read();

use the state parameter that is passed to the methods.

Also, I’m not sure what this code is suppossed to do:
(encoder1A_Set != encoder1B_Set)
Aren’t the encoders independent of each other.

I don’t think it is possible for your program to know which direction your encoder is turning. Unless of course you are turning it with a motor, then you can work out the direction yourself. All you can do is know how much you have turned.

Take a look at this project, it pretty much the same as the encoder (link removed)

Hope this helps.


#6

Hi RJ,

You’re right about the Thread.Sleep remark, it’s a leftover from a cut-paste I did.

About the code itself, it’s based on this code:
http://www.arduino.cc/playground/Main/RotaryEncoders
(Under the “Tighten up the ISR’s” heading)
And it worked for me on an arduino pro board, the problem is that the arduino has only 2 external interrupt ports, and I need to read 3 encoders so I’ve tried it on the FEZ board.


#7

I did not go through your code closely enough to discover where the memory problem might come from but can say with very good certainty that you won’t be able to do a quadrature decoder in managed code. The interrupt latency is on the order of 1~3 ms so you’ll never be able to know which channel was in which state when responding to one channels interrupt.

Generally, when trying to do quadrature decoding on a uC (in lieu of a FPGA or other HW solutions) you use an interrupt on only one phase signal (say A) and when the interrupt occurs you increment or decrement the counter depending on the state of the Phase B input (by reading the state at that time). Still, this will work for lower input frequencies and then only if you use native ISRs.

If you really need a high speed quadrature decoder then you might consider using a dedicated decoder chip.


#8

Hi Jeff, that latency is what I’ve suspected.
I’ll try doing it with only one phase interrupt and limited revolution speed.

Thanks