« Close

Datasheets and User Guides

App Notes

Software & Driver

 

13.1.11 Quadrature In

Capable DIO: FIO0, FIO1, FIO2, FIO3, FIO6, and FIO7

Requires Clock Source: No

Index: 10

 
Quadrature input uses two DIOs to track a quadrature signal. Quadrature is a directional count often used in rotary encoders when you need to keep track of absolute position with forward & reverse movement.  If you have movement in only one direction, or another way to know direction, you can simply use a normal counter with one phase of the encoder output.

The T7 uses 4x quadrature decoding, meaning that every edge observed (rising & falling on both phases) will increment or decrement the count.

This interrupt-based digital I/O extended feature (DIO-EF) is not purely implemented in hardware, but rather firmware must service each edge.  See the discussion of edge rate limits at the bottom of this page.

Quadrature is prone to error if the edge rate is exceeded. This is particularly likely during direction change where the time between edges can be very small. Errors can occur when two edges come in too quickly for the device to process, which can result in missed counts or missed change in direction. These errors will be recorded and the quantity encountered can be read. If three edges come in too quickly an undetectable error can occur.

Some quadrature encoders also include a third output channel, called a zero (Z-phase) or index or reference signal, which supplies a single pulse per revolution. This single pulse is used for absolute determination of position. The T7 supports resets according to this reference signal. Z-phase will reset the count when a high state is detected on the specified DIO line at the same time any edge occurs on A or B phases.   If the reference pulse is wider than A/B pulses, consider using the Conditional Reset feature instead of this Z-phase support.  If the reference pulse is only high in between A/B edges consider some sort of RC circuit to elongate it or using the Conditional Reset feature.  If set to one-shot mode, Z-phase will clear the count only once and must be "re-armed" by disabling/re-enabling the feature or a read from DIO#_EF_READ_A_AND_RESET.

 

Configure

Configuring the T7 for quadrature requires configuring two DIO. The two lines must be an adjacent even/odd pair. FIO0/1, FIO2/3, and FIO6/7 are valid pairs. The even IO line will be phase A and the odd will be phase B.

DIO#_EF_ENABLE: 0 = Disable, 1 = Enable
DIO#_EF_INDEX: 10
DIO#_EF_OPTIONS: Not used.
DIO#_EF_CONFIG_A: Z-phase control: 0 = Z-phase off, 1 = Z-phase on, 3 = Z-phase on in one shot mode.
DIO#_EF_CONFIG_B: Z-phase DIO number.
DIO#_EF_CONFIG_C: Not used.
DIO#_EF_CONFIG_D: Not used.

 
Update

No update operations can be performed with Quadrature In.

 

Read

The quadrature count and error count are available from the even channel. The odd channel will return zeros.

DIO#_EF_READ_A - Returns the current count as a signed 2's complement value.
DIO#_EF_READ_B – Returns the number of detected errors.
DIO#_EF_READ_A_F - Starting with firmware 1.0114, READ_A_F will return the count in a single precision float (float32). 

 

Stream Read

All operations discussed in this section are supported in command-response mode.  In stream mode, you can read from the integer READ registers (A, B, A_AND_RESET), but as mentioned in the Stream Section those reads only return the lower 16 bits so you need to also use STREAM_DATA_CAPTURE_16 in the scan list to get the upper 16 bits.

 

Reset

DIO#_EF_READ_A_AND_RESET – Performs the same operation as DIO#_EF_READ_A, then sets the count to zero.

 

Example

Configure FIO2 & FIO3 as quadrature inputs:

DIO2_EF_ENABLE = 0    //Make sure DIO-EF is disabled on FIO2
DIO3_EF_ENABLE = 0    //Make sure DIO-EF is disabled on FIO3

DIO2_EF_INDEX = 10    //Set feature index for FIO2 to quadrature.
DIO3_EF_INDEX = 10    //Set feature index for FIO3 to quadrature.

DIO2_EF_ENABLE = 1    //Enable quadrature DIO-EF on FIO2, for A phase.
DIO3_EF_ENABLE = 1    //Enable quadrature DIO-EF on FIO3, for B phase.

Edges on the two lines will now be decoded and the count will be incremented or decremented according to the edge sequence.

The current count can be read from:
DIO2_EF_READ_A or DIO2_EF_READ_A_AND_RESET

To enable z-phase connected to FIO5 you would do:

DIO2_EF_CONFIG_A=1
DIO2_EF_CONFIG_B=5
DIO3_EF_CONFIG_A=1
DIO3_EF_CONFIG_B=5

 

Testing

On some LabJack devices you can randomly tap a GND wire into FIO2 and FIO3 to cause some counts, but that does not work on the T7.  Testing needs to be done with a proper quadrature signal.

If testing with an actual encoder, first start with DIO-EF enabled and simply watch (e.g. in Kipling) the digital inputs as you slowly turn the encoder to see if the inputs change between high and low.  That confirms a valid electrical connection.

You can test using 2 digital inputs to create a quadrature sequence.  For example, configure quadrature on FIO2/3 as shown above, and connect FIO0 to FIO2 and FIO1 to FIO3. 

FIO0 = 1    //Initialize FIO0 to output-high.
FIO1 = 1    //Initialize FIO1 to output-high.

DIO2_EF_ENABLE = 0    //Make sure DIO-EF is disabled on FIO2
DIO3_EF_ENABLE = 0    //Make sure DIO-EF is disabled on FIO3
DIO2_EF_INDEX = 10    //Set feature index for FIO2 to quadrature.
DIO3_EF_INDEX = 10    //Set feature index for FIO3 to quadrature.
DIO2_EF_ENABLE = 1    //Enable quadrature DIO-EF on FIO2, for A phase.
DIO3_EF_ENABLE = 1    //Enable quadrature DIO-EF on FIO3, for B phase.

Now we can simulate a quadrature signal by toggling FIO0 and 1 in the proper sequence.  We will use the FIO_STATE register (address=2500) which operates on all 8 FIO bits at once, but we will set the inhibit bits for FIO2-FIO7 (bits 10-15) so they are not affected.  To set bits 10-15 we can simply add 64512 to the desired FIO0/1 state value:

Write FIO_STATE = 3 + 64512, then should read DIO2_EF_READ_A = 0.
Write FIO_STATE = 1 + 64512, then should read DIO2_EF_READ_A = 1.
Write FIO_STATE = 0 + 64512, then should read DIO2_EF_READ_A = 0.
Write FIO_STATE = 2 + 64512, then should read DIO2_EF_READ_A = -1.
Write FIO_STATE = 3 + 64512, then should read DIO2_EF_READ_A = -2.
Write FIO_STATE = 2 + 64512, then should read DIO2_EF_READ_A = -1.
Write FIO_STATE = 0 + 64512, then should read DIO2_EF_READ_A = 0.
Write FIO_STATE = 1 + 64512, then should read DIO2_EF_READ_A = 1.
Write FIO_STATE = 3 + 64512, then should read DIO2_EF_READ_A = 2.
Write FIO_STATE = 2 + 64512, then should read DIO2_EF_READ_A = 3.
Write FIO_STATE = 0 + 64512, then should read DIO2_EF_READ_A = 4.
Write FIO_STATE = 1 + 64512, then should read DIO2_EF_READ_A = 5.
Write FIO_STATE = 3 + 64512, then should read DIO2_EF_READ_A = 6.
Write FIO_STATE = 2 + 64512, then should read DIO2_EF_READ_A = 7.

 

Quadrature Decoding or Simple Counting?

Quadrature decoding is only needed when you need to keep track of absolute position with changes in direction included.

If you want to track absolute position but the direction does not change, or for whatever reason you always know the direction of movement, then you can just count the pulses from one phase (A or B) using a simple counter.  The interrupt counters available on 6 of the FIO0 lines have the same 70k edge rate limit discussed below, but they only do 1x counting and only use 1 timer.  The high-speed counters on the 4 CIO lines can handle up to 5 MHz per counter.

If you are just trying to measure frequency, you can use a counter as described above and note the change in count over some time interval, or you can use a DIO-EF that measures the time of individual pulses.  Either way just one phase (A or B) is needed.

 

