The MCHP_QEI block provides an interface to the Quadrature Encoder Interface (QEI) peripheral available on dsPIC and PIC32 microcontrollers. This peripheral decodes quadrature encoder signals to measure position, direction, and velocity of rotating shafts, making it ideal for motor control and precision positioning applications. Key Features:
| Family | QEI Type | Max Modules | Features |
|---|---|---|---|
| dsPIC30F | 16-bit | 1-2 | Quadrature decoding, index reset |
| dsPIC33F | 16-bit | 1-2 | Quadrature decoding, index reset |
| dsPIC33E | 32-bit | 1-2 | Extended position counter, velocity measurement |
| dsPIC33C | 32-bit | 1-2 | Extended position counter, velocity measurement |
| dsPIC33A | 32-bit | 1-2 | Enhanced position/velocity, advanced filtering |
| PIC32MK | 32-bit | 1-2 | Extended features, modulo with index reset |
| Parameter | Options | Description |
|---|---|---|
| QEI Mode | β’ Quadrature Encoder | β’ External Pulse Counter |
| X2/X4 Mode | on/off (16-bit QEI only) | X2: 2 counts/line, X4: 4 counts/line |
| Parameter | Options | Description |
|---|---|---|
| Position Output | β’ is not an output | β’ 16-bit unsigned |
| Position Reset Mode | β’ Never reset | β’ Reset on INDEX |
| Modulo Limits | [Low High] vector | Position counter modulo boundaries |
| Initial Value | Integer | Position initialization value |
| Parameter | Options | Description |
|---|---|---|
| Index Counter Output | β’ is not an output | β’ 16-bit unsigned/signed |
| Index Match Value | QEA/QEB state (00, 01, 10, 11) | Encoder state when index is valid |
| Index Polarity | Active high/low | Index pulse polarity |
| Parameter | Options | Description |
|---|---|---|
| Velocity Output | β’ is not an output | β’ 16-bit unsigned |
| Period Output | β’ is not an output | β’ 16-bit unsigned |
| Max Period | Time (seconds) | Maximum period for velocity calculation |
| Parameter | Options | Description |
|---|---|---|
| Digital Filter | on/off | Enable input signal filtering |
| Filter Cutoff Freq | Frequency (Hz) | Low-pass filter cutoff frequency |
| Swap QEA/QEB | on/off | Reverse encoder direction |
| Invert Polarity | QEA, QEB, INDEX, HOME | Invert input signal polarity |
| Pin | Function | Description |
|---|---|---|
| QEA/QEIA | Phase A Input | Encoder channel A (or pulse input) |
| QEB/QEIB | Phase B Input | Encoder channel B (or direction input) |
| INDEX/QEINDX | Index Input | Index pulse for position reset |
| HOME/QEIHOM | Home Input | Home reference signal (optional) |
The block supports 4 output datatype representations for position:
| Output Type | Range | Description |
|---|---|---|
| 16-bit unsigned | 0 to 65535 | Raw encoder counts (unsigned) |
| 16-bit signed | -32768 to 32767 | Raw encoder counts (signed, bidirectional) |
| 32-bit unsigned | 0 to 4,294,967,295 | Extended position (32-bit QEI only) |
| 32-bit signed | Β±2,147,483,647 | Extended signed position (32-bit QEI only) |
All outputs are raw encoder counts transferred directly from peripheral registersβno runtime computation. Users handle conversion to physical units (degrees, radians, RPM).
Hardware Considerations: dsPIC30F/33F/33E/33C lack hardware FPUβperform fixed-point arithmetic in time-critical loops. dsPIC33A has hardware FPU.
Counts_Per_Rev = PPR Γ 4; % X4 mode (or PPR Γ 2 for X2 mode)
Position_rad = QEI_Position Γ (2 Γ Ο / Counts_Per_Rev);
Position_deg = QEI_Position Γ (360 / Counts_Per_Rev);
Example: 500 PPR encoder in X4 mode = 2000 counts/rev:
Position_deg = QEI_Position Γ 0.18Position_rad = QEI_Position Γ 0.00314Velocity output (if enabled) is position difference per sample period:
Velocity_RPM = Velocity_counts Γ (Sample_Rate Γ 60 / Counts_Per_Rev);
In X4 mode, the QEI peripheral counts on both rising and falling edges of both channels, providing 4 counts per encoder line: QEA ββββββββββββββββββββ___ β β β β β β β β βββββ βββββ βββββ βββββ QEB βββββββββββββββ___ββββ β β β β β β β ____βββββ βββββ βββββ ββββ Count: 0 1 2 3 4 5 6 7 8 9 10 11 12 Direction: FORWARD (QEA leads QEB by 90Β°)
In X2 mode, only one edge per channel is counted, providing 2 counts per encoder line: QEA ββββββββββββββββββββ___ β β β β β β β β βββββ βββββ βββββ βββββ Count: 0 1 2 3 4 5 6 (Rising edges of QEA when in X2 mode)
The index pulse provides absolute position reference. It can reset the position counter when specific conditions are met: QEA ββββββββββββββββββββββββ β β β β β β β β β β β β β β β β QEB __βββββββββββββββββββββ_βββ INDEX ______ββββββββ β β Position: … β 47 β 48 β 0 β 1 β 2 β … β Reset on INDEX
// QEI Control Register QEICONbits.QEIM = 0b110; // X4 mode, reset on index match QEICONbits.POSRES = 1; // Index pulse resets position QEICONbits.SWPAB = 0; // No swap of QEA/QEB QEICONbits.TQCS = 0; // Internal clock QEICONbits.UPDN = 1; // Direction (read-only)// Position Counter POSCNT = 0; // Current position MAXCNT = 1999; // Modulo at 2000 (500 PPR Γ 4)// Digital Filter Control DFLTCONbits.QECK = 0b100; // Clock divider for filter DFLTCONbits.QEOUT = 1; // Enable digital filter
// QEI Control Register QEICONbits.QEIEN = 1; // Enable QEI QEICONbits.PIMOD = 0b110; // Modulo count mode QEICONbits.IMV = 0b11; // Index match: QEA=1, QEB=1 QEICONbits.INTDIV = 0b011; // Velocity timer prescaler QEICONbits.CCM = 0b00; // Quadrature encoder mode// Position Counter (32-bit) POSCNTH = 0; // Position high word POSCNTL = 0; // Position low word// Modulo Limits QEILEC = 0; // Lower limit (32-bit) QEIGEC = 1999; // Upper limit (32-bit)// I/O Control Register QEIOCbits.SWPAB = 0; // Swap QEA/QEB QEIOCbits.OUTFNC = 0b00; // No output function QEIOCbits.QFDIV = 0b100; // Digital filter clock divider QEIOCbits.FLTREN = 1; // Enable digital filter// Velocity/Period Capture VELCNT = …; // Position delta (velocity) INTCNT = …; // Period counter
// Similar to dsPIC33E with additional features: QEICONbits.PIMOD = 0b111; // Modulo + index reset (MK only)
Hardware: 500 PPR (Pulses Per Revolution) incremental encoder
Configuration:
Resolution Calculation: // 500 PPR Γ 4 (X4 mode) = 2000 counts/revolution Counts_per_rev = 500 * 4 = 2000; Degrees_per_count = 360 / 2000 = 0.18Β°; Radians_per_count = 2Ο / 2000 = 0.00314 rad; // In Simulink/MATLAB Position_rad = QEI_Position * (2pi/2000); Position_deg = QEI_Position * 0.18; Note: Set modulo limits to [0, 1999] so position wraps at 2000 counts (one full revolution). For signed output, use [-1000, 999] for symmetric range.
Method 1: Position Difference // Simulink blocks: QEI Position β [Unit Delay] β Subtract β Velocity (counts/sample) ββββββββββββββββββββ // Convert to RPM (1 kHz sample rate, 2000 counts/rev) Velocity_RPM = (Position - Position_z) * (1000 samples/s) * (60 s/min) / (2000 counts/rev) Velocity_RPM = Velocity_counts * 30 Method 2: Period Measurement (32-bit QEI, Better at Low Speed) // Use QEI period output Period_Output: 32-bit unsigned Max_Period: 0.1 seconds // Period in timer ticks, convert to RPM Velocity_RPM = (60 / Max_Period) / (Period_ticks / QEI_max) Tip: Position difference method works well at high speeds. Period measurement (INTCNT) is better for low speeds where counts are infrequent.
Configuration:
Hardware: Proximity sensor generates pulses, separate direction signal
Configuration:
Cause: Encoder wiring reversed (QEA and QEB swapped)
Solution: Enable “Swap QEA/QEB” parameter, or physically swap encoder wires
Cause: Electrical noise on encoder signals
Solutions:
Cause: Encoder frequency exceeds QEI peripheral maximum input frequency
Solutions:
Causes and Solutions:
Cause: Position exceeds selected datatype range
Solutions:
// Rule of thumb for filter selection: Max_Encoder_Freq = Max_RPM * (Counts_per_Rev / 60); Filter_Cutoff = Max_Encoder_Freq * 2; // Nyquist criterion// Example: 3000 RPM motor with 500 PPR encoder (X4 = 2000 counts/rev) Max_Encoder_Freq = 3000 * (2000 / 60) = 100 kHz Filter_Cutoff = 100 kHz * 2 = 200 kHz // Select β₯ 200 kHz filter
The maximum encoder input frequency depends on the device clock and filter settings: // For dsPIC33E/33C at 70 MIPS (140 MHz SYSCLK) QEI_Clock = 140 MHz; Filter_Divider = [1 2 4 8 16 32 64 256] * 3; // Actual divider values// Maximum input frequency: Max_Input_Freq = QEI_Clock / (Filter_Divider * 2); // Examples:// QFDIV=0 (Γ·3): Max = 140M / (32) = 23.3 MHz// QFDIV=1 (Γ·6): Max = 140M / (62) = 11.7 MHz// QFDIV=7 (Γ·768): Max = 140M / (768*2) = 91 kHz
For 32-bit QEI with period measurement: // Period counter resolution: Timer_Prescaler = [1 2 4 8 16 32 64 256]; // INTDIV settings Timer_Frequency = QEI_Clock / Timer_Prescaler; Period_Resolution = 1 / Timer_Frequency; // Velocity range: Max_Velocity = 1 / (Period_Resolution); Min_Velocity = 1 / (Period_Resolution * 65535); // 16-bit counter// Example with INTDIV=4 (Γ·8) at 140 MHz: Period_Resolution = 1 / (140M / 8) = 57.1 ns Max_Velocity = 17.5 MHz Min_Velocity = 267 Hz
When using QEI interrupts for index detection or position limits: Interrupt Response Time:
Last Updated: 2024 | MCHP Blockset for MATLAB/Simulink