Quadrature Encoders

One common task for an electronic device is to read the position of a rotary input. This could be to determine the position of part of a mechanical assembly, or simply to allow the user to select from various options using a scroll wheel.

Rotary encoders generally come in two varieties — absolute and relative. Absolute encoders, as you might expect, convey information about their absolute position. Even if the system has been powered off, these encoders will tell the system exactly where it is (plus or minus one position count.)

Quadrature encoders, on the other hand, do not remember any information about their position. They simply allow the microcontroller (or other circuit) to determine how far the encoder has turned while the microcontroller is monitoring it. This is perfect for jog dials used by the user, where absolute dial position doesn’t matter. Also, they’re easier to manufacture and work with — just two signal wires will do (plus ground and power.)

A generic quadrature encoder module from Amazon.
CLK and DT are the quadrature signals; SW is a normally-open SPST push switch contact.

Quadrature encoders are so named because they supply two phases of information, in quadrature. That is, these two phases transition 90 degrees apart in phase. One cycle of quadrature output (usually corresponding to one “click” of a dial) comprises four distinct phases. Turning it in one direction, the output might be

LL –> LH –> HH –> HL –> LL.

Turned the other way, this encoder would then output

LL –> HL –> HH –> LH –> LL.

Only one line changes state at a time (the criterion for a Gray code) — and by monitoring both lines, the direction of travel can be determined. (If the old state were HH, for example, the next state would have to be either LH or HL — one for clockwise and the other for counterclockwise. The state it changed into would tell you which direction it turned.)

As long as the microcontroller checks both lines faster than the maximum rate at which they can change, no position skip is possible. (Skipping may not be a huge issue on a jog wheel if it only happens once in a while — but skipping steps would make a positional encoder lose track of where it was, possibly causing a mechanical crash.)

Here is Arduino C code (tested on ESP32) to read two pins: ROTARYDAT and ROTARYCLK (defined elsewhere) to get the quadrature state of a rotary input, and update global integer variables called encHalfPhases and encTheta. (Using encHalfPhases directly resulted in the control being too sensitive to use reliably, so encTheta divides it by two.)


void IRAM_ATTR ISR() {

  //Interrupt handler for quadrature encoder on pins ROTARYDAT and ROTARYCLK.
  //Check the quadrature state, update theta, and GTFO...
  //CC:BY-NC-SA M. Eric Carr / Paleotechnologist.Net

  //Grab the new state (TODO: use raw GPIO reads to do this atomically and faster)
  uint8_t newState;
  newState=0x00;
  if(digitalRead(ROTARYDAT)){newState|=0x01;} 
  if(digitalRead(ROTARYCLK)){newState|=0x02;}

  //Update enctheta based on pin state changes
  if((newState ^ encState) & 0x02){
    //Clock changed. Increment or decrement count based on if clk and data match
    if((newState & 0x01)^((newState & 0x02)>>1)){
      encHalfPhases++;}
    else{
      encHalfPhases--;}
      }
  
  //Update the encoder state
  encState=newState;

  //Update theta
  encTheta=(encHalfPhases>>1); //Divide by two. Shift may be faster than div??
      
  }


The code is written to be run as an interrupt service routine (ISR), so it should execute and return very quickly, with no loops or delays. Attach it to interrupt-on-change-capable pins as follows:

  attachInterrupt(ROTARYDAT, ISR_quadrature, CHANGE);
  attachInterrupt(ROTARYCLK, ISR_quadrature, CHANGE);

Through the magic of interrupts, when either pin changes state, the ISR_quadrature routine is called automatically, the saved state is updated, theta incremented, and control is handed back to the main program. All of this should take a few microseconds on most MCUs.

The IRAM_ATTR requests that the compiler place this routine in SRAM instead of Flash memory, for speed of execution (interrupt handlers should be very fast, because you want it to finish before another important interrupt event comes along.)

If implemented as an ISR tied to interrupt-on-change, this routine should work reliably to track quadrature changes. Use it to implement jog controls or to see how far your robot has traveled etc.

A subtle note: Although it may be tempting to use CLK and DT to clock directional data in to a D flip-flop, this setup can glitch if CLK is toggled without changing DT. The “Clock” and “Data” names are misnomers; thinking of them as Phase A and Phase B is safer.

Share and enjoy!

Posted in Arduino, Building blocks, Digital, Electronics, HOW-TO, User Interface Design | Tagged , , , , , , , , , , , , | Leave a comment

New Toy: Round LCD Displays

Full-color (okay, 16- or 18-bit color) LCD and LED displays have been available as breadboardable, microcontroller-friendly modules for several years now. Recently, though, round displays have been appearing in hobbyist-friendly form. These can be thought of as rectangular displays that simply don’t implement pixels that aren’t in the circle radius.

A GC9A01 120-pixel, 18-bit SPI display as a breadboardable module.