Edge Rate Limits

Keep in mind that the T7 does 4x quadrature counting, so for example a 100 pulses/revolution encoder will generate 400 edges/revolution.

This interrupt-based digital I/O extended feature (DIO-EF) is not purely implemented in hardware, but rather firmware must service each edge. This makes it substantially slower than other DIO-EF that are purely hardware-based.  To avoid missed edges, the aggregate limit for edges seen by all interrupt-based DIO-EF is 70k edges/second.  If stream mode is active, the limit is reduced to 20k edges/second.  Excessive processor loading (e.g. a busy Lua script) can also reduce these limits.

The more proper way to think of the edge limit, and understand error that could be introduced when using multiple interrupt-based DIO-EF, is to consider that the interrupt that processes an edge can take up to 14 μs to complete.  When a particular channel sees an applicable edge, an IF (interrupt flag) is set for that channel that tells the processor it needs to run an ISR (interrupt service routine) for that channel.  Once an ISR is started, it runs to completion and no other ISR can run until it is done (except that stream interrupts are higher priority and will preempt other interrupts).  When an ISR completes, it clears the IF for that channel.  So it is okay to have edges on multiple channels at the same time, as long as there is not another edge on any of those channels before enough time to process all the initial edges.

Say that channel A & B have an edge occur at the same time and an ISR starts to process the edge on channel A.  If channel A has another edge during the first 14 μs, that edge will be lost.  If channel B has another edge during the first 14 μs, the initial edge will be lost.  If channel B has another edge during the second 14 μs (during the ISR for channel B), the new edge will be lost.

 

For faster quadrature tracking, an option is to use a chip such as the LFLS7366R-S from US Digital and then use the SPI ability of the T7 to talk to that chip.  In fact, a Lua script can be used to handle the SPI communication with the chip and periodically put the current count in a user-ram register than can be easily read by any host application or modbus client.  If you don't find an example for the LFLS7366 ask us about it.

 

19 comments

Hi,

to know the maximum count rate I need to know the "wide edge rate limitation" time or frequency. Please specify it.

Thank you for reminding me to fill that in.

Specifications for edge rate have been added.

I seem to have an issue using quadrature with an encoder with a resolution of 1024 ticks/rotation. The encoder measures a geared motor with a top speed of 0.23 RPS. Considering the gearing , the number of expected ticks at max speed is ~72,432 ticks/sec.  Using a python script I can monitor the ticks through the terminal. The problem occurs as the speed approaches maximum and the terminal printout appears to seize until the motor is either stopped. Strangely, the number of ticks appears to update correctly once the seizure has stopped.  I noticed that the "Input Timer Total Edge Rate" is only 30k edges/sec while streaming. Can I either can reduce the update rate / stream to accommodate or will I need to use an encoder with lower resolution? Thanks for any help as usual.  

Hi,

Please add documentation how to configure and use Z-channel support (Resetting counter on event at digital input).

Thank you very much in advance!

Best regards,

Martin

Hi,

Thank you very much for the updated documentation.

The quadrature feature seems to work fine, with one (minor) problem: My Z-phase signal is inverted. Do I need a hardware-inverter or would it be possible to add handling of inverted Z-phase signals in firmware?

Thanks!

Best wishes,

Martin

We can add a polarity option to firmware for you. With a little luck it will be in the next beta.

Thank you very much for offering this. I will be able to work with an inverted level-triggered Z-phase input. However, as mentioned in comment#4, I believe that it would be more correct - not only for my application, but in general- to reset quadrature-counter based on edges. Imho, level-based reset is incorrect whenever the Z-pulse is wider than 1/4 pulse of the A or B phase. This is the case in my application. My 0° mark on the crankshaft of my test-stand covers a crankshaft angle of about 10degrees. My encoder has 360 tics per rev and with 4-edge evaluation, this results in 1440 edges per rev and makes an angular resolution of 1/4 degree. If Z-phase reset is level-triggered, then the quadrature-counter would count from zero to 350° (about 1400 ticks), then be held at zero during the next 10degrees of crankshaft angle and would then continue counting correctly.

