Encoders, how to support them

The overhead required to bit-bang in a quadrature encoder is going to grind your EMX to a halt even using interrupts. You need to offload the pulse detection to a chip like:

[url]http://usdigital.com/products/interfaces/ics/lfls7166-s[/url]

I have dealt with these encoders before and found that it is much easier to use an interface chip.

Sorry that I wasn’t clear.
To answer the topic start, in my experience the standard encoder is the quadrature encoder.
5k pulses per second result in 14400 cycles @ 72 MHz, so a well tuned native interrupt handler would work nicely, though I am unexperienced in this platform :slight_smile:
Native encoder support would help in a lot of smaller robotics projects, as is my project (I’m investigating for a prototype for what hopefully will result in a quantity of 70).
Adding another ic would complicate things quite a lot for me, though its probably a good solution for others.
BTW, I can’t find the RLP docs for writing an ISR in the wiki or Downloads & Tutorials, where should I look?

http://www.ghielectronics.com/downloads/NETMF/Library%20Documentation/Index.html

under RLP, search for “interrupt”

The following is a class I wrote to drive the quadrature encoder available at sparkfun: [url]http://www.sparkfun.com/products/9117[/url]


    class QuadEncoder
    {
        byte lastPosition;
        InterruptPort[] rotationPins = new InterruptPort[2];
        InterruptPort buttonPin;
        sbyte offset = 0;

        public bool Wrap { get; set; }
        public int Value { get; set; }
        public int MinValue { get; set; }
        public int MaxValue { get; set; }

        public QuadEncoder(FEZ_Pin.Interrupt rotationPin, FEZ_Pin.Interrupt secondRotationPin, FEZ_Pin.Interrupt buttonPin)
        {
            this.Wrap = true;
            this.Value = 0;
            this.MinValue = 0;
            this.MaxValue = int.MaxValue;
            this.rotationPins[0] = new InterruptPort((Cpu.Pin)rotationPin, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
            this.rotationPins[1] = new InterruptPort((Cpu.Pin)secondRotationPin, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
            this.buttonPin = new InterruptPort((Cpu.Pin)buttonPin, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);

            this.rotationPins[0].OnInterrupt += new NativeEventHandler(OnRotate);
            this.rotationPins[1].OnInterrupt += new NativeEventHandler(OnRotate);

            this.buttonPin.OnInterrupt += new NativeEventHandler(OnButton);

            this.lastPosition = GetPosition();
        }

        private byte GetPosition()
        {
            byte position = 0;

            bool pin1 = this.rotationPins[0].Read();
            bool pin2 = this.rotationPins[1].Read();

            if (pin1)
            {
                if (pin2)
                    position = 0;
                else
                    position = 3;
            }
            else
            {
                if (pin2)
                    position = 1;
                else
                    position = 2;
            }

            return position;
        }

        void OnButton(uint data1, uint data2, DateTime time)
        {
            QuadEncoderButtonEvent(this, data2 != 0);
        }

        void OnRotate(uint data1, uint data2, DateTime time)
        {
            byte position = GetPosition();
            sbyte offset;

            offset = (sbyte)(position - this.lastPosition);
            this.lastPosition = position;

            if (offset == -3)
                offset = 1;
            else if (offset == 3)
                offset = -1;

            UpdateOffset(offset);
        }

        private void UpdateOffset(sbyte offset)
        {
            bool changed = false;
            this.offset += offset;

            if (this.offset >= 4)
            {
                changed = true;
                offset = 1;
            }
            else if (this.offset <= -4)
            {
                changed = true;
                offset = -1;
            }

            if (changed)
            {
                this.Value += offset;

                this.offset = 0;

                if (this.Value > this.MaxValue)
                {
                    if (Wrap)
                        this.Value = this.MinValue + ((this.Value - this.MaxValue) - 1);
                    else
                        this.Value = this.MaxValue;
                }
                else if (this.Value < this.MinValue)
                {
                    if (Wrap)
                        this.Value = this.MaxValue - ((this.MinValue - this.Value) - 1);
                    else
                        this.Value = this.MinValue;
                }

                QuadEncoderRotationEvent(this, offset);
            }
        }

        public delegate void QuadEncoderRotationEventHandler(QuadEncoder encoder, sbyte direction);
        public event QuadEncoderRotationEventHandler QuadEncoderRotationEvent = delegate { };

        public delegate void QuadEncoderButtonEventHandler(QuadEncoder encoder, bool state);
        public event QuadEncoderButtonEventHandler QuadEncoderButtonEvent = delegate { };
    }

I’m using it with a knob for user input.

Can you please add it to code-share so the whole community can benefit from it http://code.tinyclr.com
maybe with an explanation on how it is used.

Hi community,

There is a routine for the LS7366 in the code part of this site.
Different to the LS7166, mentioned before, the LS7366 communicates through SPI not by physical IO.
Also the LS7366 has programmable DFLAG an LFLAG outputs, that can interrupt a processor.

Have alook at: [url]http://code.tinyclr.com/project/317/ls7366-library/[/url]

@ jesse. thank you for your encoder code distribution, how responsive is the code? Is it possible for me to read 4-5 360ppr encoders simultaneously (2 channel) at 1rps each? I am so confused why is there an issue with program many high speed encoders using 72 Mhz board.

It wouldn’t be a problem if you were dealing with native code in real-time. But with .NET Micro you have delays that are not deterministic so even a 72MHz processor will not reliably catch digital inputs coming in that quickly. In my experience (senior design engineer of 6 years) these kinds of time sensitive tasks are best left to either dedicated hardware or 8-bit micros with no other task to handle.

@ blue stream from your experience can I process an 5 encoders simultaneously using an atmega1280 and cod vision avr?

Code Vision AVR generates compact machine code, so the answer is probably.
It depends on how you write your code.

If you do not succed, have a look at a special designed chip for encoders.

Such as: [url]http://www.lsicsi.com/encoders.htm[/url]
Look for the right chip specs.

Assuming that only one encoder is active at any given time…absolutely. If all five are asynchronous and operating at max RPM, probably not with an AVR 8-bit core. If you upgrade to the AVR32 you can definitely catch that many interrupts without them being synchronized.

If I were to use a dedicated uC for reading multiple quadrature decoders I would not even bother with using interrupts. Four encoders would only be eight data lines to poll, or more precisely one port, which can be done very quickly. If the uC has a built in timer you might even be able to use it to poll on a more periodic basis.