GC9A01 display modules use an SPI bus interface, which is slightly more involved to set up than the ubiquitous I2C (or “Wire”) interface. There’s a good reason for this — at 240×240 resolution (really 120px radius), that’s some 45,000 pixels per frame, or north of 800,000 pixels. If you want to do any kind of video or animation, you need several frames per second. SPI is generally used for higher data rate applications, since it can run at 8Mb or more.

I followed the instructions in this video to get the display set up using a standard ESP32 dev board module. The Arduino GFX Graphics Library referenced in the video can drive the GC9A01 via the usual set of APIs for drawing pixels, lines, circles, etc.
Do note that these are 3.3V parts — it’s best to drive them with something modern and fast like an ESP32, which will probably be a 3v3 part itself. An Arduino Uno or PIC16F84A or 8051 could work with these, though — just very slowly. Maybe I’ll get the DrACo/Z80 to run one (via a voltage divider, at least).

They’d make great aircraft instrument replica displays, if only they were a little larger…

Posted in Arduino, Components, Digital, Toys, User Interface Design | Tagged , , | Leave a comment

Non-Volatile SRAM

I’m used to discovering cool new technology when browsing sites like DigiKey. But occasionally, you’ll come across device descriptions that at first look like oxymorons.

I recently needed to order a few 32kB SRAM chips for a course I’m teaching, involving building the latest incarnation of the DrACo/Z80 computer. DigiKey has always been a reliable source for SRAM, and ever since I learned that pretty much every manufacturer out there uses compatible pinouts and protocols, life has been easy. (There are benefits to working with tech with forty-year-old traditions and standards!)

32kB (volatile) SRAM

While ordering the SRAM, I came across an interesting filter field — Volatile or Non-Volatile. This is interesting because SRAM, being transistor-based, is inherently volatile: when you remove the power, it stops remembering whatever you stored in it. (SRAM uses six-transistor memory cells, and when you remove the power, the delicate balancing act that keeps it in a zero or one state goes away. When powered up again, it will basically pick 0 or 1 at random.)

Filtering by Non-Volatile and selecting a likely-looking example, it became apparent what I was looking at. Someone using SRAM had at some point asked an engineer to make a version that wouldn’t lose its contents when powered off. Having looked at the problem, an engineering solution was arrived at — a button-cell battery and a small power management circuit was unceremoniously grafted on top of a memory chip. When external power is available, the system works as usual. When power to the Z80 is cut, it keeps the SRAM memory powered but inactive, with a backup time of up to eleven years, per the datasheet. It looks weird, but it works nicely.

Battery-backed-up NVSRAM, on its custom adapter

The form factor is still DIP28 with the same (or compatible) pinout — but due to the addition of the backup battery, it’s in a 600-mil (0.6″) wide format instead of 300-mil. The 32kB SRAM chips we’ve used over the years have come in both formats — and both work well on a breadboard. However, the original prototype uses a 300-mil socket. Re-wire-wrapping it would be a boring, tedious weekend project with a real risk of breaking things.

The most efficient solution (the one which would have it working by the next lecture and which didn’t involve FedExing exotic adapter PC boards overnight) was to hack together an adapter out of stripboard. It actually turned out better than I was expecting.

The NVSRAM unit next to its adapter

This almost solved the problem. The row connectors I used for the 300-mil pins were too big to fit in the DrACo’s wire-wrapped socket. Fortunately, a pair of DIP14 sockets were just the right size to fit in the socket and accept the new contraption.

The whole works, in place on the DrACo/Z80.
It looks weird, but it works!

It’s weird, having 32kB of memory space that won’t go away. Now I need to figure out what to do with it. For now, I’m running a short program to zero it all out.

What uses do people have for so many thousands of bytes of memory, anyway…??

Posted in Digital, DrACo/Z80, Drexel, EET325, Toys | Leave a comment

Meta-tool

One of the most interesting and useful things about 3D printers is that they’re meta-tools — tools that can be used to make new tools.

I recently needed to adjust the suspension on the e-bike I’m building, but found it quite awkward to turn due to a combination of spring stiffness, inaccessibility, and small diameter. It would be difficult to get slip-joint pliers around it, and turning it by hand wasn’t feasible.

It’s technically a hand-adjustable mechanism, but is already a lot more than finger-tight.

After a few quick measurements, I drew up a first draft of a bit to fit over the adjustment nut. This took a few iterations to get right due to the unusual shape, but eventually I had an outline that would fit over the nut.

I added a handle to turn the current design into a wrench, printed it, and tried it out. It fit, but the force needed to turn the nut immediately bent the plastic out of shape. Version 1.0 looked like the right tool, but needed to be much stronger.

Keeping the center free to slip around the shock absorber body, I added as much material as possible and printed the resulting model at 80% infill with four outer shells. This did the trick, and the resulting wrench is usable enough that it’s going in the bike’s tool bag.

The printed wrench (version 2.0).
Suspension readjusted to account for rear-mounted battery pack.
Posted in 3D Printing, Tools | Leave a comment