The z-phase is level triggered because the IO interrupt system has unusual limitations. I do have a couple ideas that might help:

 

  • The One-Shot option: One-Shot mode already exists. In one-shot mode the z-phase will only reset the count once.
  • A new quadrature option that would require the z-phase to go to the inactive state before clearing the count.
  • A new DIO_EF that will reset or stop timers. This index would use one of the 6 pins that quadrature can run on (FIO 0,1,2,3,6,7).

Thank you very much for your reply and for sharing your thoughts.

I have considered the one-shot option before contacting you. It will certainly work for a while, but once the counter overflows, (in my application after 1,491,308.0889 rotations, which will occurr after about 16.57 hrs) the phase-relationship will be lost. I am not sure myself whether this constraint is a problem, but it is not entirely unthinkable that a test will last long enough for an overflow to occurr.

I like the other two ideas.

I would be especially in favour of your proposal for a new DIO_EF that would reset or stop timers if it could not only reset the quadrature counter but also the high-speed counter.

Greetings from Germany,

Martin

Beta firmware 1.0134 has a new digital feature called "Conditional Reset" (name may be changed). It can reset the count of other DIO_EF features.

*THIS IS JUST GREAT!*

The new funktion works perfectly! Thank you very much for implementing this feature.

I am convinced that this is not just helpful for my project, but moreover I believe that this funtion is handy for many applications and it is also imho the proper way to handle Z-phase in general.

I am truly impressed with how you guys handle user feedback.

Greetings from Germany,

Martin

Hi, 

I've been using the "AddRequest" function for UE9 labjack (old library) in Matlab to read quadrature input. I recently bought the T7-Pro and looking at the Matlab library provided, this function seems to have been taken out. Is there an equivalent function in the new T7 library that I can use to set a pin(s) to continuously read the quadrature input? 

I saw the WatchDog function, but I prefer this to be done on internal timer and in hardware, as opposed to constantly calling a Matlab read function. 

Thanks!

With the UE9 you wrote some things to configure a timer in quadrature mode, and then would read the timer value whenever you want to get the current count.  Similar with the T7 as shown in the example above, but rather than a timer mode it is called a Digital I/O Extended Feature (DIO-EF).  You write some registers to configure and then read a register to get the count.  If you are using LJM, then start with the simple eWriteName and eReadName functions.

Hi,

sorry to bother you again.

I am trying to stream the results of the quadrature-counter to my host-PC using LabView.

So far I have been successful, but apparently only the lower significant 16 bits of the 32bit counter are streamed out. Therefore the counter seems to overflow at 64kcounts.

When reading the counter in C/R mode, all is fine.

My encoder is connected to FIO0/1 digital input pair, with Z-phase on FIO2.

I have tried streaming registers DIO0_EF_READ_A (3000d), as well as register DIO0_EF_READ_A_F (3500d). Both registers show the identical symptom.

I use latest LJM, latest LabView wrapper and samples. LabView 2014 32bit on WINXP32. Firmware 1.0126beta.

Any ideas?

 

Thanks in advance!

Best,

Martin

 

The data-stream return by stream is 16-bits wide. If you stream a 32-bit address such as DIO0_EF_READ_A the upper 16-bits are saved in STREAM_DATA_CAPTURE_16. To get the full 32-bit value you need to stream DIO0_EF_READ_A followed by STREAM_DATA_CAPTURE_16 and recombine the values in software.

 

Thank you very much for the immediate response!

The proposed solution works for me, so I can continue with my project, which is my main concern.

As a low-prio side-note, I do not understand why using the STREAM_DATA_CAPTURE_16 register is necessary. Doesn´t the function LJM_eStreamRead return doubles (64bit)? And, AINs work fine, also without the need for the STREAM_DATA_CAPTURE_16 register, although AIN results are 32bit registers.

Best regards,

Martin

A normal analog input is transferred as a 16-bit binary value and then LJM converts it to a float using the cal constants that it reads before starting a stream.  Added some detail to Section 3.2.

This absolutely makes sense!

Thank you very much for this clarification and for updating section 3.2. This is really helpful and greatly appreciated!

Have a great day!

Best,

Martin