Author Topic: Keyboard / Switch Matrix - H/W Debounce + Multiplexer  (Read 1885 times)

0 Members and 1 Guest are viewing this topic.

Offline eevdudeTopic starter

  • Contributor
  • Posts: 14
  • Country: pl
Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« on: January 07, 2022, 05:44:42 pm »
Hi everyone - hope you all had a good start to the year. I'm back now i have a few days to play around and have some more questions for you knowledgeable peeps :)

 What i would like to do is make a highly responsive keyboard matrix, that i can extend easily, requires no startup configuring (so no fpga) and fairly simple / cheap to implement. This is probably going to be highly controversial, but I've done a lot of software debouncing and am not that keen on it for larger number of switches that can be pressed at once - and the small mcu's i've used spend most their time debouncing switches, and to get minimal lag can be tricky (especially when you've implemented multiple functions with a handful of switches). I've looked at shift registers, decoders, large i/o mcu's etc.

So as per the digikey page (and others) on hardware debouncing, i'd like to try that (RC + schmitt inverter) just if anything to try it out. Now as the switches themselves won't be being scanned in a matrix (wouldn't work with the hardware debouncing), i figured i could read all the switches in a row by using a 16-1 multiplexer, and if i used 5 multiplexers, i could use 4 pins for address and 5 pins for reading 1 key from every column at the same time. No deboucing needed, i could scan 5 keys (1 column per row) at once, and simply step through all 16 address bits to scan - seems too simple (apart from the additional hardware routing & costs).



But i have a few questions -

Should this function as i imagine it will? I can test it on a breadboard with a couple of switches when the chips turn up, but what about 5 multipexers (80 switches) - any potential issues?

I've seen the calculation for timing (RC circuit) - but as a diode has been added to assist with capacitor charging, how to account for that - for instance  5ms, 10ms or 20ms? (also the schmitt inverter can only take max 20ma, so R1 would need to factor that in?)

Is there a way to work out the approx maximum delay from a switch being pressed, to it being read by an MCU? I can understand some of the terms in the datasheets, but trying to work out a worst case time is a bit beyond my skill.

Anything else i might have missed?

Thanks for any advice :)
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 6231
  • Country: de
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #1 on: January 07, 2022, 07:47:56 pm »
You're still in "scanning mode".
There's a more elegant way of doing this with static logic, but it will require at least 10 16-pin ICs (vs. 5 24-pin ICs for the same function, meaning approximately the same PCB area. You'll probably need a couple of more ICs for further decoding, unless your MCU can take of that.

The solution is "Priority Encoders", eg, MC14532 or 74HC148. They will encode 8 single inputs to a 3-bit binary output and can be cascaded at will, also up to 80 bits or more. If you need modifier keys like "Ctrl", "Alt", "Shift" etc. you can connect these in a separate priority encoder for special processing.

The devices will output a strobe signal when a key is pressed.
You MCU can then decode the binary output from the priority encoders.
The beautiful thing is, that the MCU only has to do debouncing (for all keys) once per key press. Fully and easily configurable in software.
Also that pressing several keys at once (eg, QWERTY) will only give the output of the highest prioritized key. No ambiguities are possible.

Check it out.

Cheers.
« Last Edit: January 07, 2022, 07:55:29 pm by Benta »
 
The following users thanked this post: eevdude

Offline eevdudeTopic starter

  • Contributor
  • Posts: 14
  • Country: pl
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #2 on: January 07, 2022, 08:22:06 pm »
Thanks for pointing me to those - i had search for something similar earlier, but missed the priority bit (and i think i was searching 16 to 4 encoders).

I could definitely use that, but why would the modifier keys need to be handled differently? Does it make it easier if you want to adjust the keycode at the end?

I will have a think about the software debouncing - i've seen keys with upto 10-15ms jitter (especially if you rapidly hit the keep over and over), the only way i could read them with any kind of push accuracy was to accept the first high (or low) pulse, and then wait 20ms before checking that key again (so you get accuracy on pressing, but not releasing). May need to push the boat out on a decent mcu.
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 6231
  • Country: de
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #3 on: January 07, 2022, 08:35:49 pm »
but why would the modifier keys need to be handled differently? Does it make it easier if you want to adjust the keycode at the end?

