Taking another crack at keyboard matrix scanning using the NRF52 PPI #1111
Replies: 9 comments
-
Posted at 2020-08-31 by @gfwilliams Hi! For the KeyPad module, there's a cunning(ish) way of handling KeyPads that doesn't involve scanning them all the time: http://www.espruino.com/modules/KeyPad.js Basically you put all the columns into 'pulldown' state and watch them, then set all the rows to 1. So then you can just wait until the pins change state, and then do a proper scan to see what was pressed, then go back to watching the pins again. If you're only planning on handling one press at a time then you can just do the whole thing like that, since the state of the pins will change whenever a button is pressed or released. If you want to try and handle > 1 press (which isn't always guaranteed on a matrix keypad) then you'll have to keep scanning while a button is held, but even that isn't such a big deal as I imagine the buttons won't stay pressed for too long? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-08-31 by consolenaut Thats a great suggestion, it sounds so obvious now you've said it :) I'll definitely be handling >1 press but that still takes a lot of load off the espruino, if nothing else it'll probably save me some power I would've burned sequentially turning pins on and off. I'm guessing I'll still want to do some messing around doing the scanning with the low level NRF52 lib to offload that to a peripheral rather than having the core do it. I'll likely still want to do processing on the core while keys are pressed/held to send keycodes with modifiers and things, but if I only have to do that after a pin state change thats great. My end goal is to build a mechanical keyboard firmware lib that handles the hardware level stuff & does a bit of extra helpful stuff like classify press/release cycles as a 'tap' or a 'hold' without the user having to do that, provides a lightweight mechanism for defining keymaps as a JSON file, and lets the user write their own javascript functions to make their keyboard do interesting stuff. This already exists in proper embedded code (QMK) but I'd love to do something similar on espruino since Javascript is so much more accessible :) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-08-31 by @gfwilliams That sounds like a great project! I'm not sure using PPI for scanning (via MCP23017) is even possible. You could potentially use 'Compiled JS' or maybe even inline C to increase the poll speed though: http://www.espruino.com/Compilation You mentioned scanning a 4x16 matrix in http://forum.espruino.com/conversations/352979/#comment15489686 - you should be able to do that with http://www.espruino.com/MDBT42Q without an IO expander? If so, you could use Compiled JS or Inline C to do the scanning and you could do it really fast - I don't think there'd be a need for PPI or anything like that to help you out. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-09-01 by consolenaut Thanks, I'm looking forward to getting it working :) I'm going to give the compiled JS a shot today hopefully! You're right that I wouldn't need the MCP chip to scan a 4x16 matrix, originally I wanted to do it that way for future expandability but the MDBT42Q has 32 GPIO pins, so that gives me the headroom to do a full size keyboard (6x22) with some extra GPIO to spare to do things like LED backlighting/dedicated buttons So, set up watches on my columns, only scan when a watch gets triggered to stop us burning processor cycles at idle, and do the scanning in compiled JS or inline C to get a speed boost - that sounds like enough for me to get going with and see how far I get :) Thanks for helping me out on this one, I might go quiet for a couple of days while I try this out but I'll post and update to let you know how its working out! |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-09-01 by @gfwilliams Great! Just to add, I think you can have a maximum of 8 watches on nRF52 - so if you're doing 4x16 you'll need to watch the 4, not the 16 :) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-09-01 by @allObjects I'm sure you already read thru the conversation about Exploring adding setWatch/clearWatch (interrupt handling) to MCP23017 (MCP2308) Portexpander Ports It's a good approach to scan only after an interrupt happened. Regarding the setting and reading of pins, array is of help. Unfortunately, setting pin modes has to happen pin by pin. I once had asked @gordon to also consider the array for setting pin mode the same way as reading and writing to pins goes. I used similar approach - setWatch() and scanning after event - for resistive touch screen without driver (Espruino is directly driving and reading the 4 electrodes of a resistive touch screen: Resistive Touchscreen directly (no touch controller)). I later used it in the UI modules http://www.espruino.com/ui (how come is in conversation: Modular and extensible UI framework and ui elements.). |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-09-06 by consolenaut Hey! Just wanted to post an update, I had a go at implementing the suggestions yesterday evening & got something working - it catches even fast button presses but occasionally drops them which is something I'm looking into. I've attached some code, its still ugly POC code & I'm sure there are things I can do to make it run more efficiently :)
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-09-07 by consolenaut Just a quick question on the pinModes/setWatch method - is there a way to set an array of pin modes & watches like how I'm able to read an array of pins with digitalRead? I couldn't find anything about it in the docs, is it something on the roadmap? I'm trying to get rid of any unnecessary loops to get this to run faster and I think It'd be really useful :) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-09-14 by @gfwilliams
I'm afraid there isn't anything at the moment, no... As you had done, |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-08-29 by consolenaut
Hi there Gordon! I wanted to ask your advice on the best approach to take writing some keyboard matrix scanning code.
I had a go at this a couple of years ago using an MCP23017, clocking the row outputs sequentially from the espruino & reading the column inputs on the MCP each cycle to determine which keys were pressed. This worked okay but I had a couple of weird quirks with the MCP chip & ended up burning way too many espruino cycles just turning the row lines on and off - not the best approach!
I'm taking another crack at it, this time using an MDBT42Q instead of a Pico, I think using the NRF52's PPI to keep as much off the processor as possible is the right approach. I was thinking of using the NRF52's GPIO pins to drive the rows sequentially again, then listening for an interrupt from the MCP to know when to read its buffer to get the column states, and if anything has changed send it back up to the processor properly to send a keycode. I wanted to ask if that sounds sensible and, if so, which events and tasks it would make sense for me to set up.
I appreciate that's a reeeeaallly long question, but I'd love a nudge in the right direction to get me going :)
Beta Was this translation helpful? Give feedback.
All reactions