Using separate IOC pins vs Multiplexing via glue logic - Page 1
Forum section: electronics / general

author: void_error
author_rank: Frequent Contributor
timestamp: August 11, 2016, 04:12:42 pm
content: I'm running out of pins on a 40-pin micro while trying to add more functions. Swapping the micro for one with more I/O pins is out of question because there's no other PIC which has the peripherals I need but with more pins.Initially the 4 pushbuttons and two quadrature encoders would have been read via 4 pins with IOC enabled (pushbuttons) and 4 GPIO pins on an I/O expander (encoders) but I'm trying to reduce the costs by using jellybean logic ICs. These are part of a front panel board.IOC would work just fine but the pins are occupied by some peripherals (core independent) so I'm asking this question: Can I get away with using a 3-to-8 multiplexer like the 74HC251 and scan for changes by selecting its inputs one by one or will it cause problems with detecting short/long presses on the pushbuttons or miss encoder counts?

author: JPortici
author_rank: Super Contributor
timestamp: August 11, 2016, 06:01:30 pm
content: which pic are you using?anyway i'm not sure..let's say that the idle level is low level and IOC is fired after low to high transition.you would have to first put the input low: disable the mux, change and then enable it so you can see if there was a transition when you were checking other signals.. or you could miss a transition, then keep track so you don't check it two timeswhy don't you sample the ports and analyze those instead?sample then xor with previous one. if result is greater than zero you had a transition in the port. check if positive/negative etc

author: void_error
author_rank: Frequent Contributor
timestamp: August 11, 2016, 06:30:21 pm
content: I'm using one of the 16F188xx series, the freshly released ones, like the 16F18855/18875/etc and most of the pins are going to be allocated to peripherals (SPI/I2C/UART/PWM...)Missing a short button press is what I'm worrying about.I'm out of I/O pins which have IOC and I was wondering if I could use something cheaper than an I/O expander.I think the best compromise would be to use IOC for the pushbuttons and a MCP23008 for the encoders, it has IOC and an interrupt pin which can trigger an interrupt on the micro when there's a transition. I2C might not be to slow for this and there's already an I2C bus available with only two more devices, an RTC and an EEPROM.

author: Ian.M
author_rank: Super Contributor
timestamp: August 11, 2016, 06:39:47 pm
content: Encoders generally have far higher pulse rates than user push-buttons and its far more critical not to miss any transitions. Stick the buttons on the i/o expander, the encoders on the PIC's own pins, and poll the encoders fast enough not to miss any state changes at the maximum rate of movement. If you need the encoders to support wake from sleep, use IOC, but *ONLY* while in sleep mode.

author: void_error
author_rank: Frequent Contributor
timestamp: August 11, 2016, 07:03:21 pm
content: Quote from: Ian.M on August 11, 2016, 06:39:47 pmWhy only in while sleep mode? Because of the IOC glitch the older 16F series had?

author: Ian.M
author_rank: Super Contributor
timestamp: August 11, 2016, 07:13:12 pm
content: *MUST* *READ* for anyone who doesn't have a lot of miles under their belt dealing with switches and mechanical encoders:http://www.ganssle.com/debouncing.htmBasically, if you let a switch directly trigger an interrupt with no hardware debouncing it can cause an interrupt storm which may lock up main loop processing until the switch stops bouncing. If its an encoder thats right at its transition point, and there is any source of mechanical vibration, it may continue until the user moves the encoder again. Its acceptable to use an interrupt to detect the initial change, but as soon as it fires ONCE, it should be disabled and the input should be polled until all bouncing has stopped and its been stable for long enough that its likely all movement has ceased, before shutting off the polling timer and reenabling the interrupt.

author: void_error
author_rank: Frequent Contributor
timestamp: August 11, 2016, 07:36:39 pm
content: I'm familiar with that.My usual approach when dealing with bouncy switches (usually pushbuttons) is to use the interrupt only to detect the edge and activate a timer and check again after the timer expired. Add hardware debouncing on top of that - RC low-pass filtering to "clean up" the signal to put it short.I haven't dealt with encoders yet so I'll take your advice regarding those. Not sure about hardware debouncing those.Quote from: Ian.M on August 11, 2016, 07:13:12 pmEncoders with detents, which I'm going to use, should be easier to deal with then... (Bourns PEC11L-4125K-N0020)

author: dannyf
author_rank: Super Contributor
timestamp: August 11, 2016, 10:14:14 pm
content: You didn't say how many pins left for the key reading. So it is hard to help you.I would say that the solution will depend on the mature of the keys you are trying to read. Polling consumes processor power and is slow: you may miss short puleses.For most mcus, using interrupts to read key presses is preferred.If you have to use an io expander, thus, try to pick one that has an interrupt pin so nee key presses will trigger a read of the io expander.

author: void_error
author_rank: Frequent Contributor
timestamp: August 12, 2016, 04:47:16 am
content: I didn't know at the time, but it turns out I have 6 available pins with IOC one on GPIO port after using the I/O expander which has an interrupt pin.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: August 12, 2016, 07:35:13 am
content: Perhaps another option would be to use a very small MCU just for managing the keys and encoders and communicate to the main MCU with I2C or SPI? Are there any PICs in the same region as say an Atmel ATTiny?

author: dannyf
author_rank: Super Contributor
timestamp: August 12, 2016, 04:47:16 pm
content: QuoteWhy is that?Simple:1) the interrupts, external or pin change, are essentially a parallel piece of "code" running that monitor pin states and notify the mcu if the specified conditions have occurred. By offloading such "exeuction" from software to hardware, you free up precious mcu processing capabilities for something else.2) the cost you pay, in terms of overhead and taking care of bounces, is minimum. Say that you press a button 10x per second, and each press generates 20 bounces, and each bounce takes 20 (isr latency/overhead) + 30 ticks (reading + processing) to process, the "wasted" processor power is 10*20*50=10,000 ticks. For a typical 1MIPS mcu, that's 1% of its processing power. Even if we were 10x off, that's only 10% of processing power.Those numbers compare well with polling, especially for infrequent key-presses.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 12, 2016, 10:58:43 pm
content: You rarely need an interrupt on a button apart from wakeup, and for the latter it's often possible to arrange things such that any button causes the wake int, and the buttons can be scanned individually afterwards.I almost always use polling every few tens of mS, which has the added benefit of debouncing "for free".When running out of pins it's unusual not to be able to share at least some, with at most the odd passive or diode, without having to resort to extra ICs, YMMV obviously depending on details.for example with a 44780 type LCD, the LCD doesn't care what happens when enable is inactive, so you can use the data lines for button inputs, with just some resistors to prevent the buttons messing up the LCD data.

author: David Hess
author_rank: Super Contributor
timestamp: August 13, 2016, 03:40:39 am
content: I prefer using SSI type shift register logic for I/O expanders controlled with an SPI interface which can be bit-banged if necessary. With cleverness, chip select and load can be combined to get the interface down to 4 pins for clock, data out, data in, and CS/Load. On the programming side, the interface is polled through an interrupt service routine slaved to a timer which is probably acting as the local CPU interrupt task timer anyway. The ISR handles debouncing since it already has a stable time interval to work with. The main program accesses the input and output state through shadow registers.Look for the 74165 and 74595 in the logic family of your choice.

author: void_error
author_rank: Frequent Contributor
timestamp: August 13, 2016, 07:22:22 am
content: Quote from: mikeselectricstuff on August 12, 2016, 10:58:43 pmTriggering an interrupt if any of the buttons if pressed which in turn triggers scanning (multiplexing) of the buttons might only require one extra pin with some of the glue logic already in place.Quote from: David Hess on August 13, 2016, 03:40:39 amI'm already doing that to light up the pushbuttons' LEDs. 74HC595 used.CPU interrupt task timer - didn't know how to call it, thanks.Quote from: David Hess on August 13, 2016, 03:40:39 amOr in other words the main program would be a state machine with the state set by the value of the inputs and/or the task timer value? That would be my approach. I want to be able to read pushbutton presses and changes in the encoder states while communicating with SPI & I2C peripherals and updating a UC1701 based display in parallel mode.As I already have a 74HC595 and cascading them doesn't require extra MCU pins I think I'll go with something similar to the solution presented by dannyfhere.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: August 13, 2016, 07:28:13 am
content: Quote from: David Hess on August 13, 2016, 03:40:39 amYou can combine data in & out on one pin with a resistor. And possibly also share clock or latch with another function.Or drive latch via an RC filter from clock to make it automatically latch after receiving a clock burst.

author: 22swg
author_rank: Frequent Contributor
timestamp: August 13, 2016, 08:24:28 am
content: Its possible to hang a 4 bit LCD and 3x4 key pad on a MCP3008 expander , with interrupt back to pic for the key pad ...

author: David Hess
author_rank: Super Contributor
timestamp: August 14, 2016, 03:55:17 am
content: Quote from: void_error on August 13, 2016, 07:22:22 amOn these little microcontrollers, I always end up dedicating one timer to generating a periodic "upkeep" interrupt which counts down to trigger a slower "upkeep", etc. That allows various upkeep routines to be executed at different time intervals while only taking one timer peripheral.Often the upkeep routines will continue to run even if the main program crashes so basic monitor functionality can be built in for diagnostic purposes.QuoteI do not know if they still use the term "shadow register" but it was common back when the 6502 was used. It is just a global memory location which is used to communicate between the main routine and any interrupt routines or hardware. A shadow register often mirrors an actual hardware register. On the Atari 800, there was a whole set of shadow registers which were copied out to hardware registers on every jiffy (1/60th of a second linked to the video vertical refresh rate) by an ISR. Software could not read the output only hardware registers but could read the shadow registers to find out what the current programmed hardware state is. These days you can usually read the output state directly so the shadow register is built in.A set of shadow registers for instance could be copied in and out to hardware periodically by the ISR (or hardware via DMA) to update the display. For reading keyboards, I implemented a couple of state registers and shadow registers so on a detected keypress down, the bits in a shadow register are set by the ISR for the main program to read and reset. Shadow registers for counting up and down could be used for keypress controlled continuous value scrolling or whatever.QuoteThe 74HC595 can also be cascaded with the 74HC138 so inputs and outputs are done simultaneously.This timer/ISR/shadow register method of programming would probably not work well for reading encoders for performance reasons; they would have to be handled separately although I might use shadow registers between the encoder routines and one level of the CPU housekeeping interrupt task levels.Quote from: mikeselectricstuff on August 13, 2016, 07:28:13 amI almost wrote about combining the input and output using a resistor and tristate capability of the microcontroller I/O pin but this excludes the possibility of using the existing SPI peripheral for faster access.I never bothered deriving the latch from the clock because I worried that the read latch would come too late. I always included 74165s and 74595s in series so CS falling latched the inputs and CS rising latched the outputs.This way of doing things however also means every read is a write and every write is a read explaining the need for shadow registers to hold output and input state.

author: void_error
author_rank: Frequent Contributor
timestamp: August 14, 2016, 06:24:03 am
content: Quote from: David Hess on August 14, 2016, 03:55:17 amThe two encoders will be directly connected to the micro, using Interrupt-On-Change to detect transitions and a timer for debouncing.I went with dannyf's solution since I had 4 unused pins on a 75HC595. I've got an almost finished schematichere. Some component values will most likely be tweaked after I assemble the first board.This is how I plan to read the pushbuttons:Set the outputs of the 74HC595 which are connected to the buttons high and enable a low to high IOC on RA1 pinWhen RA1 goes high it means one of the buttons was pressedDisable IOC on RA1 and set the 4 pins tied to the pushbuttons high one by one and read the value on RA1 to determine which one is pressed. That will require data to be shifted into the 595s 4 times. With an 8MHz SPI clock it won't take long.Re-enable IOC when none of the pushbuttons is pressed anymore

author: Howardlong
author_rank: Super Contributor
timestamp: August 14, 2016, 06:57:40 am
content: Quote from: Ian.M on August 11, 2016, 07:13:12 pmThe method I use is with IOC, but although I permanently enable the IOC interrupt as a whole, I disable the IOC rise or fall notifications independently and dynamically, depnding on state, avoiding interrupt storming. It relies on the fact that the encoder should never bounce on both pins at the same time, and that you can imdependently enable and disable both the rising and the falling edges. You also avoid the use of a timer that way.It was originally described herehttp://www.microchip.com/forums/m933132-p2.aspxand the code for a 10f322 is herehttp://www.microchip.com/forums/download.axd?file=0;933663