Because they would be held while another key is being pressed, meaning two (or more) keys are active. The priority logic would only provide one key code.
You'll probably need to group all "normal" keys in one priority encoder chain, and treat Ctrl, Shift, Alt and Alt-Gr separately. You also have Ctrl+Alt and perhaps Shift+Ctrl, Shift+Alt or perhaps even Shift+Ctrl+Alt to deal with.

« Last Edit: January 07, 2022, 08:40:14 pm by Benta »
 

Online mariush

  • Super Contributor
  • ***
  • Posts: 5136
  • Country: ro
  • .
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #4 on: January 08, 2022, 12:58:59 pm »
What is "fairly simple / cheap to implement" to you?  When keyboards sell for 2-300$ these days, cheap can be relative.

If you're not afraid of less common / potentially hard to source in the future parts, Digikey has 40+ bit port expanders you could use...

1. 2.8$ each Pericom / Diodes Inc PI4IOE5V96248ZLEX 48 bit port expander with i2c  and 5v tolerant i/o : https://www.digikey.com/en/products/detail/diodes-incorporated/PI4IOE5V96248ZLEX/7802377

2. NXP PCA9505 / PCA9506  (9505 has buit in 100kOhm pull up resistors)  40 bit port expander with i2c :
qdn : https://www.digikey.com/en/products/detail/nxp-usa-inc/PCA9506BS-118/1154224
tssop : https://www.digikey.com/en/products/detail/nxp-usa-inc/PCA9506DGG-518/1157017


 

Offline eevdudeTopic starter

  • Contributor
  • Posts: 14
  • Country: pl
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #5 on: January 08, 2022, 07:09:06 pm »
What is "fairly simple / cheap to implement" to you?  When keyboards sell for 2-300$ these days, cheap can be relative.

Good point, i think i'd like to be around 100usd - but with reasonable latency,>2kro, not planning to go super high end on anything though. I might build a couple of different layouts, depending on cost.

Those expanders might work, good point about future supply issues, will look them over. Would that be x2 for 80 keys or some kind of matrix?

Definitely open to new ideas - but i'd still be interested in finding out how/if i could use those 40c multiplexers in the way i imagined with a low end mcu (although if you have to use schmitt inverters thats about $4).
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6865
  • Country: fi
    • My home page and email address
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #6 on: January 08, 2022, 08:32:46 pm »
This is probably going to be highly controversial, but I've done a lot of software debouncing and am not that keen on it for larger number of switches that can be pressed at once - and the small mcu's i've used spend most their time debouncing switches, and to get minimal lag can be tricky (especially when you've implemented multiple functions with a handful of switches).
I wouldn't say controversial, but it does sound odd to me.

I've done a few keyboard/gamepad projects, and prefer to use a zero-latency dead-time counter for debouncing.  This requires a byte of RAM per physical key, and since I like to use diodes in my button matrix, I can support all keys individually (no N-key rollover, or alternatively N is the number of keys available).
My preferred microcontroller for these is the ATmega32u4, because I can program it using only open source tools, on bare metal without any vendor stuff, in Linux.
I do also use various Teensies (2.0++, LC, 3.0/3.1/3.2, 4.0, 4.1) in my projects.

The zero-latency dead-time software debouncing I use is really trivial, and only requires that you can the keyboard matrix at regular intervals.  For USB HID, I'd recommend 2kHz scan rate for minimal (~1ms) USB HID latency.  Each physical switch is associated with an integer: one bit for the state, and 7 or more bits for a counter.  When the counter is nonzero, the button state does not change ("dead time"), and each scan just decrements the counter.  Only when the counter is zero, can the button matrix change the button state.  On AVRs with one port as inputs, and another port or counter as outputs, this can be written in assembly to be very fast.

At 10kHz scan rate, 7-bit counter has a resolution of 0.1ms and maximum dead time of 12.7ms.  At 2kHz scan rate (which should still be enough to give you the minimal 1ms USB HID latency) the resolution is 0.5ms and maximum dead time 63.5ms.  Because the dead time counter is initialized to maximum value, you can set different dead times for presses and releases; even separately for each key, if you have the Flash or RAM to store the values to be used.

(Thus, the keypress dead time is the minimum time each key remains depressed, and keyrelease dead time is the minimum time between release and next press of that same key.  This matches human physiology, and yields the best response with minimal/zero latency.  The actual 1ms minimum latency comes from the USB HID protocol itself: each HID device gets one 64-byte transfer slot every millisecond.)

The complex part is if you want to do e.g. USB cyclic rollover since each USB keyboard HID message can only contain up to six keycodes; for this I'd use a separate area to hold currently pressed keys, which is then copied in rolling chunks of six keys to the USB HID reports.
Also, I haven't needed to implement "doubleclick" or "tripleclick" detection at all; that would add another layer of complexity.

Because this has worked so well for me, I suspect you have used unsatisfactory software debouncing methods.
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 6231
  • Country: de
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #7 on: January 08, 2022, 09:07:30 pm »
@Nominal Animal:
Why do you go on about USB? I haven't seen that mentioned anywhere (unless I've misread something).

Now first, the OP wants a non-matrix keyboard. I've shown a possible solution to that (not my favourite, I'll admit, I prefer matrix keyboards myself due to efficiency).

Second, decoding matrix keyboards by scanning seems to many people to be the only way, but in reality it's also inefficient (noise- and timewise).

Static matrix keyboard scanning is my favourite.
It needs I/O ports with pull-up resistors (no problem today) and interrupt capability (also no problem today).
Imagine (for simplicity) a 64-key matrix arranged as 8 x 8.
The 8 columns are connected to an output port A set to 0b00000000.
The 8 lines are connected to an input port B with pull-ups and interrupt capability.
Press a key: IRQ from port B.
Debounce and read port B.
Set port A to input with pull-ups, set port B to output with 0b00000000.
Read port A.
Now you'll have the key coordinates for processing. This will even provide decoding of the simultaneous pressing of several keys.

Easy, no?
 
The following users thanked this post: eevdude

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6865
  • Country: fi
    • My home page and email address
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #8 on: January 08, 2022, 10:34:08 pm »
Why do you go on about USB? I haven't seen that mentioned anywhere (unless I've misread something).
Because OP did not provide any kind of time scales at all, and it was the only benchmark (as to what kind of latencies one can achieve in practice) I know of that is trivially available to everyone.  I did not intend to imply that USB HID is the way to go; it is just a measurement stick that should be easy to understand for everyone.

Now first, the OP wants a non-matrix keyboard.
In that case, I misread the initial post: "What i would like to do is make a highly responsive keyboard matrix, that i can extend easily, requires no startup configuring (so no fpga) and fairly simple / cheap to implement. [...] to get minimal lag can be tricky", which I found odd.  All the USB stuff was just for comparison, since it is ubiquitous.  I assumed that things like human reaction times varying from 10ms to 60ms and having <1ms response latency is "instantaneous" are less known, and approaching the possible requirements –– since they're unstated –– from the ubiquitous USB side would be most useful.

I am only a hobbyist on the electronics side, but my projects range from a custom macro keyboard using Teensy 2.0++, Teensy LC button matrix with analog pots, 8-button through-hole isolator with debouncing (for arcade cabinets and such), and a Pro Micro Gamepad (direct, no matrix).  I did also do a CH551G USB gamepad design, but every time I've bought stuff from JLCPCB/LCSC, they didn't have enough CH55xG chips (that can be programmed using SDCC and open source tools), so it is still "untested"; it uses a 4×3 matrix.

Using this zero-latency dead-time approach with both matrix and non-matrix buttons/switches, I've had zero problems.  The fact that OP has had issues with software debouncing, or finds it problematic in some way, is odd to me.

Second, decoding matrix keyboards by scanning seems to many people to be the only way
True, and that is silly.  The main benefit from the matrix scanning method is that as shown by my "designs" above, they are very simple, and the price is ridiculously low, since you only "need" diodes (and them only if you want to avoid key rollover issues); the CH55xG gamepad components cost less than $5 in retail in singles, including nice tactile buttons (the 12x12mm ones).  Teensy LC costs $12 USD, and the matrix board provides connections for 32 buttons and 9 pots, using just 4 0805 resistors and 16 SOT-23 Schottky diode pairs (like BAS70).

but in reality it's also inefficient (noise- and timewise).
That is debatable; consider the CH55xG gamepad as an example.  I think we need some specific requirements and timing goals to compare the various approaches.  Even the ATmega32U4 (Pro Micro clone), active, running at 16 MHz, only consumes max. 30mA.  At 8 MHz, half that, or about the same as one or two indicator LEDs.  Then again, I know nothing of production prices, only what I see as a hobbyist.

I say this, because the cheaper 8-bit microcontrollers (CH55x, AVRs) may not have interrupt capability on sufficient number of I/O pins, or may not support triggering on both edges (on both low-to-high and high-to-low transitions, as opposed to only one of them).  So –– and as you yourself pointed out ––, static matrix tends to require additional hardware (e.g., the priority encoders).

If it matters any, to me, I considered my own post as a separate branch: whether OP's observations of software debouncing are due to software debouncing in general, or whether they simply have used poor SW debouncing algorithms (and my position is obviously the latter).  There could very well be other reasons why matrix scanning is out, but software debouncing, in my practical experience as a hobbyist, is not it.
 

Offline eevdudeTopic starter

  • Contributor
  • Posts: 14
  • Country: pl
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #9 on: January 08, 2022, 10:54:00 pm »
Thanks for the replies - for now i'm not really taking USB into account, for testing may probably end up using it, but for the final solution it will be left out (think some kind of diy hackable arm based computer in a keyboard) - hence the need for some form of i/o expansion (preferable to just stuffing a large mcu as usb isn't needed in the end game).

From my understanding, matrix scanning + debouncing + usb constitues most of the latency in modern keyboards (which seem worse than keyboards/computers 'back in the day'). I've done low latency software switch debouncing before (where you accept the first "pressed" signal you get, then ignore any changes for the next n ms) so pressed has "priority" but released has a delay, it worked ok but took a lot of processing power. I think that would be similar to your method but need to work it out in my head, i guess using bits for counting saves some memory/power could be useful for lower power mcus.

Also the original method i was thinking out loud with multiplexer even is still scanning (as pointed out), although the debouncing would be done in hardware, but the processing loop would be just to

write out 4 bits
read 5 bits
loop 16 times

and you have all 80 keys, pre-debounced, only need 9 i/o, 4 out, 5 in only

but probably it's just some crazy idea and there's good reasons not to ;)
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6865
  • Country: fi
    • My home page and email address
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #10 on: January 09, 2022, 12:07:52 am »
I've done low latency software switch debouncing before (where you accept the first "pressed" signal you get, then ignore any changes for the next n ms) so pressed has "priority" but released has a delay, it worked ok but took a lot of processing power. I think that would be similar to your method but need to work it out in my head, i guess using bits for counting saves some memory/power could be useful for lower power mcus.

Without autorepeat, the basic C dynamic scan loop looks like this:
Code: [Select]
#include <stdint.h>
#include <string.h>

#define  KEY_ROWS   8
#define  KEY_COLS   8

#define  KEYPRESS_SCANS     40
#define  KEYRELEASE_SCANS   40

static uint8_t  key_counter[KEY_ROWS][KEY_COLS];

extern void     key_press(uint_fast8_t row, uint_fast8_t col);
extern void     key_release(uint_fast8_t row, uint_fast8_t col);
extern void     key_set_row(uint_fast8_t row);
extern uint8_t  key_get_col(uint_fast8_t col);

void key_init(void)
{
    memset(key_counter, 0, sizeof key_counter);
}

void key_scan(void)
{
    for (uint_fast8_t row = 0; row < KEY_ROWS; row++) {
        key_set_row(row);
        for (uint_fast8_t col = 0; col < KEY_COLS; col++) {
            const uint_fast8_t  state = key_get_col(col) & 1;
            if (key_counter[row][col] > 1) {
                /* Dead time active */
                key_counter[row][col] -= 2;
            } else
            if (key_counter[row][col] ^ state) {
                /* State change */
                if (state) {
                    key_counter[row][col] = 1 + 2 * KEYPRESS_SCANS;
                    key_press(row, col);
                } else {
                    key_counter[row][col] = 2 * KEYRELEASE_SCANS;
                    key_release(row, col);
                }
            }
        }
    }
}
Autorepeat can be implemented as another layer on top (basically, keeping the set of currently pressed keys in a small array, with repeat counters), or by adding another array (thus RAM requirement increases to 3 bytes per switch/button/key):
Code: [Select]
#include <stdint.h>
#include <string.h>

#define  KEY_ROWS   8
#define  KEY_COLS   8

#define  KEYPRESS_SCANS     40
#define  KEYRELEASE_SCANS   40

#define  KEYREPEAT_FIRST  1000
#define  KEYREPEAT_NEXT    500

static uint8_t  key_counter[KEY_ROWS][KEY_COLS];
static uint16_t key_repeat[KEY_ROWS][KEY_COLS];

extern void     key_press(uint_fast8_t row, uint_fast8_t col);
extern void     key_repeats(uint_fast8_t row, uint_fast8_t col);
extern void     key_release(uint_fast8_t row, uint_fast8_t col);
extern void     key_set_row(uint_fast8_t row);
extern uint8_t  key_get_col(uint_fast8_t col);

void key_init(void)
{
    memset(key_counter, 0, sizeof key_counter);
    memset(key_repeat, 0, sizeof key_repeat);
}

/* Assume called every 0.5ms = 2000 times per second */
void key_scan(void)
{
    for (uint_fast8_t row = 0; row < KEY_ROWS; row++) {
        key_set_row(row);
        for (uint_fast8_t col = 0; col < KEY_COLS; col++) {
            const uint_fast8_t  state = key_get_col(col) & 1;
            if (key_counter[row][col] > 1) {
                /* Dead time active */
                key_counter[row][col] -= 2;
            } else
            if (key_counter[row][col] ^ state) {
                /* State change */
                if (state) {
                    key_counter[row][col] = 1 + 2 * KEYPRESS_SCANS;
                    key_repeat[row][col] = KEYREPEAT_FIRST;
                    key_press(row, col);
                } else {
                    key_counter[row][col] = 2 * KEYRELEASE_SCANS;
                    key_repeat[row][col] = 0;
                    key_release(row, col);
                }
            } else
            if (state) {
                if (!--key_repeat[row][col]) {
                    key_repeat[row][col] = KEYREPEAT_NEXT;
                    key_repeats(row, col);
                }
            }
        }
    }
}
The above examples are written so that
  • key_press(row, col) is called whenever a key is pressed,
  • key_repeats(row, col) is called whenever a key has been pressed so long it is time to emit an autorepeat press,
  • key_release(row, col) is called whenever a key is released,
  • key_set_row(row) is called to set the currently scanned row, and
  • key_get_col(col) is called to read the state of the input pin corresponding column col.
  • (key_counter[row][col] & 1) is 1 if the key is currently pressed, and 0 otherwise.
Note that this way, if you keep both A and Z keys pressed, the autorepeat will yield AZAZAZAZ...

In practice, I don't use the exact above code, but it describes the underlying logic.  Sometimes the keypresses need to be filtered, sometimes you want the autorepeat to do a single keypress (except for combining keys), and so on.

The KEYPRESS_SCANS, KEYRELEASE_SCANS, KEYREPEAT_FIRST, and KEYREPEAT_NEXT macros specify the interval in number of calls to the key_scan() function.  To make them consistent in real-world time, it needs to be called at regular intervals (2000 times/sec for minimum USB HID latency).  If that is not possible or preferable, I'd use a timer counter and 16-bit key_counter array entries also.  Then, the decrement would be adjusted to reflect the interval between the previous and current scans.



Note that I too use different methods with keyboards, and my point here is only that this kind of software debouncing works very well for me; better than hardware debouncing (because I can trivially adjust the macro values by converting them to variables, and just initialize them from defaults from Flash, and use e.g. HID commands from the host computer to adjust them in real time).  This does not invalidate anything Benta wrote, it is only a different approach.

My first Teensy 2.0++ project was (is!) a 70cm × 20cm × 2cm thick birch plank with an arcade joystick and classic microswitch-based buttons.  I used an absolute encoder (a hexadecimal one, with five pins) to select between keyboard emulation (with 15 different layouts, WASD and ↑←↓→ and so on) and gamepad emulation.  Teensy 2.0++ is an AT90USB1286 with native USB and 46 I/O pins, and can be programmed in Linux on bare metal using avr-gcc, avr-libc, and Teensy Loader.
 
