4
\$\begingroup\$

I am programming an Altera FPGA using Quartus II v9.0 to count encoder pulses and output that count to an external LabVIEW program (see diagram below). I was able to debug one issue with my code thanks to the StackExchange community, but now I am getting intermittent run-away in my encoder count.

As I move my encoder, my LabVIEW code is displaying the current count correctly. When I stop moving the encoder, the count stops about half the time, and the other half the count just runs away. I suspect that the encoder is getting stuck in an in-between state and one of my phases is fluttering. Is there a trick that I can use to filter this out, or a better method of counting encoder pulses that I can program into my Altera FPGA?

schematic

simulate this circuit – Schematic created using CircuitLab

The 4-input XOR block executes as:

(IN1 xor IN2) xor (IN3 xor IN4)

The Count enable and Count direction signals are going in to a 32-bit built-in counter function (LPM_COUNTER) on my Altera FPGA programmed using Quartus II v9.0. The output of this counter is stored in a buffer (LPM_BUSTRI) and read using a LabVIEW program whenever the LabVIEW code needs it. I have a similar LabVIEW code reading other buffers from the FPGA that is working fine, so I am fairly certain that the problem lies in my FPGA somewhere.

I have tried adding a trigger delay to the A and B signals that only registers a change in the signal if that signal has remained high or low for a certain number of clock cycles (I tried 2 and 4 so far). This seemed to make the problem worse. I also tried adding a fourth set of D-Q flip-flops, which did not have any obvious effect.

Thank you for your help!

\$\endgroup\$
  • \$\begingroup\$ Are you using Schmitt triggers to clean up the encoder inputs before the FPGA? If not then you will need some digital debounce on A and B after the synchroniser regs (before reg 2/5 above). \$\endgroup\$ – shuckc Jul 31 '13 at 16:33
  • \$\begingroup\$ Have you tried 'analog' debouncing? A small R-C lowpass is sufficient in most cases. Also, you are using an optical encoder? What about ambient light hitting the detectors? This might cause irregular output of the encoder. \$\endgroup\$ – JimmyB Jul 31 '13 at 16:54
  • \$\begingroup\$ The encoder is completely enclosed, and I am not sure whether it is optical. I do not think interference on the encoder is the issue, although I could be wrong. I will look in to Schmitt filters and debouncing. Thank you. \$\endgroup\$ – Engineero Jul 31 '13 at 21:40
  • \$\begingroup\$ You do not necessarily need the debounce circuit outside the FPGA - last time I worked on a project that needed an encoder, the debouncer was built entirely in VHDL - I seem to remember that the vhdl component would output low by default, then every time it received an input spike from the hall sensor, it would output High (Once) and then disregard entirely its input from the hall sensor until X time had passed, where X was some value that was high enough to disregard the bounce but low enough that it didn't disregard the next pulse; something like 1 ms. \$\endgroup\$ – medivh Aug 1 '13 at 7:49
  • \$\begingroup\$ @medivh thanks. It looks like I have a few ideas to try out from this thread. I will get back to you all with what I find out. Thanks everyone! \$\endgroup\$ – Engineero Aug 1 '13 at 13:42
2
\$\begingroup\$

Capture the input rather than the counter to see if bounce is your problem. If you have storage scope, use edge trigger to get the capture. Otherwise try adding debounce between Reg1/Reg2 and between Reg4/5.

To implement this use an 8 or 16 element shift register fed from synchronised A. Take the AND and the ~OR from between all the shift register bits, these give you are "all set" and "all clear" signals. Use this as the set and reset of an output register, which would feed REG2. Same for B -> REG 5.

If you find this still glitches you can either try a lower clock, or extend the shift register. Above 16 stages it's probably better to remodel as a binary counter and last-state bit. On each cycle if the state is different from last, reset counter and update last-state. If the counter overflows without being cleared, that's your trigger to set/reset the output.

