I'm Out of Interrupt Pins...

Here's my scenario:

I'm using an AT90USB1286 (Teensy++ 2.0). I chose it because of the larger number of I/O pins and 4 (as opposed to only 2) interrupt pins.

I have two interrupt pins (0/SCL and 1/SDA) taken up by the I2C interface to a DS3231 TCXO/RTC. I have one interrupt pin (2/RX) taken up by the GSCLK pin on a TLC5940 LED driver chip. I am left with INT3 free with which to manage an Alps EC05E rotary encoder for input.

Every (good) example I've seen of interfacing a rotary encoder with an Arduino involves the use of two interrupt pins; I only have one interrupt pin left. What do I do? Do I settle for using one interrupt pin and only getting half-resolution on my encoder? (I have not tried this yet, but it has 12 detents with 12 pulses per detent, so I might still have enough resolution to be useful) Do I try to handle the rotary encoder without using interrupt pins? Can I utilise one of the many available PCINT pins?

I know I can't move the SCL/SDA pins to another pair, or else I2C won't work. Can I move the GSCLK pin from my TLC5940 to another pin and somehow make that work? To be honest, I'm not even completely sure why I need to use an interrupt pin with the GSCLK on the TLC5940, but it's working for now, so I don't want to change it.

Please keep this in mind: I'm using the TLC5940 library, the Wire (I2C/TWI) library, and I would like to use the last example from the Rotary Encoder [Arduino Playground] page http://www.arduino.cc/playground/Main/RotaryEncoders to manage my rotary encoder input...but I'll be ok without it, if there's a viable alternative that won't require using too much active CPU time, thus getting in the way of other things...

I'm willing to make adjustments to my setup and my methods of interfacing with these components, but being able to continue using the I2C and TLC5940 libraries would be fantastic.

I'm aware of I/O expanders that allow the triggering of interrupts, but the TLC5940 and accompanying UDN2982 chips (not to mention the 12x13 LED matrix, the DS3231, and the AT90USB1286) take up too much space in my project as it is, so adding another chip isn't really an option. If any proposed solutions can involve software changes or physical reconfiguration, I would appreciate it.

I'm just looking for options and ideas on what I can do.

could you connect 2 interrupts together and when it happens check for each even?

Encoder 'steps' specification can be a little confusing. Typically a encoder will have a given step rate specification, say 100 steps per revolution, by the manufacture. However they define 'step' as a complete transition of both edges of both a and b channels, four transitions in all per 'step'.

So if you interrupt on just one channel raising you will get the 'full' specified 100 step rating of the encoder. However if you interrupt on both both a and b channels (using two interrupts, 'raising') you will get 200 'steps' per revolution. And finally if you use both interrupts on 'change' status you end up with 400 steps per rev.

I know that may not sound correct, but I have tested this with a optical encoder rated at 128 steps per rev by the manufacture, but can obtain 128, 256 or 512 step counts per revolution depending on how many interrupt pins (one or two) are used and if interrupt on 'raising' or 'change' is used. Again is more about how the manufacture defines step Vs how many edges you actually use in decoding the encoder.

This concept doesn't just depend on using interrupts or not. As long as the encoder doesn't spin too fast it's possible to decode the steps using simple digitalRead statements, and the resolution per revolution obtained is just your choice on which channels and edges you use to define a 'step'.

Any one agree or disagree on what I found in my experiments with my specific optical two channel encoder?

Lefty

I continue to dispute the theory that you MUST use interrupts at all.

Your correct, you don't HAVE to use interrupts at ALL times. However depending on the speed the encoder is turning, how many 'edges/channels' your are tracking and how many other software tasks your sketch is trying to perform, there is a speed as which you will miss counts. Interrupts just raise the speed factor one can handle, but even there it's possible to 'miss counts' because of the ISR overhead factor given a high enough rotation speed.

Lefty

@Richard - I read someplace in some discussion of encoders that only reading from one pin reduced the resolution by half, but I could just be smoking something. Perhaps I had better redo my research. :P

@graymalkin - I'm not sure what you mean by that. Do you mean I should try to hook both encoder pins to one interrupt pin and try to read both at the same time? I imagine some extremely clever coding could handle that input, but I wonder how it would work.

@retrolefty - Thanks for the info on steps. I did not know that about rotary encoders. That's pretty interesting, actually. So basically, if this encoder has 144 steps (as 12 steps 12 detents leads me to believe), then if I just read one pin, but read both on ups and downs (on all changes), then I could, in theory, receive 288 step resolution? And if I used both pins tracking all changes, I could get 576 pulses per revolution?

I guess in the end, so long as I can read encoder input in both directions, without the commonly-referred-to problem of switching directions and having the software carry on in the original direction for one more step, I should be fine. Also, I don't have to await input from the encoder, but from a button which will tell me to listen to the encoder...

