-
-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
another i2c PE button question #70
Comments
Hey, Can you check whether data has changed via I2C, or can you only set the pin mode and read /write? |
I'm not sure which way to go; I can see the efficiency of reading a whole port expander byte (or word) at once and caching that for a short time. but in some apps, it may be necessary to always ask for 'fresh' data even if you have to re-fetch a whole byte/word. I guess to allow max flex, when you do the equiv of a digitalRead(), you could add a param that forces a refetch of data, or will allow cached data. and if you leave off that last param, it would have a reasonable default (whatever that is). dont know if I'm overthinking it or not; but i2c bus traffic has to be managed between all the things on the bus. I have an i2c oled display that I'm trying to keep updated quickly and I also want to scan for keyboard changes and not feel sluggish on the key scan. if I do an i2c request for each keypress check, it would clutter the bus. that's why I'm trying to think of the best way to deal with port expanders and fetching a whole bunch of data even if the user only wanted one bit of it. thinking aloud, maybe something like: digitalRead(pin, cache_allowed=true); I'm thinking that hiding the fetch of the byte/word and the cache timing is something I'd like to hide from the app writer and just let them call the abstract digitalRead(). if they dont have a good reason to disable it, the cache would be used and some holding time would be in a ctor, somewhere. |
oh, and there would be a 'digitalReadWholePort()' or something, for when the user really wanted a complete set of bits and is going to do their own AND and OR stuff from that. that would also have a cache_allowed flag, to match the single bit reads. while it might seem less useful to keep the cache if you are asking for all the bits, but you may want to throttle how often the port is polled and this cache thing could be one way to limit how fast the i2c port is being queried. (this might belong more on the port-expander class, though.) |
out of curiosity which port expander are you using? You could use the debounce time of the buttons as the expander's interval to read data. |
I tend to use mcp23008 and pcf8574 (or 75) mostly. |
Have one of the MCPs lying around and never used it so far. |
I often dont have a spare gpio to allocate to the interrupt pin on the PE chip so I have to poll and compare old word to new word, etc. usually there are not enough pins. hey, isn't that way we use PEs? lol |
I setup button2 using an MCP23008 and an ESP32. I used a timer to update the state of 8 different buttons and used a global array to store that state of each of the buttons. Inside the button2 custom state handler rather than reading from the MCP I am reading from the array in memory. The fact that button2 "reads" the state of the button from the array more frequently than the timer updates the array doesn't really matter in the end. Both are happening so frequently that it self-mitigates any delays in updating the state. I was able to accurately capture single, double and triple presses and helds accurately. |
Just commenting to join in the conversation. I now typically use PCF8574/PCF8575/MCP2308 in all my projects that require anything more than a few button inputs to prevent occupying precious GPIO pins directly, and I came across the exact question of how to debounce those inputs (given I'm in the habit of using Bounce2 for debouncing simple single button inputs). Just wondered what the current consensus on best approach was? FWIW, I'm using https://github.com/xreef/PCF8574_library to read the inputs, which has the option to either read a single channel, or all 8 channels at once (for, I suspect, almost the same cost). |
Hey, as mentioned - it took a while. |
I'm using Button2 with a PE. I'm using an Adafruit board with an ATTiny817 so it's a little more complicated but with the MCP23008 it would actually be a lot easier to implement.
Should work just fine. |
Thanks for the suggestion! Yes, that should certainly work. I might try to implement some optimisations since I have 16x buttons, and polling them all individually in every iteration of loop over an I2C interface would be somewhat inefficient. |
Although, thinking about it some more... I don't see how you can pass BUTTON_PIN to the custom handler? setButtonStateFunction() will only accept a parameterless function, so if you have to explicitly define separate callbacks for each input channel of a MCP23008, that's not really a viable solution. |
given that the i2c port expander is going to have to be called periodically, but you get 8 or 16 bits all at once from that.
the current paradigm is to assign a button to a single bit and the overhead of fetching that bit is small-ish. but on i2c, if you want to read 8 bits and you fetch that same byte 8 times, clearly that 'annoys the i2c bus'. (btw, you should never anthropomorphize computers; they hate that. grin)
so, what is a good way to decouple the polling of that byte (or 16 bits) from the test for button presses, that do single bit checks?
you can fetch an i2c byte and timestamp it and cache it, I guess. we'd have to do that outside of your class. there's no provision for a background poller, is there?
what I'm thinking is yet another user-provided vector that will get called by your library via your own loop() method. it would know enough to fetch the byte once.
what is a good abstraction for the user api? you could use the same 'give me pin status' query and it would either pull from the cache or it would get fresh data and reset the timestamp/age of the cache, automatically, for you.
what are your thoughts on this?
more and more, I find that buttons have to be on PE's and not on the native chip.
The text was updated successfully, but these errors were encountered: