Getting started · Chips
Chip tutorial 1: quadrature encoder theory
A/B Gray code, direction, and distance — the mechanical and electrical problem before any RTL.
Last edited: September 21, 2026

You want a small digital chip that knows which way a slotted disk is turning and how far it has gone, then hands that position to a host over I2C.
Direction is not in either waveform alone. It lives in which of A and B leads. At 180° electrical, B is the inverse of A, only two of the four states ever appear, and direction is gone. A once-per-revolution index, Z, does not add a step. It loads the fixed middle of the unsigned range, 0x80000000, so travel remains in both directions. Later parts have to honor that contract. Nothing here is a mask.
The disk the chip never draws

Slotted encoder disk on a shaft. Two optical interrupters, A and B, watch one ring of holes about 90° electrical apart. A third mark, Index Z, fires once per revolution. A, B, and Z are the chip's digital inputs.
A hole in the gap lets light through and the digital output sits at one level. Solid material flips it. Place A and B on the same radius so that when A is in the middle of a hole, B sits near a hole edge. Their waveforms then sit about a quarter of one hole period apart. That quarter cycle is electrical degrees of the hole pitch, not 90° of shaft rotation. The drawing shows a few slots. Tutorial examples use on the order of 50 to 1000 holes.
On a real disk, watch one hole period and count the AB combinations. You want all four, in order, with uneven time still allowed. If B is only the inverse of A, you have wired a differential pair, which is the right trick for noise on one channel and the wrong trick for direction. Keep that pair off the quadrature inputs.
One sensor cannot say which way
A single interrupter says that something moved. Reverse the shaft and the pulse train looks the same. Software that assumes forward then walks the position the wrong way, and homing lands on the wrong side of travel. Two sensors fix that when their electrical phase is near a quarter cycle. In one rotation direction A's edges lead B's. In the other, B leads A. The decoder does not measure the lead in nanoseconds. It only needs to see which legal two-bit state follows which.
The Gray ring, counted on both edges of A
Treat A and B as two bits. As the disk turns smoothly, only one bit should change at a time:
00 → 01 → 11 → 10 → 00
Walk the ring one way for one rotation direction and the other way for reverse. A simultaneous jump such as 00 → 11 is noise, bounce, or a missed sample.

Ideal quadrature near 90° electrical. Forward: A leads B. Reverse: B leads A. Arrows mark the ×2 policy: both edges of A count, and B supplies direction.
This series counts both edges of A and uses B for direction. With 100 holes you get 200 steps per revolution. Counting every A and B edge is common in industrial peripherals. We stay at both edges of A so the table stays small. Rising edges of A alone would throw away half the motion A can report.

Legal steps change exactly one bit. One sense of the ring increments. The opposite decrements. Diagonal jumps are illegal at the sample instant.
Hardware keeps the previous synchronized sample of A and B and compares it with the new sample. Same state: do nothing. A neighbor on the ring: add or subtract one, in the sense you document. A diagonal: leave the count alone and optionally set a sticky error. Swapped A and B wires still produce a clean counter, with the opposite idea of forward. Write which way is plus one, and do not flip the table later. If the clock samples slower than the edges arrive, legal neighbors collapse into diagonals. Fix the sample rate. Do not rewrite the ring.
Eighty degrees still works. One hundred eighty does not.
Ideal 90° is a target, not a requirement for the ring to be readable. At 80° or 100° electrical the four states still appear in order. Only the time spent in each state becomes uneven. Direction survives.

(a) 80° and (b) 100° still walk all four states, with uneven intervals. (c) At 180°, B is the inverse of A. Only two combinations appear, so direction cannot be recovered.
At 180° you are back to one channel dressed as two wires. That failure is different from a differential A and A-not pair, which is intentionally 180° so a receiver can reject noise on a long cable. Differential signaling protects one bit. Quadrature needs two bits near a quarter cycle. Mixing those two uses of 180° is how a sensor gets wired so that it pulses and never says which way.
Index loads the middle. The ends saturate.
Power-up leaves an incremental count arbitrary until you home. When Z is qualified, the position register loads 0x80000000. There is no writable mid-scale register. Software that wants a different home subtracts an offset in the host.

The position register is an unsigned 32-bit counter. It saturates at 0 and at all-ones. It does not wrap. An Index Z event loads 0x80000000.
Further reverse steps at zero leave the count at zero. Further forward steps at all-ones leave it at all-ones. Wrapping hides a runaway axis. Saturate-and-hold makes the end of the numeric budget visible. Motion that reverses after a saturate end walks the count back into the interior. Loading zero on the index would sit on that floor for any reverse motion. The middle leaves headroom both ways.
What one step is worth
Resolution here is how much shaft travel one counter step represents. Accuracy is whether the real edge lands where the geometry promised. A fine counter does not invent a precise disk.
With both edges of A counted, steps per revolution are twice the hole count. Treat diameter d as the teaching stand-in and resolution as π·d divided by the step count. Four teaching rows:
| Holes | Diameter | Steps/rev | Resolution | uint32 range | uint16 range |
|---|---|---|---|---|---|
| 100 | 20 mm | 200 | 0.314 mm | ~1349 km | ~20.6 m |
| 400 | 5 mm | 800 | 19.6 µm | ~84 km | ~1.29 m |
| 50 | 100 mm | 100 | 3.14 mm | ~13500 km | ~206 m |
| 1000 | 25 mm | 2000 | 39.3 µm | ~169 km | ~2.57 m |

Four geometries at this decode policy. The uint16 column is contrast: the same disk can exhaust 16 bits in meters while 32 bits still have kilometers of numeric headroom. This chip uses 32 bits.
The register read, high byte first
I2C here is a two-wire bus for a short board link. SCL is the clock, driven by the host. SDA carries address and data. Both lines are open-drain: a device may pull a line low and must not drive it high. Pull-up resistors return idle lines high. The chip is a slave only, at 7-bit address 0x42. A first bring-up uses the classic 100 kHz mode.
To fetch the position, the host writes a register pointer and then reads. The outline is START, address 0x42 with the write bit, the register address, a repeated START, the address with the read bit, the count bytes, a master NACK on the last byte, and STOP.

Host register read: START, address plus write, register pointer, repeated START, address plus read, count bytes, master NACK, STOP. The drawing labels those count bytes MSB then LSB.
The count bytes on that read go out most-significant byte first, then down to the least-significant byte, which is what the drawing labels under the data slot. A host that assembles the first byte as the low eight bits will build a position the chip did not hold. Read all four bytes in one transaction after the pointer write latches the count. Mixing single-byte reads while the disk is moving assembles a value from two different moments.
| Offset | Name | Access | Role |
|---|---|---|---|
0x00–0x03 |
COUNT |
R | 32-bit position; on the wire, MSB byte then LSB byte |
0x04 |
STATUS |
R | sticky illegal transition |
0x05 |
CTRL |
R/W | soft clear of count, status, or both |
Z always loads 0x80000000. Part 2 turns the ring, the saturation, and this read into RTL and checks them in simulation before any layout work begins.
Continue exploring
-
Chip tutorial 2: Verilog and simulation
×2 Gray decode, saturating uint32 counter, Z mid-load, and an Icarus self-check you can run locally.
-
From idea to something a shop can print
How a napkin sketch becomes a file, a cover letter, and a glass plate a shop can print from.
-
LVS: layout versus schematic, and how to read the report
Schematic and layout describe one circuit in two languages. How LVS extracts nets from polygons, a LayoutEditor script that checks a layout against a SPICE netlist and against a schematic, and how to read opens, shorts, and device mismatches.
-
GDSII in plain language
A 1970s suitcase that still carries almost every chip drawing on Earth.
-
Paths in layout: centerline, width, end caps, and bends
A layout path stores a centerline and one width. How end caps and corners are built, when a path turns into a polygon, and how a wrong cap causes an open or a short.
-
Design rules and DRC: real rule values and how to read a marker
Design rules are the factory's limits in numbers; DRC is the spellchecker that measures them. SKY130 width, space, and enclosure values, rule flags, how to write and test a .ledrc rule deck by hand, and why deleting a marker fixes nothing.
-
Database units: how layout files store coordinates as integers
A GDSII or OASIS file stores every coordinate as a whole number of database units. How that scale becomes microns, and what breaks when tools disagree.