MCP23017 PortExpander driving 4x4 KeyPad w/ interrupt / setWatch for 'keyDown' detection #952
Replies: 9 comments
-
Posted at 2017-10-27 by @allObjects ...continued... The questioning conversations triggered my activities to finally tackle MCP23017 PortExpander. My MCP23017 lived so far neglected life since about the time when @drazzy gave it a push and provided the MCP23017.js module. Having also a key pad at hand (with a broke key... argh...) left me with no excuse to walk the talk... (as 'kind-a' outlined in mentioned questioning conversation). Here a good cut of working code (also attached as file for easy 'grab' and play for yourself:
...to be continued...Attachments: |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-10-27 by @gfwilliams Nice - thanks! Do you think the interrupt handling is something that could be added to the existing MCP23017 module? I'm wondering whether I could modify |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-10-27 by @allObjects ...continued... The MCP23017 I happened to get are I2C models, stamped: MCP23017 E/SP. Not as familiar to me as SPI, it gave me some grieve on top of the challenge what the universality of the chip already posed to me, especially the re-config from 16 bit to 8 bit mode (and of course also some lousy wiring flaws and coding typos made me burn some night oil). The code is not the most leanest, but having implemented a touch UI, I knew about the needs and challenges to meet. Therefore, the 'Kpd' module (or class) supports the use of multiple types of callbacks: callback on key up (preferred), callback on key down, and both. It even supports a polling mode if you want to live an Arduino loop and lifecycle... The code also supports bouncy hardware and clumsy key press and releases behavior. Example output - with key number first in line - from provided sample callback look like this:
and:
and both down AND up callbacks:
Usage with no callbacks - ciao Arduino - can look like this:
and related output:
Even though the interval driven polling / Arduino loop is not the most efficient, it is though already a lot more efficient that doing just every thing with polling / in loop. As mentioned earlier, the implementation could be leaner ( |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-10-27 by @allObjects ...@gordon, you go my 6AM brain going with your #3 post... After a while thinking about what components - hw side / js side - and lifecycle events current For example, there must 'things' that:
I'm sure that current STM MC / Espruino interrupt mechanism - including the event queue - is not a trivial thing... and going now through additional 'unpredictable' / semi-robust communication to perform the handling does not make it easier. Yes, it makes it simpler for the application / user, but the easier it is for the user the more complex it is for the system. A If we can find a robust solution along the 80/20 rule, that will be really great. I said
because if I2C has an internal error, the whole application crashes... all is dead... a watch dog would have to restart the app, and the app would also have to 'feed' the watch dog properly so that it would not inadvertently restart. There is so much intertwined / layered / micro I2C calls that I have 'no clue' how I could 'easily'/not heavy handed catch internal errors / timeouts / exceptions... it just seems to be messy to me until now. clearWatch() logically 'maps' to 'disable interrupt'. Therefore it is crucial that the watch object can be accessed by the handle and also options object with it's extension in order to handle things that are not easy to generalize / automate / require user/application involvement at particular life cycle events... ...all sounds... and is still very fuzzy... I have to gain a bit more experience with the current all-in-application setup and let it mature before making specific suggestions / state requirements. I was also looking into the key matrix module how I could make a leaner version and from that derive change requests for the current setWatch() / clearWatch() / set/clear interrupts via I2c. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-10-30 by @gfwilliams For keypads I'd imagine you could easily handle whatever you need outside of an IRQ in the setWatch without too much trouble. I mean, what you're suggesting is basically the ability to run JS code in an IRQ, since you'd have to be able to access I2C to read the values back. You can run 'compiled' JS in an IRQ I believe, but really that's pushing things a bit far I think. I could enable JS IRQs, but it's likely to be super unstable. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-10-30 by @allObjects I took a deep dive into the MCP23017 (I2C) Portexpander module (and rebuilt - no offense to be taken here) to understand it's wokings and prepare a test bed with full regression. So fare, regression includes validating reset and input only (activities are jotted down separate conversation: Exploring adding setWatch/clearWatch (inerrupt handling) to MCP23017 (MCP2308) Portexpander Ports). While working through the code, I rethought the interrupt story... to the point where I'm thinking to add watch function to the portexpander pins and hide the fact that this makes only one watch in Espruino. The part from JS IRQs would only be for putting the application service request into the queue instead of calling the watch callbacks 'myself' (in a setTimeout to defer), in order to make the interrupt service routine to behave more like a hardware interrupt than a software interrupt... and achieve in shorter handling. I'm worried about loosing interrupts/events. This is anyway something that has to be looked into because while I2C communication with the portexpander goes on to deal with an interrupt, interrupt is disabled until port register or interrupt capture register is read. Port register may already be different from interrupt register because port register - as by definition - delivers the pin states when read, interrupt capture register - as by definition - captures/latches the pin states when the interrupt happened. In 8 bit portexpander (23008) and 16 in portexpander (23017) in 8-bit mode with separate, non-mirrored AB interrupt pins, the register latch 8 bit at once. In 16 bit / mirrored mode (AB interrupt pins), the registers latch 16 bit at once. Teasing out the details - which pin caused the interrupt from flag register(s() and what was its state at interrupt time from capture register(s) - by parsing the 8/16 bits and invoking (or placing into a queue) the application interrupt/watch callback for the related pins is an interrupt service routine by itself... like a service to the service... As said, still in the phase of completing the test bed for current functionality. After that I will venture into adding watch capabilities in one or the other ways to the Portexpander Ports. In respect to a Keypad solution, it could be just one dedicated keypad module specific to the use of a Portexpander rather than two modules - a module for a keypad using a module for interrupt enabled Portexpander... |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-11-08 by @allObjects Uploaded schematics / wiring as addition to first post #1. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-11-08 by Wilberforce
You could do an |
Beta Was this translation helpful? Give feedback.
-
Posted at 2017-11-09 by @allObjects @wilberforce, Setup of portexpander and enable interrupt on a pin A3:
with Internals of
and with
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Posted at 2017-10-27 by @allObjects
Espruino site provides a nice, lean example for driving a KeyPad Matrix. Code is lean, pin usage is pretty fat: 8 pins: 4 for columns and 4 for rows.
For applications where pins become a shortage and I2C, SPI, OneWire,... become a great and efficient tool to drive peripherals, MicroChips PortExpander MCP23017 / Datasheet with version for 16-bit / 2 x 8-bit (and MCP2308 - 8-bit) come in handy - see pic of breadboard setup.
Espruino provides an easy to use MCP23017.js module and application example MCP23xxx I2C and SPI port expanders. The provided module though just supports simple input and output - nicely emulating the single bit / one pin Port approach.
The existing module works fine for certain types of inputs and outputs, but for scanning for example a 4x4 or even 8x4 key pad, a lot of code has to be executed at a decent rate which eats away a lot of computing power and let's the application feel sluggish... If for sure may work but raises the question how to do it more efficient with, for example,
.setWatch()
(see conversation).The wiring follows the sketching found above conversation. How it looks tangible is shown in attached pic. The code is subject to following posts.
...to be continued...
Attachments:
Beta Was this translation helpful? Give feedback.
All reactions