\$\endgroup\$
  • 1
    \$\begingroup\$ That makes sense, and I sort of tried that already, but only with a count of 2 and 4 clock pulses. I implemented it differently (using a counter, not a shift register), but I can try it your way. Out of curiosity, why do I put it after Reg1 and Reg4 instead of before them (at the raw inputs)? \$\endgroup\$ – Engineero Jul 31 '13 at 21:43
  • \$\begingroup\$ Reg1, Reg4 are used as clock crossing synchronisers, since inputs A and B are asynchronous with respect to CLK1. You can tell because they do nothing other than delay the signals by one cycle. Since you want the maximum setup time available for metastability to settle between synchroniser stages you don't want any intermediate logic adding routing delay. Besides, if the synchroniser is achieving anything you want that logic to use the clean signal after the synchroniser. \$\endgroup\$ – shuckc Jul 31 '13 at 22:31
  • \$\begingroup\$ What kind of register would I use for the output register (second paragraph of your answer above). Could I do this with a D-Q flip-flop and just not wire up the data or clock terminals? \$\endgroup\$ – Engineero Aug 1 '13 at 13:53
  • \$\begingroup\$ It worked! My counts are no longer running away, and it actually seems to be working fine with a 4-bit shift register. Thank you so much! \$\endgroup\$ – Engineero Aug 1 '13 at 15:41
  • \$\begingroup\$ Awesome! The output stage would be a standard register, the D input would be (Q & ~reset) | set where set = & shift_reg_bits; and reset = ~ |shift_reg_bits; . I don't know LabVIEW, that's Verilog. \$\endgroup\$ – shuckc Aug 1 '13 at 15:49
2
\$\begingroup\$

Sorry, I would have answered this earlier but I was out of town with limited internet access. I see that Shuckc already answered this, but I feel that I have a solution that would be superior.

The problem with debouncing and/or filtering A and B is that it can prevent your decoder from working at the maximum speed (and thus missing counts), it adds complication, it increases logic size, and most importantly it is not required.

Start by keeping the six registers that you already have in your schematic. Let's call the output of Reg2 and Reg5 as A and B. The output of Reg3 and Reg6 is called A_prev, and B_prev-- which is basically the value of A and B for the previous clock.

Next, you create a truth table roughly like this:

A_prev, B_prev, A, B, Count_En, Count_Dir
  0       0     0  0    0         0
  0       0     0  1    1         0
...etc...

You'll have to fill out the entire truth table yourself, but you get the idea. Basically, you look at the current state of A and B, along with the previous values for A and B, and decide if you want to increment or decrement your counter. Now you create some logic to implement this truth table. I recommend that you also register the output of this truth table, before sending the signals to the counter.

This truth table fits into a pair of 4-input LUTs (the basic building block of most FPGAs). Essentially, this is super small. Registering the output of this truth table also takes essentially zero logic, since every LUT in the FPGA has a Flip-flop on the outputs of the LUTS. Compare this with doing some filtering/debouncing, which could take 16 or 32 flip-flops and limits the usefulness of the unused LUTs. So this logic is 1/16th or 1/32nd the size of the filtered/debounced version.

If you are using a newer FPGA that has a 6-input LUT that can be split into 2 smaller LUTs then this design uses even less logic resources.

Registering the output allows your logic to run at greater than 100 MHz on most halfway modern FPGAs, or makes meeting your timing constraints much easier when you are at slower clock speeds. While this doesn't sound important, it doesn't cost anything and it greatly improves the robustness of this design and allows it to be more easily reused in future projects where your main clock is faster.

The very nice thing about this design is that A_in or B_in can change on literally every edge of your 25 MHz clock. If you have a little noise or bounce on your inputs it might cause your counter to "vibrate" back and forth between two adjacent signals, but this would/could happen with a filtered/de-bounced version as well.

The reason why this design doesn't need to filter/debounce A and B is because it can operate as fast as your 25 MHz clock allows. It can't get confused by a quickly changing or noisy input, like your previous design could.

A pet peeve of mine is badly implemented quadrature decoding. Usually it is a bad software implementation that causes the decoder to miss or skip pulses, but occasionally a hardware implementation will do that as well. I'm not saying that filtering/debouncing the quadrature inputs will skip pulses, but I am saying that this approach is better in every way including the maximum speed that it can accept pulses.

\$\endgroup\$
  • \$\begingroup\$ Do I understand correctly that you are basically hard-coding the states that your quadrature encoder can take, and then comparing the current state of the encoder with this truth table to determine whether you are to increment the count, decrement the count, or hold it steady? That makes sense to me as well. If I have time I will try to implement this and see if it runs even better, but the accepted answer is running flawlessly and I am on a bit of a time crunch. Thank you! \$\endgroup\$ – Engineero Aug 2 '13 at 13:28
  • \$\begingroup\$ @Engineero You understand correctly. \$\endgroup\$ – user3624 Aug 2 '13 at 13:49
  • \$\begingroup\$ With a mechanical encoder I doubt the captured frequencies fall outside 0-50hz, with perhaps a uS of bounce on each edge. By passing through bounce you move the problem downstream. For instance if you are positioning a cutting tool or setting a self-destruct timer with a jog dial, you probably wouldn't tolerate overshoot in the set point due to bounce. I'd clean up the input signals first - preferably outside the FPGA until I knew I had logic resources spare to trim the BOM. \$\endgroup\$ – shuckc Aug 5 '13 at 8:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.