Imagine the crown stem on a pocket watch; turn the knob, and it does nothing, but pull it out to the locking position, and turning the knob sets the time. My setup will work similarly, in that I'll press in on the encoder, having the shaft hit a button, which will signal the MCU to start listening for encoder pulses. So if I'm doing this, there's technically no need for interrupts on the encoder pins? The only thing that will be happening when the encoder is being turned would be tracking the position, making the necessary changes on the display, and then acting on some other code when the button is pressed a second time. If some pulses are accidentally missed or skipped, it won't be that big of a deal, provided it doesn't skip more than ,say, two out of every ten pulses, and never more than one in a row.

So basically, I can get away just fine with attaching my encoder pins to any digital pins on the Arduino and only worry about input from the encoder when I need it, and find the input by specifically looking out for it?

I guess that sounds more or less ideal. If that's how it is, then great. If I've got something wrong, please correct me. :)

Thanks for the help in determining my direction! You guys rock. :D

Any one agree or disagree on what I found in my experiments with my specific optical two channel encoder?

Jumping in late, I can confirm that this is true. You can use it to your advantage to get more resolution out of an encoder than the headline rate. http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html

You don't have to use interrupts but it is easy to loose pulses especially if you are using just software. I favour using a latch to give you direction and step pulses. These are then much easer to deal with in software. You interrupt on the step and look at the direction in the ISR.

The two outputs from the encoder are there so that you can tell what direction the shaft is being twisted.

Mike's hardware is probably "the way to go" for a good result... but for something that "will do", you may get enough quality by putting one of the outputs on your interrupt input, and looking at the state of the other line via a simple input within the code processed when interrupt occurs.

If you succeed.... please write up what you've done on the playground?

@Richard Crowley- So you're saying I can hook one encoder pin to an interrupt pin, and the other to a normal I/O pin, and when the interrupt pin fires, then I know to read data from both pins?

@Grumpy_Mike - Your method of reading encoders is complicated and awesome, but I don't think I have the space for that on my board. Looking at my layout so far, I have about 1.75 square inches of space available on the back of my board, but none of the individual chunks of open space are much larger than 0.25 inches square. I guess an I/O expander might fit, but I might still be better-served by just reading from regular input pins, then.

When the aforementioned button is pressed, and the encoder listener runs, pretty much the only thing the whole unit should be doing is listening to the encoder (and incrementing/decrementing a variable), and updating the LEDs to reflect the rotational position of the encoder. I'd say two to four full rotations of the encoder should approximately equal one full rotation on the (circular) LED matrix. Would I be able to maintain this degree of accuracy by simply reading the encoder through regular I/O pins?

Thanks for your help! :)

Would I be able to maintain this degree of accuracy by simply reading the encoder through regular I/O pins?

As you are rotating this by hand you should get away with it. There is not much of a penalty if you miss out a pulse or two because you have visual feedback of where you are. A mouse works in the same way, you miss lots of pulses but it doesn't matter because you keep pushing until you reach where you are going. It's not like you are using the pulses to determine where something has actually been moved to like in my telescope pointing project.

@tkbyd - Sorry I missed your post. I promise I wasn't ignoring you. I was writing mine while you posted yours. I agree that Mike's solution seems to be very comprehensive, and I will definitely give it a good go on my breadboard. As for putting one pin on interrupt, and reading the other only once the interrupt fires, I will absolutely put it up on the playground when I get it working.

@Richard Crowley - I promise I'll be uploading the complete schematics, board design, and source code, as well as a complete research and build log once I've got the whole project wrapped up; I just want to save it all up for a grand release. :P

Running one pin on interrupt and the other in a standard input should absolutely be sufficient for my purpose, I just hadn't thought of doing that. If Mike's solution is easy enough for me to grasp and implement, I'll be using it in this project, and if not, I will definitely continue to pursue it, since it seems like a fantastic solution overall. Four times the manufacturer-quoted spec...is awesome. That makes even the lamest encoders out there sound like they could be worthwhile.

I'll do some research on flip-flops, since I'm not really even sure what they are or what they do. My basic education in electronics is severely lacking. :P

I might go for a no-interrupt method with the encoder, but that depends on how well my button-to-listen idea works out.

@Grumpy_Mike - Right. I'm not in need of positional information, so skipping a couple here and there is no big deal, especially not if it's consistent. If all else fails, I'll go for something like the Austria Microsystems AS5030, which outputs degree-accurate positional information via serial or PWM. I have a few samples of that chip (they sent me 3 of it and 3 of the AS5035)...though soldering it to something for testing will be extremely difficult due to the incredibly tiny pitch.

UPDATE:

Wow...I must be a little dense. I just re-evaluated the datasheet for the 1286, and realised what the problem was...there are plenty of interrupt pins, I just didn't notice the others because they're not grouped together. I feel like an idiot. The chip actually has 8 interrupt pins, apparently.

INT0 = SCL INT1 = SDA INT2 = TLC5940 GSCLK INT3 = INT4 = DS3231 32kHz INT5 = GND INT6 = INT7 =

So I have three interrupt pins open. I could get by without the 32kHz signal just fine, but the Teensy++ 2.0 schematic shows an optional connection to a 32kHz signal, so I thought I'd take advantage of the included 32kHz signal on the DS3231. Without that connected, I have five interrupt pins open.

So it looks like this problem is moot. :P

Am I crazy, or does this thing really have 8 total interrupt pins?