Teensy 4.1 + MCP23017 examples

nshaver

Member
I'm building a teensy 4.1-based drum machine. It's got quite a few buttons and LEDs so I'm using a few i2c MCP23017 to offload the I/O. It took me WAAAAY too long to get the Teensy 4.1 working with the MCP23017 using interrupts. I had a really hard time finding code examples, especially working out the magic sequence of code that makes the MCP23017 interrupt reset after triggered/processed. There was a bit of discussion on these pjrc forums about it, but nothing that "just worked". Now that I've got it working with and without interrupts I figured I'd make a quick post here. Maybe it will save a future googler the hours I spent figuring out what surely has already been figured out.

Here are my example projects:

Without interrupts: https://github.com/nshaver/teensy_mcp23017_no_interrupts

Using interrupts: https://github.com/nshaver/teensy_mcp23017_interrupts

If anyone notices that my "using interrupts" version has any bugs or sees things that coule be improved - feel free to reply here so I'll know. As far as I can tell, it runs very fast and stable. I haven't finished this project yet though. I'll have more confidence in it after the drum machine runs for 24 hours without getting glitchy.
 
nice work! I wish I had this code about a week ago. I just went through the same thing. It sounds like we are working on similar projects! I just started a drum machine project too! I ended up going the no interrupt route since my drum pads are done with a 4x4 matrix. I found it easier to do that way than use interrupts.
 
Interesting! One question, though: you are reading the multiplexer in the version without interrupts every loop cycle. Given the speed of the Teensy 4.1, I reckon this will be much too often to only catch button presses. Worse, it will slow down the loop while waiting for the I2C transfer to finish. I would think it will be sufficient to read the multiplexer every 5ms or so and still not miss a beat.
The interrupt version is much more efficient of course. The button state variable might need to be declared volatile, by the way.
 
I have some loop-counting logic in my examples. When polling every loop the "loops per second" numbers were in the hundreds or low thousands. When using the interrupt it runs at around 8 million loops per second. It's a night and day difference. I think interrupts are definitely worth the trouble, and it's a lot of trouble. You were correct about the button state needing to be volatile.

Regarding not reading every loop (when not using interrupts), my thinking was this: if I don't read every loop, there's a chance that a button will be both pressed and released before I got around to polling again. In that case I would have missed a button press, and that's pretty much the last thing I want to happen.
 
nice work! I wish I had this code about a week ago. I just went through the same thing. It sounds like we are working on similar projects! I just started a drum machine project too! I ended up going the no interrupt route since my drum pads are done with a 4x4 matrix. I found it easier to do that way than use interrupts.

Have you done any testing to see how many loop/sec you're able to process? I worry that if I poll too much my Teensy won't also be able to handle the wave generation and effects. I plan on using reverb and that has a pretty big hit on the processor.
 
Regarding not reading every loop (when not using interrupts), my thinking was this: if I don't read every loop, there's a chance that a button will be both pressed and released before I got around to polling again. In that case I would have missed a button press, and that's pretty much the last thing I want to happen.
Yeah, whatever serves your purposes best. I was just calculating that 5ms would cover 200BPS (that is, 12000BPM) - most probably you will not be able to press and release pads that fast. And the 5ms in between are a lot of time for the Teensy to do something different.
 
Yeah, whatever serves your purposes best. I was just calculating that 5ms would cover 200BPS (that is, 12000BPM) - most probably you will not be able to press and release pads that fast. And the 5ms in between are a lot of time for the Teensy to do something different.

Well, for what it's worth I gave the non-interrupt method a try again and polled every 5ms. I'm also keeping up with the LED state of any LEDS that I've turned on or off, so that I never try to turn on an LED that was already on, or off one that was already off. I'm now getting at least 3 million loops/second, even when hitting the buttons crazy fast. This is the most responsive and accurate I've managed to get yet. I'm going to do a little more testing to hit it a button as fast as I can for a good minute or so and see if the Teensy counts as many as I hit. If it does then I think I'm going to call it good enough and switch my methodology to polling instead of interrupts. The interrupts are just more trouble than they're worth. My current setup is with three MCP23017s, one processing 16 button inputs, and the other two processing 32 LED outputs.

Thanks for all of the suggestions and discussion.
 
I did some testing to see if I'm missing important button presses with the non-interrupt method. Best I can tell, it's fine. I'm going to polling, interrupts are more trouble than they're worth in my current use case. I made a short video of this most recent test:

 
For what it's worth I have updated the code in github for my "no interrupts" version. Link is in first post to this thread.
 
Glad to hear that. I am at a similar task but have to read many analog inputs in short intervals and I am going to try that by polling as well.
 
Glad to hear that. I am at a similar task but have to read many analog inputs in short intervals and I am going to try that by polling as well.

For what it's worth, I have used CD74HC4067 multiplexers to read lots of pots into a Teensy 4.1 for MIDI controller projects. That has worked ok, but my pot values seem to be jumpy sometimes. I've resorted to doing multiple analogReads (like maybe 3 reads in a row) and then using the last one. I suspect that my hardware design might be lacking, maybe I need a capacitor on my pots or something like that. The multiple analogReads don't seem to slow things down much so I've just gone with that and moved on.
 
I am about to do exactly the same - MIDI controller, 4067s, resistance values (from FSRs). I had to put an opamp in between to have a low impedance signal at the analog pin, that improved things greatly.
 
I am about to do exactly the same - MIDI controller, 4067s, resistance values (from FSRs). I had to put an opamp in between to have a low impedance signal at the analog pin, that improved things greatly.

Ah, thanks very much for that tip! I'm seeing quite a bit of hits now that I google for "multiplexer opamp". I'll make use of an opamp on my next multi-pot 4067 project. Did you use a 4072/4 op amp, or something fancier?
 
Back
Top