'Quadrature decode, interrupt-on-change problem sol'
Heavy stuff... Please don«t fall asleep; interrupt-on change discussion at
the end... ;)
I use to build quadrature decode systems in another way than I«ve seen you
talking about in the telescope control discussion. As I think it works
very well and can be nicely implemented in PICs, I decided to share it with
The description below is based upon a system I built to position a large
machine in an industry, and I have added some new details to try building a
I have never seen any other system using this method.
Please tell me what you think about it!
To send the pulses over long distance, use two differential line drivers
with matched impedance into one cable of two shielded twisted pairs.
(Maybe a third one for the zero position signal)
Equally for both A and B channels:
The recievers also has cable matched impedance.
They each feed a RC delay and schmidt-trigger.
The time constant based om max interrupt process time (below).
The schmidt-triggers then connected to a XOR gate, which other input was
>from a microcontroller (MC6805K1) output pin. The outputs from the XOR
gates directly to the microcontroller. The pins generate a interrupt on
(On the 6805K1 I used an extra external gate to generate a combined input
to INT input pin from the two XOR gates)
The microcontroller acknowledges the last position by setting the outputs
to the XOR gates to the same. When one channel change, the XOR output goes
high, and the controller executes the interrupt routine.
The interrupt routine read the pins in to internal register.
Then immediately outputs the new state it computes easily since it is just
XOR of the input and current output.
It checks if both XOR inputs were high; if so then error (double step (or
2*n) since last decode.)
Then check if no one is changed! This happens if the routine is called by
mistake (program error) heavy noise, hardware error etc.
If no error then compute what move has happened, and just
increment/decrement a buffer counter register, checking also for overrun of
buffer. It detects both positive and negative transistion on both channels
so it gives the highest possible resolution: four steps per encoder cycle
If any pin still high then run again. (return from interrupt only when
everyting done, to save overhead time; at very high count rate this routine
will be computing two steps per interrupt, (since it acknowledges the new
state early (see above)), and the system is still working.
The main program then transfer counts from the buffer counter to the main
counter and process. Thanks to the buffer counter the system accepts very
high count frequency, like when the machine is vibrating and the decoder
quickly moves forvard and backwards. Using minimum process time.
The system seem very reliable and routine is fast. Could be even faster
using a PIC!
(Or an SX!!)
So, for an up-coming project I plan to use a PIC.
As a lot of you probably have realized the cirquit with the XOR described
above is similar to the Interrupt-on-change feature of some PICs.
Nice, but there are one potentially nasty problem with that, though...
Read in Microchip 1996 PIC14000 preliminary datasheet DS40122B:
" 10.6.3 PORTC INTERRUPT ON CHANGE "
" Note: If a change on the I/O pin should occur
when the read operation is being executed
(start of the Q2 cycle), then the RCIF
interrupt flag may not be set. "
... And we have a high frequency of potential misses, and one miss is too
¤ Only the service routine may read (or use read-manipulate-restore) port C.
¤ Other routines may execute clean writes to port C (not BSF, INCF etc)
This will do it, if we design the input filters and schmidt-triggers to
never output too short pulses (same length positive or negative): In order
to guarantee that the routine called by the interrupt-on-change always read
the input before it changes next time.
But I would like also to use the other inputs with interrupt on change.
I«ts OK, You may think: just let the routine process the other pins too.
NO!! Because we have no time guarantee!
Example: One signal change so the interrupt routine is called and read port C.
A pin that changes while that routine is reading port C, _may_ neither be
read that time, nor set the pending bit!
- Begin bad idea
Maybe we say: OK don«t use the other interrupt on change pins, but use the
ones without interrupt as normal inputs?
For other routines to read port C, they may disable interrupt and call the
decode routine in order to get it to read in data from Port C? If inputs
has changed when the decode routine read the new quadrature data then it
will execute on it. If the routine detects no change in quadrature when
having read port C it shall exit.
- End bad idea
What happens if the decode routine is called like above, without any change
on quadrature inputs have occourred yet, but the quadrature input(s) change
while reading the port??
BAD thing: old value is processed (no change) and the port change interrupt
pending flag is not set until input changes another time! Then the encoder
will either have moved two steps or back to none relative the last
processed position. This is a fault!
¤ Only the two quadrature inputs should generate interrupt on change
(configure other pins as outputs or I2C to disable their interrupt
¤ Never call this routine unless a change has ocurred (pending flag set)
The processor may never be busy (like doing other interrupts, or processing
a routine that temporarily disables interrupt) for longer time than needed
to jump to the decode routine and having read the port C.
One remedy would be that the routines that work in interrupt disabled mode
often enough check the interrupt on change pending flag and calls the
quadrature decode routine when needed.
Hum... Lets try to create a simple circuit work like the one I made with
the MC6805 and external gates !
METHOD TO _AT_ANY_TIME_ CALL THE QUADRATURE DECODE ROUTINE IN ORDER TO READ
If we make sure that the compare register on port C interrupt-on-change
logic always gets loaded with the value that the routine has as input,
there will be no problems.
METHOD TO LOAD THE READ DATA INTO INPUT COMPARE REGISTER
First we add resistors in series with the input pins on port C,
as we will (very shortly) set them as outputs! (R=approx 1k - 10k ohm.)
For schematic on Port C see:
Microchip 1996 PIC14000 preliminary datasheet DS40122B FIGURE 5-3 and 5-4
The compare latch is the most lowest in the schematics.
Read and write port C routine:
1 Read port C to PORTC_known register in RAM (reads input pins)
* Mask bits in output pin positions using OR (optionally, see (*) below)
* AND with PORTC_out (optionally, see (*) below)
2 Write Port C with the result (writes to the output latch)
3 Set all pins as outputs ("input" pins will win over outer cirquitry
because of the resistors)
4 NOP (Needed to stabilize output, I read Microchip recommended it when
5 Read port C (Reads pins = output latch = known_state into compare
register (as well as W))
6 Set input pins as inputs (those we added resistors to)
7 Clear port C interrupt-on-change pending flag (see (7) below)
Now we have the read data in PORTC_known register, and guaranteed
_the_same_ in the compare register.
As the routine and compare register see the world the same way we will have
no "scizzofrenia" problems about however pins are changed or not.
(*) Optionally, if some of the pins are outputs, this routine can take care
of writing the data to them too.
Any other routine may write a byte directly to port C if it is not
interrupting between the read and write of the routine above, of course.
But never use read or read-modify-write! HOWEVER: If there should be a
temporary glitch on one output pin as it is read by the routine above, it
will then be recritten with the value of that glitch! Not likely to occour,
but to be safe, include the lines with * and write to port C by setting
PORTC_out register and call the routine above.
(7) If inputs changed during the first read of port C, the pending flag
will be set even when we tried to clear it. So if changes occourred then or
before end of this routine, it will be processed when this routine before
exit test to run again if the flag then is set.
Now we can call the port C read routine anytime; with or without
And we can have asynchronous interrupt-on-change inputs processed correctly!
¤ The only routine reading from the port must be the port C read routine
¤ After that routine is processed _all_ routines that handles change on
port C signals _must_ be processed before next read!
¤ Good idea is to check if interrupt-on-change pending bit is set, directl
when the routines to handle them are done, and in that case go for it again!
¤ No routine may read port C or even use BSF or other read-modify-write
instructions on port C!) They may make a clean byte-write, but se (*) above!
¤ To output to pins in port C in a safe way, include the lines with * and
write to port C by setting the bits as desired in PORTC_out register and
call the routine above.
¤ A routine that wish to know a state of a pin on port C which is not a
interrupt on change pin, may call the port C read routine (which then
executes all interrupt on change routines in case there happened to be new
data for them). Then the calling routine reads the input in the PORTC_known
This seem to be a watertight solution.
Anyone who see a doubt, please tell!
So, we can enable interrupt on change on all pins, and have the position
zero signal on one of them, and then we can guarantee zero position is
interpreted quickly and without a puls on quadrature signals.
- Puh... - it«s in the middle of the night now... -
Anyone have comments on the quadrature decoding above?
Have I understood the interrupt-on-change functions correctly?
In all this text I might also have made other mistakes...
Morgan Olsson, MORGANS REGLERTEKNIK, Sweden, ph: +46 (0)414 70741; fax 70331
More... (looser matching)
- Last day of these posts
- In 1998
, 1999 only
- New search...