I have a project (pinball machine) that will have a decent number of microswitches that will be connected in an 8x8 switch matrix. I'm trying to determine what my options are for reading this matrix without consuming a large number of pins on a microcontroller.

I tried looking for an IC designed specifically for such an application (scanning a large number of buttons) but all I could find is the TCA8418 and TCA8418E chips from TI, looking for similar chips lead me to a couple others but they all share a common problem. They're only in QFN or BGA packages which is beyond my ability to hand solder. I know it's possible, but not something I want to undertake. Those chips are beautiful for this though, it's a real shame.

Alternatively, I've looked at 16 port bus extenders that can be communicated with via I2C or SPI. These seem to be a good option, but I worry about missing button presses. The pinballs will be racing around rapidly, so probably in the millisecond range. That isn't all that fast in terms of an MCU, but it's going to be busy doing a lot more than just reading switches (audio, dot matrix display video feed, and an 8x8 matrix of LEDs). On top of that, it would have to handle switch bounce.

My other concern is the necessary diode that may cause V(il) to creep up towards the 0.8V limit of LVCMOS. A 2x2 example is below.

I've also considered using a small 8-bit microprocessor to be dedicated to keyscanning, it could probably emulate the function of those TCA8418 chips. But I'd have yet more code to write, and another source of bugs to work out. They're about the same price as the bus extender though, so if it's a superior solution than it is what it is.

Is there something else out there, or some method for scanning large (ish) arrays of switches/buttons?


simulate this circuit – Schematic created using CircuitLab

  • \$\begingroup\$ back in 1976 using a slow MC6800 we had to interface 96 switches and 96 LEDs so we used 1:16 decoder and 8bit latch to write and read latches with 1kHz scan rate cycling every 16ms which is about the bounce time of momentary switches ( then debounced in S/W. You may scan faster. WIth low R (e.g. 200R) active terminated bus (V/2), you can use I2C in x Mb/s rates rather than 1k8 pullup for 350kbps \$\endgroup\$ Apr 2, 2018 at 1:43

4 Answers 4


I wouldn't try to get too clever, you'll just make your circuit more troublesome in the long term. Do you really need a switch matrix? Why not just use multiple port expanders or shift registers? Those should be fast enough. If not, many come with an interrupt output which you can hook up to your micro to make it INSANELY fast. That will also eliminate the polling overhead. If you can get away with a micro that has a lot of IO, like the Arduino mega I would go with that instead.

Many port expanders and shift registers are available in dip packages. For example the MCP23017-E/SP https://www.digikey.com/product-detail/en/microchip-technology/MCP23017-E-SP/MCP23017-E-SP-ND/894272

And here's a shift register you could use: CD4021B https://www.digikey.com/product-detail/en/texas-instruments/CD4021BE/296-2040-5-ND/67261

You can easily daisychain multiple shift registers together to get as many inputs as you need.

Tutorial: https://www.arduino.cc/en/Tutorial/ShiftIn

  • \$\begingroup\$ I would second "don't get too clever", and simple 8 bit cd or 74hc series cmos shift registers. Personally I think that better than a zillion pin micro - more robust,repairable, and easier to change micros. But if you do want to get too clever: 11 micro port pins can read 110 switches (with diodes). Generally M pins can read M*(M-1) single switches \$\endgroup\$
    – Henry Crun
    Apr 2, 2018 at 6:47
  • \$\begingroup\$ That's a solution I hadn't considered, and you're right it would work. It does come with a tradeoff though. With a matrix there are only 16 connections to the "motherboard". Taking them out of the matrix results in 128 connections which is significantly larger. That would significantly increase the complexity of assembly. \$\endgroup\$
    – Geomancer
    Apr 2, 2018 at 21:24

You have not stated what you intend to connect the "scanning" circuit block to.

Any reasonably fast micro can do the scanning and anything else you might have in mind. Just drive the scan routines with a periodic interrupt that is fast enough. For example, you might choose to scan a row every 100us, which would give you a scan rate of 800us for the entire array. It can deposit the key states into an 8-byte array which you can work with to implement the desired functionality. You can also implement a debounced array which will respond slower, necessarily, as microswitches can bounce for quite some time.

Doing it in a dumb way only takes 11-16 port pins. If you use a 1 of 8 decoder (eg. 74HC138) to decode the column, then you only need 3 pins to address that, and then 8 pins to read the row.

CMOS threshold is typically 0.3/0.7 Vcc so even with a 3.3V supply you have 1V to play with. Use Shottky diodes as you show and you'll have plenty of noise margin. HCT (TTL) level inputs are fairly rare these days.

Microswitches may not be reliable switching such small currents unless you specify ones that have precious-metal contacts. If you just try to use existing ones that have spent their life arcing and switching solenoids or whatever you may have issues unless you use relatively high voltages and currents through the switch matrix, but that is outside the scope of this question and my answer.

  • \$\begingroup\$ The MCU is an ARM Cortex M4. The potential issue is that the MCU must keep the audio buffer fed and continue to drive the video feed (which as I mentioned has no buffer/memory). If the MCU spends too much time in an interrupt, the audio will pop and the display will flicker. I'm sure I'm overthinking it and the MCU will have plenty of time, but before I start buying parts I figured I'd ask around to see if I'm missing anything. \$\endgroup\$
    – Geomancer
    Apr 2, 2018 at 21:26
  • \$\begingroup\$ You're using DMA channels, right? My first step on something like this would be to grab an eval board and code the skeleton of what is required. \$\endgroup\$ Apr 2, 2018 at 21:47
  • 1
    \$\begingroup\$ Reading in a 8bit port should be a single clock cycle... this should be the fastest action to do... \$\endgroup\$
    – MadHatter
    Apr 3, 2018 at 0:05
  • \$\begingroup\$ @MadHatter Read the port, set up the column decoder for the next read and then go off and do other stuff for a bit- several sequential actions. \$\endgroup\$ Apr 3, 2018 at 9:48

If you want to use an 8 X 8 matrix to read the switches then you could use an IO expander chip such as the MCP23S17. It will give you 16 IO pins in exchange for four SPI bus pins.


All 16 pins are configurable as input or output via an internal register. You can also optionally enable internal pull-up resistors so you may not need to put separate ones on the board.

A single register access takes 24 SPI clock cycles. You would need to do 16 such reads to scan the whole matrix, so 384 SPI clock cycles (48 byte transfers). You can clock the SPI bus on the MCP23S17 up to 10MHz, so you are looking at 38.4us of SPI transfer time to read all the switches.

If you make the SPI transfers interrupt driven then you are looking at servicing 48 interrupts lasting less than 1us each every 1ms. You can just schedule the interrupts to occur once every 20us and put them at low priority so they don't interfere with the audio or lights if they are also interrupt driven. On the other hand, an occasional 1us delay probably won't interfere too much with the audio and lights if you are doing those in the main loop.

Alternatively you could do all the SPI transactions as a block in your main loop. You could probably expect the code to take somewhere near 50us if you did it that way. 50us every 1ms amounts to 5% of your CPU time. Again, just service the audio and lights in interrupts and the SPI stuff won't interfere with it.


Markoplexing is an interesting take on Charlieplexing and other scanning techniques;


Alternatively you could connect the switches to analogue inputs and use a standard resistor-ladder style setup to read all of them with very few pins.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.