What is a quadrature encoder/decoder ?
If you’ve ever used a mechanical computer mouse (yes the ones that get dirty and the pointer hangs), they’ve got 2 of these encoders in them. The whole purpose of them is to measure how far the mouse was moved and in which direction. By using 2 sensors (e.g. photodiode/LED pair) aligned in a special way and a chopper wheel this can be done. Ideally the sensor produces two debounced square waves with a phase shift of 90°.
LTSpice is freely available, but not completely bug free. So far I’ve found 2 annoyances with the supplied models for a D-flip-flop and a N-way XOR gate. I found some Verilog HDL code for a quadrature decoder which I wanted to simulate, but due to these bugs it didn’t work right away.
- D-flip-flop: absolutely no time delay between input and output.
- N-way XOR: according to mathematica XOR for 4 inputs should be XOR( XOR(A,B), XOR(C,D) ) which can be expanded with boolean algebra to some complicated formula. Its output should only be high, if an odd number of inputs is high, otherwise low. LTSpice treats an N-way XOR like a 2-way XOR, that is its output Y is only high if just one of its inputs (A,B) is high (A+B=1). This is not correct.
As a small part of my PhD work, I came up with the CAD designs of a rotary encoder add-on for some translation stages incorporated in our vacuum setup. Later on I added some user friendly electronics using the Arduino Diecimila board. The stages are driven by NewFocus picomotors.
These are essentially lead screws moved by piezoelectric actuators, assisted by friction and the inertia of the screw. The piezo expands with a slowly rising high voltage and drags the screw with it. Later the voltage is shut of quickly which moves the piezo back to its zero position without rotating the screw. By reversing this sequence (sawtooth waveform) the direction of rotation can be reversed.
The advantage of these picomotors is the step size and speed. The average translational step size of the stage is somewhere in the 30nm range, the driving frequency can be as high as 2kHz. We use them for precision adjustment of optical components (mirrors, lenses) in vacuum. The biggest disadvantage is that the step size varies a lot over time and current position on the lead screw. The balance of friction/inerta is easily disturbed by dirt and other mechanical irregularities. Therefore it is not possible to reproducibly move to a certain point in space. This is where the rotational encoder comes handy.
The first version was built by our electronics shop using an FPGA and a microcontroller to upload the results to a PC with RS232/RS485. It worked, but there was no userfriendlyness. No display, no help texts if wrong commands were sent to it and so on. The FPGA was programmed with the quadrature decoder logic and an up/down counter with a buffer. This allowed it to continue counting while sending the last requested position to the µC.
A quadrature decoder looks something like this in Verilog HDL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | module quad(clk, quadA, quadB, count); input clk, quadA, quadB; output [7:0] count; reg [2:0] quadA_delayed, quadB_delayed; always @(<strong>posedge</strong> clk) quadA_delayed <= {quadA_delayed[1:0], quadA}; always @(<strong>posedge</strong> clk) quadB_delayed <= {quadB_delayed[1:0], quadB}; wire count_enable = quadA_delayed[1] ^ quadA_delayed[2] ^ quadB_delayed[1] ^ quadB_delayed[2]; wire count_direction = quadA_delayed[1] ^ quadB_delayed[2]; reg [7:0] count; always @(posedge clk) begin if(count_enable) begin if(count_direction) count<=count+1; <strong>else</strong> count<=count-1; end end endmodule |
This was taken from fpga4fun.com. Thanks for the help btw. !
Putting it into LTSpice (without the counter itself) looks like this:
The delay lines had to be added to correctly represent the D-flip-flops. The resistor terminates the delay line to avoid reflections, the schmitt trigger cuts off voltages spikes above the high level. They shouldn’t be there, but I think it is some kind of numerical error. This work around should not be necessary with a proper model for the D-flip-flop, that is with a configurable time delay for the gate. Without a time delay between signal input and output, it just doesn’t work. The clock signal’s rising edge would always occur at the same time as the signal’s rising edge. If this happens, the signal of V(cnt_enable) just vanishes at all times. The error in the N-way XOR was removed by building a 4-way XOR with three 2-way XORs. The 4 D-flip-flops on the left are some sort of memory. Without them a time shift of the clock vs. the signals can have bad effects.
Edit: please read comment #6 for more info on the XOR/D-flip-flop issue.
Transient analysis gives this result:
A zip-file with the LTSpice files: 6_d_ff.zip, and a PDF of the 2 graphs: pico_encoder_spice.pdf.
When I put this into the Arduino, all of this is done in software of course. It works by polling 2 quadrature encoders (4 sensors) with a timer2 overflow interrupt at about 500Hz including the processing of the analog signals. I didn’t use pin change interrupts, as I wanted to have analog values for adjusting switching levels in my code and not in hardware. This can all be done via the serial link and stored in the EEPROM, much easier for users.
No related posts.











That code is Verilog, not VHDL.
OK. Changed the term to ‘Verilog HDL’.
I don’t know whether you’re interested, but I had posted an Arduino library to do quadrature decoding in the timer2 interrupts as well. I took the time to encapsulate it into a class so you can do things like:
#include “Quadrature.h”
Quadrature myencoder1(9, 10); // Connected to pins 9 and 10
…
x = myencoder1.position();
Might be of interest to you.
http://www.neufeld.newton.ks.us/electronics/?page_id=249
Thanks for the blogroll, BTW!
Nice, I’ll consider this when I use a rotary encoder button next time. And it’s about time I familiarize myself with creating and really understanding classes/objects in C++, not just using them :-)
Your code accepts encoders on all the digital pins of the Arduino, but in this little project I had to use analog reads. User adjustments on the sensor hardware itself had to be avoided at all cost. It is only good enough for hand wheels and maxes out at about 50Hz tick frequency (about 1 revolution per second).
I’ve been lucky on my projects and the internal Schmitt triggers have been good enough to do analog conversions for me. My sympathies to you. :-)
Before having indulged your ignorance with your misguided attempt at trashing LTspice, you really should have made the small effort required to read the LTspice Help file topic on digital a-devices (Help -> LTspice -> Circuit Elements -> A. Special Functions). Had you done so, you would have seen the following:
“The propagation delay defaults to zero and is set with instance parameter Td. Input hold time is equal to the propagation delay.”
And:
“The exclusive XOR device has non-standard behavior when more than two inputs are used: The output is true only when exactly one of all inputs is true. Use the associative property of XOR’s with multiple XOR devices to implement an XOR block with more than two inputs.”
Rather than blogging testimonials to your own techno-tool laziness, you might consider joining the LTspice Yahoo users’ group. It’s very active, offers more useful support than most for-pay groups, has a huge archive of circuits and tips and is open to all, beginners and experts alike, with an interest in LTspice.
http://tech.groups.yahoo.com/group/LTspice
See you there! – a.s.
Well my friend, thank you for showing me the ‘right way’. It’s always nice to be reminded of the good old RTFM.
If I had really wanted to thrash LTSpice you would have noticed.
I’d prefer non standard behaviour of gates to be pointed out more clearly, that is NOT having to dig through the manpage.
Defaulting the delay Td of a logical gate to zero is questionable. It would be more helpful to make these parameters clearly visible by adding a line with “Td=0, Z=…” for setting default values.