An incremental encoder provides a cost-effective way to capture shaft angle of a motor, especially when position accumulation for several turns is required (such as when transferring through a gear mechanism, or converting to linear position in a motion control axis). The hardware needed at the receiving end are a quadrature signal decoder, digital filter, and an up/down counter. Previous articles on this website explained how to implement them on an FPGA chip using hardware description language. That would be useful when you want to design hardware for several motion axes using minimal footprint. For a single channel application, the PIC24EP Motor Control (MC) family from Microchip
, such as PIC24EP256MC202
used in this article, conveniently provides a QEI module on chip. So, in this article we discuss how to setup and use it.
First, let us review the mechanisms of an incremental encoder for those who are unfamiliar with it. To save space, here I refer to my previous article Quadrature Encoder Receiver Module: An Implementation on FPGA
. Just read the first section on that page. The key point is the quadrature pulses A and B that are 90 degree out of phase. Traditionally, when the motor turns clockwise, A leads B by 90 degrees, and for counter-clockwise rotation, B leads A by 90 degrees. The QEI module accepts this pair of signals as input and convert to encoder counts. Here we do not need the index Z signal.
The QEI module in PIC32EP is considerably more advanced than in their previous products in the MC family. Above all, the count register is now 32 bits instead of 16. This is a significant improvement, since for a medium to high resolution encoder, a 16 bit counter overflows after a few revolutions. In our previous project using the dsPIC microcontroller, the counter is extended to 32-bit via software. Now we don’t need to do that anymore.
The module also has functions to aid in industrial machine design such as axis homing. It also has separate register for velocity readout. We don’t need those for the discussion in this article.
Apart from the microcontroller board, what we need is some device to generate encoder pulses. A motor equipped with incremental encoder can be used but it is difficult to verify whether the QEI module is setup properly. To do so, we want to read the count value after an exact number of pulses is received. A better way is to use an equipment known as handwheel as shown in Figure 1. This is an input device commonly used in a CNC machine to move its axis to a specified location. The advantage is when we turn the dial one click, exactly one pulse for each A and B channel is generated. So, with the QEI module set up as x4, for each click, the counter value should increase or decrease by 4, depending on the turning direction.
Figure 1 testing QEI module with a handwheel
The PIC32EP256MC202 has only one QEI module, labeled QEI1. First we need to assign the QEA1 and QEB1 to RP pins of the microcontroller. On our prototype the pin RPI44 and RPI45 are available so we write assignment code as follows
RPINR14bits.QEA1R = 44; // QEA1 to RPI44
RPINR14bits.QEB1R = 45; // QEB1 to RPI45
Next, we consider whether to use the digital filter in the module. This function is useful when high-frequency noise is present. To set up the filter with sampling rate equals system clock divided by 8, for example
QEI1IOCbits.QFDIV = 0b011; // DIF 1:8 clock divide
QEI1IOCbits.FLTREN = 1; // enable the DIF
The QEI module of PIC24EP has several other functions, but this is all we need for basic setup. Some are left to default values. The last step is to enable the module
QEI1CONbits.QEIEN = 1; // enable the module
For easy management, it is recommended that all setup instructions be written to a function such as initQEI()
Reading and Writing the Position Register
The special 32-bit register in QEI1 module used to keep position count is named POS1CNT. Since the bus structure of PIC24 is 16-bit, accessing the 32-bit register needs 2 consecutive reads/writes. With no data latch error could happen when, for example, the lower 16-bit is read first, but before the higher 16-bit is read, overflow happens that causes change in the higher 16-bit data. So after that data is read and combined with the lower 16-bit data to 32-bit position value, it is different from the actual value in the counter. This could happen with writing process as well.
To fix this problem, the QEI module in PIC24EP deploys two 16-bit special registers POS1CNTL and POS1HLD to transfer lower 16-bit (LSW: Least Significant Word) and higher 16-bit (MSW: Most Significant Word) of POS1CNT, respectively. The user program never reads or writes to/from POS1CNT directly.
Whenever a read to POS1CNTL is issued, the QEI module automatically writes the MSW of POS1CNT at that instant to POS1HLD. So the data in POS1CNTL and POS1HLD combined to a valid 32-bit position value.
Similarly, the writing process to POS1CNT starts from writing MSW to POS1HLD first. Later when the LSW is written to POS1CNTL, the value in POS1HLD is transferred to MSW of POS1CNT automatically. The data written to POS1CNT is valid.
On the software side, it is convenient to use a global variable of type union as follows
volatile qeipvalue QEIpVal;
This variable accommodates easy reading from POS1CNT of QEI1
void readpQEI(void) // read quadrature position counter to global
QEIpVal.half = POS1CNTL; // read lsw
QEIpVal.half = POS1HLD; // read msw from hold register
as well as writing from QEIpVal to POS1CNT
void writepQEI(void) // write quadrature position counter from
// global variable
POS1HLD = QEIpVal.half; // write msw to hold register
POS1CNTL = QEIpVal.half; // write lsw to POS1CNTL
Our simple test program starts from initializing the QEI1 module, and UART1, which is used to send data to hyperterminal program via FT232R USB-to-serial from www.ftdichip.com . The program writes value 0 to POS1CNT and enters infinite loop waiting for input SW1. The QEI1 module works independently from the main loop. With the handwheel turned 1 click clockwise, the value in POS1CNT increases by 4. A 1-click counterclockwise turn causes the decrease by 4. Figure 2 is the output captured from hyperterminal. The module works accurately.
Figure 2 Position readouts from QEI1 module of PIC24EP256MC202