Skip to content

Buttons and knobs

A button looks like the simplest input there is: pressed, the pin reads 1; let go, 0. But a button is a mechanical thing, pressed by a person whenever they like, and a clocked circuit wants its inputs to change only between clock edges, cleanly, once. This page gets the carrier board’s four buttons and its knob into the computer properly, and then uses three pins to drive the twenty LEDs and segments.

The button’s pin can change at any moment, including the instant of a clock edge. A flip-flop that samples an input as it changes can be left undecided, neither 0 nor 1, for a while: it’s metastable, as on Clocked circuits. If that undecided value reaches two parts of the circuit, one may see a 0 and the other a 1.

The cure is the same as there: pass the input through two flip-flops before anything uses it. The first may go metastable now and then, but it has a whole clock period to settle before the second takes its value, and the chance it hasn’t is tiny. Every input from outside goes through a pair like that in buttons.v:

reg [6:0] s1, s2;
always @(posedge clk) begin
s1 <= {enc_b, enc_a, enc_sw, btn}; // the pins, as they are
s2 <= s1; // a clock later: safe to use
end

The second problem is the button itself. Its contacts are two pieces of springy metal, and when they meet they bounce apart and together again a few times before they settle, over a millisecond or several. A program that counts presses by watching the pin counts every bounce.

A button pressed (or let go, the next time) at 3 ms, with its contacts bouncing, as a typical switch’s do: the pin, the debouncer’s looks once a millisecond (filled: it read 1), and HELD, which changes once. This is the emulator’s model of buttons.v, the same logic. Each press bounces differently.

buttons.v debounces the buttons: it looks at each one only once a millisecond, keeps its last four looks, and believes a change only when all four agree. A bounce is over long before four looks have passed, so HELD changes once, 4 to 5 ms after the contacts settle: soon enough that nobody notices. Here’s that logic for one button, looking every 4 clocks instead of every millisecond so it’s quick to step through:

The debouncer, simulated gate by gate. Set pin to 1 and clock: s brings it into the clock’s time, tick counts to each look, hist keeps the last four, and held turns on at the look after hist is all ones. Flick pin back to 0 for a clock or two before it’s believed, a bounce, and held doesn’t change.

There are other ways to debounce. A capacitor across the switch, with a resistor, slows the pin’s changes so the bounces smooth out (then a Schmitt-trigger input turns the slow edge back into a clean one). Software can do it too, reading the pin every few milliseconds. Doing it in gateware costs a few dozen logic cells and nothing on the board.

A program that polls HELD might miss a quick press: if it’s busy for 50 ms, a 30 ms tap comes and goes between two looks. So, like part 2’s button, the device keeps a second register, PRESSED, with a bit set for each button the moment its press begins (HELD going from 0 to 1), and left set until the program clears it. The program writes 1s to the bits it has seen; a write leaves the others alone, so a press that arrives while it’s handling another isn’t lost. And a bit set in both PRESSED and IRQEN interrupts the CPU.

AddressRegister
$8020HELDbits 0–3: buttons 1–4 held now; bit 4: the knob’s push switch
$8021PRESSEDthe same bits, set when a press begins; write 1s to clear them
$8022IRQENthe same bits: interrupt while that bit of PRESSED is set
$8023KNOBthe knob’s count of clicks (write to set it)

The computer with the buttons and knob at $8020. Count the presses shows which buttons are held on the LEDs, and counts each one’s presses on the digit above it, however hard you press. The knob shows the knob’s count in hex on the right two digits and as a light along the LEDs; push the knob to set it back to 0. (The page’s buttons don’t bounce; a real one’s would, and the gateware would take care of it.)

The knob turns forever in either direction, with a click (a detent) every so often, about 20 to a turn. Inside are two switches, A and B, worked by the shaft, opening and closing a quarter of a click apart. Turning it makes them step through four combinations, and the order says which way it’s going:

  • clockwise, B and A go 00, 01, 11, 10, and round to 00;
  • anticlockwise, the other way: 00, 10, 11, 01, 00.

Only one switch changes at each step. A sequence like that, where neighbours differ in a single bit, is a Gray code, and it’s what makes the encoder reliable: there’s never a moment where two switches are both changing and might be caught half way.

The knob’s switches: step it a quarter of a click at a time, or a whole click. The square shows the Gray code’s four states, with the one A and B are in now; the waveforms show the last changes. Each step one way round the square is +1 towards a click, the other way −1, and four make a click: KNOB counts. Tick the contact bounces and each step’s changing switch flickers back once before it settles: −1, then +1 again, and the count is unharmed.

That last point is why the encoder needs no debouncing. A bounce can only flick the one changing switch back and forth between two neighbouring codes: a step forward, a step back, a step forward. The steps cancel, however many bounces there are. Here’s the decoder, as it is in buttons.v:

The knob’s decoder, simulated gate by gate. Go round clockwise, one change a clock: a to 1, then b to 1, then a to 0, then b to 0. part counts the steps, and knob goes up by one at the fourth. Go back the other way and it comes down. was is A and B a clock ago, which the decoder compares with now.

Some encoders give two changes a click, or one; the gateware’s STEPS parameter says how many. And the knob’s shaft is a button too: push it, and it’s bit 4 of HELD and PRESSED, debounced like the others.

The little computer has eight LEDs and four 7-segment digits. Wired straight to the FPGA they’d take twenty pins: 8 for the LEDs, 8 for the segments, and 4 to choose which digit is lit (the four digits share the segment pins, taking turns faster than the eye can see: machine.v lights each for 0.7 ms in turn). The UPduino has 31 pins to spare in all, and the carrier board wants them for other things.

A shift register trades pins for time. The 74HC595 has a row of eight flip-flops: on each rising edge of its clock pin, every bit moves one place along, a new one comes in from the data pin, and the last one goes out to the next chip. Three of them in a chain are 24 places, fed by one data pin and one clock pin. Each 595 also has a second row of eight flip-flops, which is what drives its outputs: a pulse on its latch pin copies the whole first row into it at once. So while the bits are shifting through, the LEDs don’t flicker; they change all at once, when the latch says.

Three 595s in a chain. Set the LEDs (a number, one bit an LED) and a digit, then shift the bits in one at a time: each clock pulse moves every bit one place to the right, a new one coming in at the left, the last chip’s first. The outputs only change when you latch. shift595.v does this over and over, 4 clocks a bit: 24 bits and a latch, 100 clocks of 12 MHz, a whole refresh every 8.3 µs.

The program doesn’t know any of this happens. It still writes the LEDs to $8000 and the digits to $8004–$8007; machine.v still multiplexes the digits; shift595.v takes the twenty signals as they are and sends them out, a thousand times faster than the digits change. Three pins and 59 logic cells instead of twenty pins: a good trade when pins are short. (Going the other way, many inputs into few pins, there’s the 74HC165, which loads eight inputs at once and shifts them out.)

  • An input from outside goes through two flip-flops first, so a change at the wrong moment can’t leave the circuit undecided.
  • Contacts bounce; a debouncer believes a change only after several looks agree. buttons.v looks once a millisecond, four times.
  • A PRESSED register latches each press until the program has seen it, and can interrupt.
  • A rotary encoder has two switches stepping through a Gray code; the order gives the direction, and bounces cancel themselves.
  • A chain of shift registers turns three pins into as many outputs as there are chips, with a latch so they change together.
  • Jack Ganssle, A Guide to Debouncing: measurements of real switches’ bounces, and many ways to deal with them.
  • The 74HC595’s data sheet (from any of its makers): its timing, and its current limits.