Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed
Embedded Systems, 6502 breadboard computer · Lecture 14 of 29 · 28:26
Keyboard Interface Hardware: Triggering Interrupts
Study guide
What this lecture covers
The previous video decoded PS/2 keyboard scan codes with a chain of shift registers and LEDs, but it wasn't yet connected to the 6502's interrupt system. This lecture asks how to make the CPU receive exactly one interrupt per complete 11-bit scan code, rather than one interrupt per bit or an unreliable, noisy signal, and reads the resulting byte from the shift registers.
By the end, you'll understand why triggering an interrupt on every clock pulse is impractical, how an RC circuit with a diode can turn a burst of clock pulses into a single shaped pulse, why that analog-ish signal needs a Schmitt-trigger inverter to become clean digital output, and how the resulting rising edge is used to both latch shift-register data and fire the CPU's interrupt.
Key ideas
- One interrupt per bit is too fast: keyboard clock pulses arrive roughly every 85 microseconds (about 85 CPU cycles at 1 MHz), leaving too little time per interrupt to do meaningful work if every bit triggered one.
- Detecting packet boundaries by timing: since scan codes arrive as bursts of 11 pulses with gaps between packets, a timing-based circuit can detect "end of packet" rather than counting pulses, which is ambiguous when packets run together.
- RC charge/discharge shaping: feeding the inverted clock through a resistor into a capacitor produces a voltage that rises with each pulse and decays between packets, and adjusting resistor/capacitor values changes how sharply it responds.
- Diode for asymmetric charge/discharge: adding a diode across the resistor makes the capacitor charge quickly (holding the signal high through a burst) but discharge slowly through the resistor, producing a cleaner single "hump" per packet.
- Ambiguous mid-range voltage: an ordinary logic inverter (74HC04) has separate thresholds for "high" and "low" but no defined behavior in between, so a slowly decaying signal fed into it produces noisy, spurious extra transitions.
- Schmitt trigger fixes the noise: a 74HC14 Schmitt-trigger inverter has distinct positive-going and negative-going thresholds, so once a transition is detected it "commits" and won't flicker back until the signal crosses the other threshold, cleanly converting the decaying analog signal into one solid digital edge.
- Reusing the interrupt-ready edge: the same clean rising edge that signals "packet complete" is used both to trigger the CPU interrupt and to clock the shift registers' latch, since both should happen once all 11 bits have arrived.
- Reading the scan code: the interrupt handler is changed from just incrementing a counter to reading port A (where the shift register output is wired) directly into the value being displayed, confirming that scan codes like
29(space) and1C(A) appear correctly.
Walkthrough
Recap and connecting the keyboard to the interrupt line (0:00)
The lecture reviews the previous shift-register decoding setup and explains the goal: trigger a CPU interrupt on every keyboard clock pulse and read the data pin, similar to the earlier button-interrupt demo.
Designing the hardware: why per-bit interrupts don't work (1:22)
Measuring the clock period on the oscilloscope shows pulses arriving roughly every 85 microseconds (85 CPU cycles), too fast to usefully service an interrupt per bit, and counting pulses alone can't reliably tell where one packet ends and the next begins.
Creating a clean interrupt: the RC circuit (4:45)
An inverted clock signal is fed through a resistor into a capacitor to ground, producing a voltage that ramps up during a burst of pulses and decays afterward, with different resistor values tried to shape the response.
Fine-tuning the timing with a diode (6:47)
A diode placed across the resistor, oriented to allow fast charging but slow discharging, produces a signal that stays high through a whole scan-code burst and then decays gradually, giving one identifiable pulse per packet.
Addressing signal noise (14:17)
Feeding the shaped analog signal into an ordinary 74HC04 inverter produces a noisy, jittery output, because the chip's undefined behavior in the mid-range voltage band causes multiple spurious transitions as the signal decays through that zone.
Using a Schmitt trigger (17:37)
Swapping in a pin-compatible 74HC14 Schmitt-trigger inverter, which has separate high-going and low-going thresholds, eliminates the noise and produces one clean digital pulse per scan code, verified by pressing keys and seeing exactly three counted interrupts (press, then two release codes).
Implementing the shift register and reading keyboard data (21:41 and 25:00)
The keyboard's data line is wired into cascaded 74HC595 shift registers, using the same clean rising edge both as the shift registers' latch clock and as the CPU interrupt trigger. The interrupt handler is updated to read port A (the shift register's output) into the displayed value instead of just counting interrupts, and the peripheral control register is set for a rising-edge interrupt. Testing confirms scan codes like 29 (space, printed as 41 decimal) and 1C (A, printed as 28 decimal) are read correctly.
Before you watch
- Watch the two previous videos in this series: "Hardware interrupts" (for IRQ/interrupt basics) and "So how does a PS/2 keyboard interface work?" (for the shift-register decoding and scan code format).
- Some familiarity with basic RC (resistor-capacitor) charging behavior is helpful, though the lecture demonstrates it visually with an oscilloscope.
Check your understanding
- Why is triggering an interrupt on every keyboard clock pulse impractical given the CPU's clock speed?
- How does the RC circuit with a diode turn a burst of 11 clock pulses into a single shaped pulse?
- Why does an ordinary inverter produce a noisy output when fed a slowly decaying analog signal, and what specifically does a Schmitt trigger do differently?
- Why can the same rising-edge signal be used both to trigger the CPU interrupt and to clock the shift registers' latch?
- What change was made to the interrupt handler to read an actual scan code instead of just counting interrupts?
Chapters
- 0:00 Interfacing a PS2 keyboard
- 1:22 Designing the hardware
- 4:45 Creating a clean interrupt
- 6:47 Fine-tuning the timing
- 10:30 Refining with a diode
- 14:17 Addressing signal noise
- 17:37 Using a Schmitt trigger
- 21:41 Implementing the shift register
- 25:00 Reading keyboard data
From the YouTube description
Check out https://eater.net/6502 for more 6502 goodness
Support these videos on Patreon: https://www.patreon.com/beneater or https://eater.net/support for other ways to support.
------------------
Social media:
Website: https://www.eater.net
Twitter: https://x.com/beneater
Patreon: https://patreon.com/beneater
Reddit: https://www.reddit.com/r/beneater
Special thanks to these supporters for making this video possible:
Aleksey Smolenchuk, Alexander Wendland, Andrew C. Young, Anson VanDoren, Anthanasius, Armin Brauns, Asherah Connor, Ben Cochran, Ben Dyson, Ben Kamens, Ben Williams, Bill Cooksey, Binh Tran, Bouke Groenescheij, Bradley Pirtle, Bradley Stach, Brent Reusing, Brian T Hoover, Bryan Brickman, Bryan Glezerson, Carlos Ambrozak, Christopher Blackmon, Clint Bridges, Dale Andrew Darling, Daniel Jeppsson, Daniel Tang, dans, Dave Burley, Dave Walter, David Brown, David Clark, David Cox, David House, David Sastre Medina, David Turner, David Worsham, Dean Winger, Dissy, dko, Dmitry Guyvoronsky, Dušan Dželebdžić, Dzevad Trumic, Emilio Mendoza, Eric Dynowski, Erik Broeders, Eugene Bulkin, George Foot, George Miroshnykov, Harry McDow, Ian Tait, Ingo Eble, Ivan Sorokin, James Capuder, james schaefer, Jared Dziedzic, Jason DeStefano, Jason Specland, JavaXP, Jaxon Ketterman, Jay Binks, Jayne Gabriele, Jeremy A., Jim Kelly, Jim Knowler, Jim Van Meggelen, Joe Beda, Joe OConnor, Joe Pregracke, Joel Miller, John Fenwick, John Meade, Jon Dugan, Joseph Portaro, Joshua King, Jurģis Brigmanis, Kai Wells, Kefen, Kenneth Christensen, Kent Collins, Kitick, Koreo, Lambda GPU Workstations, Larry, László Bácsi, Lucky Resistor, Lukasz Pacholik, Marcos Fujisawa, Marcus Classon, Martin Roth, Mats Fredriksson, Matt Krueger, Matthäus Pawelczyk, melvin2001, Michael Tedder, Michael Timbrook, Michael Weitman, Miguel Ríos, mikebad, Mikel Lindsaar, Miles Macchiaroli, moi n, Nicholas Counts, Nicholas Moresco, Nick, Örn Arnarson, Paul Pluzhnikov, Paul Randal, Pete Dietl, Phil Dennis, Philip Hofstetter, Phillip Glau, PixelSergey, ProgrammerDor, Randal Masutani, Randy True, raoulvp, Renaldas Zioma, Ric King, Rob Bruno, Robert Comyn, Robert Diaz, Roland Bobek, sam raza, Scott Holmes, Sergey Kruk, SonOfSofaman, Stefan Nesinger, Stefanus Du Toit, Stephen, Stephen Riley, Stephen Smithstone, Steve Jones, Tayler Porter, TheWebMachine, Tom, Tyler Latham, Vincent Bernat, Vladimir Solomatin, Walter Montalvo, Warren Miller, Wraithan McCarroll, xisente, Yee Lam Wan
← How a PS/2 Keyboard Interface Works · Keyboard Interface Software: From Scan Codes to Characters →
