Full-sized keyboard with single MCU

I built a number pad keyboard based on 5x4 keyboard matrix using Pro Micro and it seems works well.

Now, I want to build full-sized keyboard. Since a full-sized keyboard has over 100 keys, I need 21 pins at least for 11x10 matrix. Additionally, if I want to add other features such as rotary encoder or OLED display, it is totally over the GPIO count of any Pro Micro compatible size MCU boards.

I found a way to implement keyboard 42 keys with only 7 pins by alternating scan instead of 6x7 matrix here: Keyboard Matrix Reduce I/O - #8 by PaulRB

With this method, only 11pins required to implement full-sized keyboard.
And, before using this method, I have some questions:

  1. What is the drawback of this method compared to implementation with matrix?

  2. I want to implement sleep/wake functionality. In this schematic, I think it would be possible to connect all pins to a single output pin through diodes. Then, when pressed any key, the output pin pull down all pins. Is it feasible?

  3. With previous method, multiple pins are pulled down simultaneously. Can this cause some kind of race condition of interrupts?

Lastly, any advice implement full-sized keyboard would be appreciated even though it is irrelevant with the question.

Thank you.

I haven't really read the thread you linked, but I'd definitely trust the author. @PaulRB is pretty reliable.

Another thing that could help would be pin expanders. You can get 8 or 16 pins on a chip that talks either I2C or SPI whichever you like. The SPI chips are a little faster but they take 4 pins to run. The I2C chips only need two pins. Additional SPI expanders cost one pin each (they'll share the other three) and additional I2C chips will cost no pins because they can share everything.

Thank you for pin expander suggestion. I have they as option but for some lack of my knowledge, I am putting them in lower priority. My main concerns of using pin expander are:

  1. Is it possible to attach interrupt to wake up on key pressed connected through expander?
  2. Additional communication could slow down scan rate, especially chainning I2C, but I have no idea how slow it is. My debouncing delay is 5ms to 10ms so it won't be a prblem if the latency is under ms order though.
1 Like
  1. Most have an interrupt pin you can take back to the microcontroller. You can pool them all together so it only takes one pin. The one I have the most experience with is the MCP23S08

It's the SPI flavor. It comes in lots of other packages and there's also the MCP2308 which is I2C.

  1. 5ms is an eternity for the SPI bus.
1 Like

128 keys, 12-13 pins used

1 Like

The matrix I was suggesting in that post from 2014 is called a "Charlieplexed" matrix. The advantages are that only a few Arduino pins and no extra chips are needed. The disadvantage is that it can only deal with one button press at a time. That's not a problem for some types of keypad, but it is a problem for QWERTY and music keyboards because those types are expected to deal with multiple keys pressed simultaneously, for example during high speed typing or playing music.

The ability to deal with multiple keys pressed simultaneously is called "Key Rollover". If a keyboard can deal with 5 keys pressed simultaneously, it is called "5-key Rollover". Keyboards that can deal with any number of keys pressed simultaneously are called "N-key rollover".

So if you are building a QWERTY keyboard, the Charlieplexed design won't be suitable for you.

1 Like

Thank you for informative link.

Oops, that is a critical drawback as you pointed out, for a full-sized keyboard. Thank you for clarification. I will find I/O expanding method.

expanded pins you can not use for wake up

It seems that this is way to go. Thanks a lot!

MCP23S08 which @Delta_G mentioned provides interrupt pin. Won't wiring Arduino's interrupt pin to the MCP23S08 interrupt pin and attaching interrupt to that pin work?

good to know

Don't forget that a key matrix must be scanned, row-by-row or column-by-column, to detect which key(s) are pressed. Most I/o expanders will not do this automatically, so the Arduino must do it, and it can't do that when in sleep mode.

However, it may be possible to set the I/o expanders to automatically detect if any key is pressed, but not which exact key is pressed. The Arduino can set the expanders up like this before going into sleep mode. If any key is pressed, the interrupt can wake the Arduino which then immediately begins scanning to figure out which key(s) were pressed.

For this technique to work, it is important that, when not being used, all the contacts of the keys on the keyboard are open. This means you cannot use any kind of latching or toggle switches, and care must be taken when choosing rotary encoders. You must choose rotary encoders which have "detents" and the contacts are always open except when between the detents.

1 Like

That is the exact condition for a wireless keyboard to fall a sleep.

Yes, it is how my keypad works now. As a matter of fact, before going to sleep, all output pins are activated and interrupt will be attached to input pins, and this strategy will be applied in same manner with or without expanders. Or, can I figure out which key in the matrix is pressed when I don't use expander?

I didn't know that there are such variants in rotary encoders. Thank you for lots of advices!

I don't know about others, but the MCP23S08 can be set to give an interrupt if any pin changes and will capture the pin states in a register so even if someone taps a key really fast the microcontroller could still catch it.

That isn't enough, by itself.

During sleep, all the columns would be pulled weakly high and the rows pulled strongly low, for example. That way, if any button is tapped, one of the columns changes from high to low and triggers the interrupt to wake the Arduino. Reading that register would only tell you which column the button was in, but not which row. The Arduino needs to scan the rows to figure that out. If the press is too short or the Arduino does not wake fast enough or scan fast enough, the key could still be missed. But those things should happen fast enough, if the code is efficient.

I don't know if there are any such variants. But that is what you would need, otherwise button presses in the same column as the encoder won't wake the Arduino from sleep.

But I would not recommend making the encoder part of the matrix anyway. It's possible in theory, but it's not easy to scan a large matrix fast enough to avoid losing signals from an encoder when the encoder is turned at high speed.

1 Like

Oh. I thought it wasn't a matrix anymore.

Once I decided to use I/O expander, suddenly I started to think "why should I stop at matrix?".

That is, with lots of MCP23S17 which provides 16 pins, I can make direct 1:1 mapping for each switch. Since it is full-sized keyboard and MCP23S17 is also available in SMD package, there is vast space to place to put MCP23S17 as many as I want.

Specifically, with only 7 MCP23S17s, I can implement full-sized QWERTY keyboard.
The only drawbacks I can think is more current consumption and cost.

However, I am not even sure it actually draws more current because direct pin configuration will require less computing power of MCU to scan matrix instead. If it could increase power consumption significantly, I will give up because my keyboard will support wireless connection too.

Meanwhile, the cost won't be serious problem because MCP23S17 is only about $2 and to spend $14 for seven MCP23S17s is not a big deal for a custom keyboard.

What about implementing direct pin with many expanders instead of using fewer expanders and sticking to keyboard matrix to reduce I/O pins?

1 Like

Oh. I thought it was a matrix... sounds like you were right.

1 Like