Author Topic: Rotary encoders vs VHDL.  (Read 8483 times)

0 Members and 1 Guest are viewing this topic.

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Rotary encoders vs VHDL.
« on: November 22, 2015, 08:14:47 pm »
I was playing around with a rotary encoder on the weekend, and found that my usual way of decoding the quadrature outputs was not working. If you are driving a counter up and down then switch bounces don't really matter, but in this case I was zooming in by uneven amounts, so switch noise would cause uneven jumps.

The solution I came up with was rather than debouncing the contacts (which just made things better) was to do away with the debounce all together, and to look at the last three changes in quadrature, and then make decisions based on that:
Code: [Select]
            case enc_quad_safe & enc_quad_last & enc_quad_last_last is
                when "010010" => scale_internal <= scale_right;
                when "001011" => scale_internal <= scale_right;
                when "101101" => scale_internal <= scale_right;
                when "110100" => scale_internal <= scale_right;
                when "100001" => scale_internal <= scale_left;
                when "000111" => scale_internal <= scale_left;
                when "011110" => scale_internal <= scale_left;
                when "111000" => scale_internal <= scale_left;
                when others => NULL;
            end case;

            enc_quad_meta <= enc_b & enc_a;
            enc_quad_safe <= enc_quad_meta;           
            if  enc_quad_last /=  enc_quad_safe then
               enc_quad_last  <= enc_quad_safe
               enc_quad_last_last <= enc_quad_last(3 downto 2);
            end if;

It's a technique applicable to both micros and FPGAs.
It is now super sweet -
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1198
  • Country: fi
Re: Rotary encoders vs VHDL.
« Reply #1 on: November 22, 2015, 11:21:30 pm »
Atmel (of all people) used to have an app note about reading quadrature encoders in VHDL. Unfortunately I can't find it anymore, but IIRC they just used a simple filter that required the N last inputs to be stable before it changed state.

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4544
  • Country: au
    • send complaints here
Re: Rotary encoders vs VHDL.
« Reply #2 on: November 22, 2015, 11:57:54 pm »
A cascade of two 2-tap filters is slightly cheaper than the 3-tap filter in most archtectures, but they're both simple enough for most cases.
 


Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Rotary encoders vs VHDL.
« Reply #4 on: November 24, 2015, 07:41:05 pm »
Quote
The solution I came up

It is based on a state machine. It has been done for decades, with four bits (16 combinations). Incredibly resistant to contact bounces.
================================
https://dannyelectronics.wordpress.com/
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Rotary encoders vs VHDL.
« Reply #5 on: November 25, 2015, 07:38:03 am »
Quote
The solution I came up

It is based on a state machine. It has been done for decades, with four bits (16 combinations). Incredibly resistant to contact bounces.

Have to agree - super resistant to switch bounces (yay! no debounce with it's arbitrary timeout is needed).

It could be implemented with an FSM, but coding it as an explicit FSM would be pretty ugly (16 states, three transitions out of each state). It also looks to be pretty compact (4 FFs for the synchronizer,  4 FFs for holding the encoder's prior inputs, a couple of LUTs to see if the encoder's state has changed, and two LUT6s to decide what action to do.

Much smaller than anything with a debounce counter, and should work up to almost any speed until the switches no longer open and close in the correct sequence, and even then it should fail relatively gracefully with it just skipping counts.

The only reason I bothered posting was that some of the other references I've bothered to read would suffer from the same problem as my original attempt had - noise input leads to noisy output.  - e.g:

http://www.fpga4fun.com/QuadratureDecoder.html
http://jugglingpirate.net/using-rotary-encoder-with-fpga-vhdl-code/
https://www.hackmeister.dk/2010/07/using-a-quadrature-encoder-as-input-to-fpga/
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Rotary encoders vs VHDL.
« Reply #6 on: November 25, 2015, 11:52:56 am »
Quote
coding it as an explicit FSM would be pretty ugly (16 states, three transitions out of each state).

Here would be one implementation:

Code: [Select]
  static uint8_t enc_states=0; //encoder states: AB_prev..AB_now, lowest four bits effective
 
  enc_states <<=2; //left shift previous states
  enc_states |= (IO_GET(ENCA_PORT, ENC_CHA)?0x02:0x00) | (IO_GET(ENCB_PORT, ENC_CHB)?0x01:0x00); //read current encoder pin states
  return enc_outcome[enc_states & 0x0f]; //return encoder output from a look-up table, lowest four bits effective

If you want, you can actually write it out on a single return line - not terribly readable but 100% functional.
================================
https://dannyelectronics.wordpress.com/
 

Offline hamster_nzTopic starter

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Rotary encoders vs VHDL.
« Reply #7 on: November 25, 2015, 06:49:20 pm »
Quote
coding it as an explicit FSM would be pretty ugly (16 states, three transitions out of each state).

Here would be one implementation:

Code: [Select]
  static uint8_t enc_states=0; //encoder states: AB_prev..AB_now, lowest four bits effective
 
  enc_states <<=2; //left shift previous states
  enc_states |= (IO_GET(ENCA_PORT, ENC_CHA)?0x02:0x00) | (IO_GET(ENCB_PORT, ENC_CHB)?0x01:0x00); //read current encoder pin states
  return enc_outcome[enc_states & 0x0f]; //return encoder output from a look-up table, lowest four bits effective

If you want, you can actually write it out on a single return line - not terribly readable but 100% functional.

Ah... you are missing the important bit. The output is based on the last two transitions, not the last two readings.

Say on a click to the left you add 1 to a counter, and on the click to the right you take 2 off the counter..

Here is the data for two clicks to the left, with a bit of switch bounce on the first transition ("00" => "01")

  ...."00", "01","00","01","00", 01","00","01","11","11"...

If you base it on the last two reading, because of the bounce in the middle you get +1, -2, +1, -2,+1, -2, +1, +1, a total of -1.
Code: [Select]
Change    input  last   output
1:        01     00      +1
2:        00     01      -2
3:        01     00      +1
4:        00     01      -2
5:        01     00      +1
6:        00     01      -2
7:        01     00      +1
8:        11     01      +1
7:        11     11      0

If you base your on the last two transitions you get a reliable output - when you get two "click to the right" or "click to the left" in a row, only then do you act on it.

Code: [Select]
Change    input  prior_values   transitions  output
1:         01     00 01         L R           0
2:         00     01 00         R L           0
3:         01     00 01         L R           0
4:         00     01 00         R L           0
5:         01     00 01         L R           0
6:         00     01 00         R L           0
7:         01     00 01         L R           0
8:         11     01 00         R R           +1


In my case I was "zoom <= zoom * 3/4" one way, and "zoom <= zoom * 5/4", with my problem being that "(3*5)/(4*4) = 15/16, 15/16 != 1", so switch bounce in the encoder would show up as a visible jump in the zooming.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Rotary encoders vs VHDL.
« Reply #8 on: November 26, 2015, 04:38:30 pm »
Quote
The output is based on the last two transitions, not the last two readings.

It doesn't really matter: 1) you can run the code within an isr triggered by transitions; 2) in pulling, any (valid) transition will be read; and any invalid transition (bounces), other than the very first one, will be ignored, as the look-up table will return a value of 0.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf