[0]: https://github.com/FrameworkComputer/EmbeddedController/blob...
[0]: https://github.com/FrameworkComputer/EmbeddedController/blob...
Testing was done [0], but it's not written in an easy-to-understand way. As a summary, Thinkpad keys are scrambled within 15-23 ms. Usually, humans ascribe scrambled letters to their own mistakes, but this time it's the keyboard's fault. Lenovo continues to ignore the issue.
One very stupid solution for your password is to change its letters to go from right to left. That way the scrambling will become anti-scrambling and you can type your password even faster than on a normal keyboard!
But if you want to reduce hardware cost, you can eliminate many capacitors and resistors by doing it in firmware instead.
Most Microcontrollers have the pullup resistor built in. Modern ones even let you turn the pull-up feature on and off per pin with a SFR (a special register /fixed memory address you can write to where you change hardware settings). Often you can also choose between reading a pin or driving it as an output.
The most important thing to know about debouncing is that any hardware switch bounces from 50-200 times over a very very short interval when you press it. You can use an oscilloscope to see that. The bouncing is not as bad on release but I imagine it still exists there too.
Another fun hardware trick is that when you turn off a magnet (like a relay) you can get a massive over-voltage pulse back (10x typical drive) for a moment. You need to protect yourself from that, for instance with a Schottky diode. Here's a discussion on that fun detail [1].
[1] https://forum.allaboutcircuits.com/threads/reduce-voltage-sp...
That shit adds up. BOM costs are everything for consumer goods.
I don't want to encourage shitty design for pennies at any level.
Stop making shitty shit.
Saving a penny on the keyboard will be one of hundreds of places where a penny was saved. Good engineering and product design is about trade offs and compromise, not taking absolute positions about what’s shitty or not.
Cherry once made a software/hardware hybrid but it didn't have any advantages compared to software debouncing, and it needed more power, so there was only one model.
If I understand it correctly, debouncing with a capacitor delay events somewhat. With software debouncing (done right) you are only required to have a minimum time between the press and release events.
In fact it's more customizable for quicker response than hardware RC debouncing.
There is, however, something wrong with shitty debouncing software.
More importantly though, software debouncing offers greater flexibility. For keyboards, you usually[1] want to implement an asymmetric "eager" mode, where a key press gets registered immediately and only the key release is debounced. Since software usually does stuff on the key down event, this works to reduce latency.
[1] Well, that's what the various enthusiast mechanical keyboard firmwares do, I am not so sure that generic $random_corp keyboards do care...
Is there an easy way to fix this? This is a noticeable nuisance in Emacs, when chord strings get "debounced" out of order (i.e. things like C-xC-m -> C-mC-x are quite annoying). The debounce precision is slower than fast human typing. Even though keypress event order is correct and noticeably correct, it gets rounded to "simultaneous", and then reordered (backwards) according to the logic you've described.
On top of that, I didn’t know what the issue was and it drove me nuts until I figured it out. Left a very bad taste in my mouth for Lenovo/ThinkPad despite all the love they receive.
Intuitively, this means register the event when you see the first edge, not once the bounces have finished.
For an example of incorrect denouncing, see most articles on denouncing (the hackaday article comes to mind), and the QMK firmware last time I checked (most keyboard set the denounce time to zero, so the debounce time just becomes the update rate).
Isn’t that ultimately what capacitor + Schmitt buffer debouncers does? The only difference is that this would be in software?
A Schmitt buffer isn’t necessary when using polled GPIO with a microcontroller.
An equivalent accurate discrete logic circuit would be a latching circuit with a gated input pulse on state change corresponding to the denounce time, which is overkill for simple button handling.
Since you said 'denounce' a couple times I'm not sure if this is some jargon I've not been aware of or just auto-correct.
c and c2 loop variables so a typo can hose you horribly. A global variable to hold the array length. ! instead of comparison to 0. Having to offset the second loop by 1. Early return which means the function will normally work fine but might result in N^2 extra time depending upon the data state. A bit trick relying on unsigned underflow without pointing out that unsigned is a key constraint even though it has a comment. An extra missing const on the incoming pointer (should be: const uint8_t * const). Braces left off the short-circuit if conditionals.
The worst part is I have personally written tons of functions like this. This is a "normal" function in C--in fact, it's far better than average.
The fact that you write C like this just shows how much we need something better.
This is a microcontroller firmware. Moving what is essentially a constant around the stack would be insanity.
> ! instead of comparison to 0
Not a problem and even idiomatic.
> Early return which means the function will normally work fine but might result in N^2 extra time depending upon the data state.
It only takes N^2 time when all columns have at least one key pressed but not have at least two rows in common in any of them (except maybe the last two) - hardly a state that you care that much about. Would you really want to increase the latency/power consumption for single key presses just to have the exceptional case not be slower than normal?
If you wanted to you could restrict the early exit with the same test for having at least two bits set. If the key matrix has no unused slots you would then only check if there is another column which shares any set row bits (because it would then share all of them), which could let you make the algorithm O(n) with some additional memory for row bit counts. But the code would be more complicated and the number of columns is not dymanic. Plus the key matrix most likely has unused slots precisely to avoid ghosting for common combinations.
> A bit trick relying on unsigned underflow without pointing out that unsigned is a key constraint even though it has a comment.
The variable with type is declared right before the bit trick. If you change it to signed when there are bit operations, especially ones you don't understand, then you deserve what you get. However, this trick does not rely on unsigned underflow. the only concern with signed (assuming two's complement) would be if the sign bit is the only one set, in which case the signed underflow would be undefined at the language level - but not a problem at the hardware level since two's complement addition/subtraction is exactly the same as unsigned addition/subtraction.
> An extra missing const on the incoming pointer (should be: const uint8_t * const).
const on the outside of function parameter types (as opposed to inside them) does not change how the function can be called. Sure, you could make all local variables const if they can be but for such a tiny function that really does not add anything.
> Braces left off the short-circuit if conditionals.
Meh, that is a code style choice and no reason to complain about C. Also not really that dangerous with modern compilers that warn based on misleading indentation.
And you missed the actually bad part of the function: The comment that says the colummns are ORed together when they are ANDed.
[0]: https://hackaday.com/2010/11/09/debounce-code-one-post-to-ru...
For instance, taking a look with a scope, if you observe that the signal stops bouncing after 3 milliseconds, it would be pretty safe to accept duplicate keypresses with a 10-ms guard interval.
Although in many cases polling is fine as well.
$2 micros are many MHz. All it has to do is save/compare one timestamp per interrupt.
So lets do some back-of-the-napkin calculations and say it takes 1us to store/compare the timestamp, a switch transitions 50 times per press on each change of state, and a person is typing at 100wpm (lets say 600cpm = 10cps).
I think these are pretty conservative numbers, 50 bounces sounds like a pretty crappy switch to me.
So 1000 transitions per second which would take 1ms, which means 1/1000th of the time is spent servicing the interrupts.
It's not going to cause a problem unless the coding is very inefficient.
A lowpass filter is an empirical hack, not a gold standard. It has multiple disadvantages; rather than being "responsive," it adds latency to the initial input for no good reason, and it affects both rising and falling edges equally, again for no good reason. It also requires the addition of unnecessary physical components.
Two questions:
1) do mechanical switches with zero bounce really exist?
2) are they cost effective enough to be used in consumer keyboards?
You just use a switch with 2 outputs: for on, and off position. Triggering 2 at the same time is impossible.
> 2) are they cost effective enough to be used in consumer keyboards?
Surely less than a percentage of a cent in extra cost.
But then the switch will still bounce except now it bounces with an extra state and you need extra logic to read an extra output per switch and debounce both outputs, which also makes PCB's more complex further increasing the cost.
>Surely less than a percentage of a cent in extra cost.
With the extra PCB and custom logic complexity you just added with the extra output per switch, you're looking at way more than that, which I guess is why the industry went optical instead of following your idea.
No, you don't need to debounce both. Both signals will never be connected at once.
You've pretty much just described a standard everyday bog standard switch.
It's either over the threshold resistance for triggering, or it isn't.
Nothing you've suggested here excludes a switch that changes state by bouncing between the two states 50 times per physical press when you sample at MHz speed, as most switches do.