Efficient nrfx-based Quadrature Decoder for High-Speed Encoders on NRF5340

Hello,

I'm developing a project based on the NRF5340 and have encountered some challenges. As I'm relatively new to C, I'm trying to implement a quadrature (incremental) encoder decoder that accurately captures all four states of the signal. For example, with an encoder offering 1024 increments on two outputs, I should be able to obtain 4096 distinct positions.

I initially planned to use the Zephyr QDEC driver; however, as noted in this thread (https://devzone.nordicsemi.com/f/nordic-q-a/91398/qdec-peripheral-with-high-speed-encoder/384446), it seems too slow for my application. In addition to decoding the signal, I also need to reliably determine the direction of rotation.

Could anyone point me to a sample or provide guidance on using the nrfx-specific functions for this purpose—ideally in a way that minimizes CPU load?

  • Hello,

    The QDEC on the nRF52 and nRF53 series is intended for mouse wheels, originally, and is typically too slow for tracking a high speed motor. You didn't mention what kind of speed you would need, but we can see from the product specification of the QDEC on the nRF5340:

    https://docs.nordicsemi.com/bundle/ps_nrf5340/page/chapters/qdec/qdec.html

    That the maximum sample rate is 500kHz. It says that it samples at 1MHz (1048576Hz, given that each sample period is 128µs), but you need two samples to be the same for it not to be caught by the debounce filter. 

    So at what speed/frequency do you need to sample?

    Best regards,

    Edvin

  • Hello Edvin,

    Thank you for your response.

    The motor runs at 3000 RPM with an encoder resolution of 10,000 increments per revolution, which results in a signal frequency of 500 kHz. According to the Nyquist criterion, a sampling frequency of at least 1 MHz would be required to accurately capture the signal. Since the QDEC on the nRF5340 has a maximum sample rate of 500 kHz, it seems like it may not be sufficient for this application.

    Would you recommend using direct GPIO sampling with PPI/DPPI and a TIMER instead? If so, is there any available sample code demonstrating this approach?

    Best regards,

    Philipp

  • Philipp.trem said:
    Would you recommend using direct GPIO sampling with PPI/DPPI and a TIMER instead? If so, is there any available sample code demonstrating this approach?

    We don't have anything. It depends on what you need. If you need a sample every now and then, it may work, but if you need all the updates, which means that you need 3000*10 000/60 = 500 000Hz. 

    There is no way to guarantee that you will be able to access the CPU this fast.

    Even though you set it up using PPI, you can sample some pulses, and store this in some capture compare registers in the timer, but it would be difficult to read them out fast enough, reliably. 

    How about reducing the increments per revolution? Is that an option? If not, it sounds like you perhaps need an external QDEC.

    Best regards,

    Edvin

  •  I want to implement a controller that runs at 5 kHz, so I would only need to read my value every 0.2 ms (200 µs).  Do you think it would be feasible to reliably read the values using GPIO sampling with PPI/DPPI and a timer in this case?

    Best regards,
    Philipp

  • Not sure. You would need to test to see if it is accurate enough for your use case. 

    I have a sample that you can use to get up and running. It is basically a sample using DPPI (using the GPPI API) that measures the length of a pulse. Perhaps you can modify this for your test.

    7752.timed_signals_ncs240.zip

    (written in NCS 2.4.0, but I believe it still works)

    Best regards,

    Edvin

Related