The following users thanked this post: eevdude

Online Benta

  • Super Contributor
  • ***
  • Posts: 6231
  • Country: de
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #11 on: January 09, 2022, 12:53:19 am »
How about getting the basic HW principles and structures defined, before you start churning out C code?
Just a suggestion from my side.
You're still totally stuck in "scanning mode". Open your mind, also to other MCUs that are not your favourites.
Pull-ups and interrupt capability may not be the strengths of your preferred parts, but are normal on many MCUs.


 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6865
  • Country: fi
    • My home page and email address
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #12 on: January 09, 2022, 06:13:41 pm »
How about getting the basic HW principles and structures defined, before you start churning out C code?
I posted that only so that anyone –– not just OP, but the others that may be reading this thread now or later –– can check if their software approach is as simple as mine; in case their dissatisfaction with software debouncing is just a matter of inefficient/unsuitable software approach and not software debouncing in general.

I am definitely not assuming OP is going by that route; I'm just trying to help evaluate if the observed problems are due to software approach, or something else.

You're still totally stuck in "scanning mode". Open your mind, also to other MCUs that are not your favourites.
Pull-ups and interrupt capability may not be the strengths of your preferred parts, but are normal on many MCUs.
I definitely concur; especially now that some/many MCUs are harder to find in retail due to the chip shortages.

(And I like this kind of discussion, where multiple completely different approaches are suggested.  The reason is, although OP may choose one, these threads are easily discovered by others having a similar but not exactly the same problem, and they then have more options to choose from.  I myself am very interested in Benta's approach, for example. :-+  If I were to do a Bluetooth or other wireless keypad/gamepad, then I'd consider low power use critical, and that interrupt approach would be perfect to minimize current consumption.)

As an example, LCSC (that I use for my projects) has my preferred MCU for this, ATmega32u4, only in QFN.  However, they have lots of STM32F0 and STM32L151 parts (noting that I'm only looking at chips with native USB) that I haven't used before; and the latter is ultra-low power, 10x10mm LQFP-64 with 0.5mm pitch (that even I can solder; and I'm an uncle bumbleduck) with all I/O pins interrupt-mappable.  Now, although I haven't programmed for these, they're supported in STM32Duino, and therefore easily programmed in the Arduino environment; good enough for rapidly seeing if it works well for one for this, at least.  I don't like going with the official eval board approach, I would instead make a test board in e.g. EasyEda and order one from JLCPCB or similar.

Your own selection should reflect your own requirements, of course; and as I stated, because my devices all have USB, my only real requirement above would be native USB interface (so I can use USB HID), plus a hand-solderable non-BGA footprint (because me fail soldering).  It might seem odd to move to 32-bit ARM, but while it may seem wasteful, they can actually do the job with smaller cost and power requirements!  Plus, it is easy to find ones with interrupt capability on all I/O pins, with lots of pins in a hand-solderable LQFP package.  And, if there exist Arduino cores for the MCU, you can either write the firmware using Arduino environment, or use the core as a guide to implement your own on bare metal, without potentially having to pay for a vendor-provided development environment (although that too is obviously a viable option, if this is to be a commercial product).

Lots of stuff to consider and explore, before making ones mind.  I also normally check out Digikey, Mouser, and TME (in addition to LCSC) to make sure I have more than one source for the chip I need (even if I only need a couple), because having my hobby project delayed due to unavailable parts is annoying as hell.  (Like that CH55xG.:(  I know LCSC has two CH552G's in stock, but I'm not going to push my luck.)  Right now, I'd be very wary of single-digit parts counts, and I've heard (here at EEVBlog forums) nasty tales of lacking stock even though there ought to have been stock at ordering time...  And eBay etc. is out for me, because of proliferation of rejects/pulls/fakes.
« Last Edit: January 09, 2022, 06:21:41 pm by Nominal Animal »
 
The following users thanked this post: Benta

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6865
  • Country: fi
    • My home page and email address
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #13 on: January 09, 2022, 08:06:44 pm »
The options discussed thus far are also not the only ones possible, not by a long shot.

For example, having looked at STM32L151, and considered Benta's approach, a new option (that I have not tried myself, but sounds intriquing to me) came into my mind:

Consider a 16×16 matrix (for simplicity, the exact dimensions don't actually matter much), but with per-keyswitch diodes, and with the inputs in the same GPIO bank so they can be read using a single I/O access in parallel.  When no keys are pressed, all 16 outputs are set high, and all inputs will trigger the same interrupt.  Then, the device goes to low-power/sleep mode.  (No current flows unless a key is pressed, so having the outputs high should not increase current consumption much –– the internal circuitry will consume some, though.)  Any key being pressed will trigger the interrupt.  When the interrupt is triggered, the device wakes up, switches to active scanning mode, using a loop roughly similar to what I showed above.

Because the MCU will do the scan in microseconds, it can then set up a timer to trigger an interrupt in about 500 microseconds (in my case; interval dictated by USB HID protocol; your choice may differ!), and again go to sleep until the interrupt triggers and it is time to do the next scan.  (Actually, on the STM32L151, I do believe one can use the USB module to signal the next wakeup, so that the next scan will be triggered immediately/very soon after the USB HID message related to the current scan has been transferred.)

This is not technologically optimal, nor is it what Benta suggested, but on this kind of MCU it would give a lot of the benefits (the MCU would sleep most of the time, and only do real work while at least one key is being depressed), with minimal additional hardware (the diodes; I prefer SOT-23 Schottky dual ones, like BAT54C and so on, that cost something like $0.02 apiece, and you only need one per two keyswitches; and perhaps 10kOhm current-limiting resistor per row/output pin, to safeguard against accidental shorts).

Would I do this myself?  I don't know, I haven't tried this.  My point here is that there are many options, and like Benta said, it starts with considering your hardware options and especially MCU first.  This was just an idea that came up after participating in this thread.  Because it is so cheap and simple and has worked well for me thus far, I personally am quite stuck to the scanning matrix and software debouncing approach.  You do not need to be!



If your target will not use USB for the keyboard interface, your MCU selection widens radically, too.

In that case, I personally would use something like a Teensy (because I have them) with a native USB interface, to emulate the target machine, by bridging the keyboard interface in the target machine (emulated by the Teensy) to your development PC as USB HID messages.  With Teensyduino, keyboard emulation is trivial: you'd only need to implement the translation layer from the target machine keyboard interface to Arduino code –– perhaps I2C, SPI, UART?  Having the keyboard then connected to the host computer and act as a normal keyboard means it is easy to test it.  Again, just my own lazy-ass approach, not the recommended/only way!

The above-linked page also describes the fact that some OSes limit HID interval to much longer than 1ms, up to 63.5ms!  This is not a hardware limitation, it is a choice made by some OSes.  I don't know which nor why, as I really only use Linux right now, and it respects the requested 1ms HID interval.  It could even be an EFI BIOS detail, I guess?
« Last Edit: January 09, 2022, 08:09:36 pm by Nominal Animal »
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 6231
  • Country: de
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #14 on: January 09, 2022, 08:43:22 pm »
I've done that myself in a project, but not with diodes.
Instead, with 4000-series OR/NOR gates (could also be 74HCxx). Their static current consumption is in the uA range, the diodes will consume more (you need pull-up resistors and a minimum diode current for reliable operation).
 
The following users thanked this post: Nominal Animal, eevdude

Offline eevdudeTopic starter

  • Contributor
  • Posts: 14
  • Country: pl
Re: Keyboard / Switch Matrix - H/W Debounce + Multiplexer
« Reply #15 on: January 09, 2022, 09:38:05 pm »
Thanks for the suggestions, code and options - i think i will build some boards with switches & diodes and some logic boards to test different things. Since my "return" to the world of electronics (was busy fixing things and tracing my own boards with those stencils and polystrene acid baths as a kid, but not touched electronics since and been a programmer for what seems like forever) - i've only really played with a pi zero and programmed some attiny/paduks - produced a small project for a friend which he hopes to kickstart someday.

I've only just got around to ordering a scope finally, and a slightly better multimeter ($27), still no power supply, signal generator etc although i'm on my 2nd soldering iron because the first (even though a lot of people rate it) was awful for me personally (one of those chinese hot air + iron combos), and my $5 multimeter isn't really that accurate.

Will probably have some more questions, but they might be about specific topics - thanks again :)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf