ESP32Encoder Library

repository·master·Indexed 18 days ago

https://github.com/madhephaestus/esp32encoder

A high-performance library for tracking quadrature encoders on ESP32 microcontrollers using the Pulse Counter (PCNT) hardware peripheral. It supports full, half, and single edge quadrature modes with low CPU overhead. The library provides hardware acceleration for ESP32, ESP32C2, and ESP32S3, and includes an InterruptEncoder class for software-based reading on unsupported hardware like the ESP32C3.

Tokens
1.8K
Snippets
7
Records
12
Agent score
63%

What's inside ESP32Encoder

  1. Overview of ESP32Encoder hardware acceleration

    master

    ESP32Encoder is a library that leverages the ESP32 Pulse Counter (PCNT) hardware peripheral to track quadrature encoders.

    Key characteristics:

    • Low CPU Overhead: Instead of generating an interrupt for every pulse, the library uses the hardware's interrupt mechanism which only triggers when the 16-bit counter buffer overflows. This results in a very small interrupt footprint.
    • Hardware Limits: The number of supported encoders depends on the specific ESP32 chip being used:
      • ESP32 and ESP32C2: Supports up to 8 simultaneous encoders.
      • ESP32S3: Supports only 2 hardware-accelerated encoders (due to having only 2 PCNT modules).
      • ESP32C3: Does not support hardware-accelerated encoders as it lacks the PCNT hardware.
  2. Encoder quadrature modes

    master

    The library supports three different modes for reading incremental encoders:

    1. Full Quadrature: Performs a count increment on all 4 edges of the signals.
    2. Half Quadrature: Performs counts on the rising and falling edges of a single channel.
    3. Single Edge Count: Counts only the rising edge of the A channel.
  3. Configure the ISR service CPU core

    master
    To manage concurrency and ensure count accuracy, you can specify which CPU core handles the PCNT Interrupt Service Routine (ISR) using the isrServiceCpuCore option. Setting this can help prevent issues where a count is read before the total count has been fully updated by the interrupt service.
  4. Configure pull-up/pull-down resistors

    master

    You can specify whether to use weak internal pull-up or pull-down resistors using the useInternalWeakPullResistors configuration option.

    Available enum types:

    • UP: Enables internal pull-up resistors.
    • DOWN: Enables internal pull-down resistors.
    • NONE: Disables internal resistors.
  5. Debouncing for KY-040 and switch-style encoders

    master

    Switch-style encoder modules (like the KY-040) often exhibit significant electrical bouncing that exceeds the standard PCNT hardware debouncing limits.

    To mitigate this, you should:

    1. Add electrical debouncing (capacitors) in the range of 0.1 - 2 µF per encoder line to ground.
    2. Call setFilter() with a value of 1023 immediately after attaching the encoder to enable the maximum hardware debouncing capability.
    // Example pattern for switch-style encoders
    encoder.setFilter(1023);
  6. Configure global ESP32Encoder settings

    master

    The following static members allow you to configure the behavior of all ESP32Encoder instances:

    • useInternalWeakPullResistors (puType): Sets whether to use internal pull-up (puType::up), pull-down (puType::down), or no pull resistors (puType::none).
    • isrServiceCpuCore (uint32_t): Sets the CPU core on which the ISR service runs. Use 0xffffffff for the default core.
    // Example: Use internal pull-ups and assign ISR to core 1
    ESP32Encoder::useInternalWeakPullResistors = puType::up;
    ESP32Encoder::isrServiceCpuCore = 1;
  7. Use InterruptEncoder for quadrature encoder reading

    master

    The InterruptEncoder class provides a way to read quadrature encoders using interrupts instead of the ESP32 hardware PCNT peripheral. This is useful for encoders where hardware peripheral limitations or pin availability are concerns.

    To use it, instantiate the class and call attach(aPinNum, bPinNum) to specify the pins used for the encoder phases. You can then retrieve the current position using read().

    InterruptEncoder encoder;
    
    void setup() {
      // Attach encoder to pins 18 and 19
      encoder.attach(18, 19);
    }
    
    void loop() {
      // Read the current count
      int64_t currentCount = encoder.read();
    }
  8. Attach encoder pins using different quadrature modes

    master

    Use the following methods to attach physical GPIO pins to the encoder instance. The choice of method determines the resolution and edge detection mode of the PCNT peripheral:

    • attachFullQuad(int aPinNumber, int bPinNumber): Full quadrature mode (4x encoding).
    • attachHalfQuad(int aPinNumber, int bPinNumber): Half quadrature mode (2x encoding).
    • attachSingleEdge(int aPinNumber, int bPinNumber): Single edge mode (1x encoding).
    ESP32Encoder encoder;
    encoder.attachFullQuad(18, 19); // Attach pins 18 and 19 in full quadrature mode
  9. Read and manipulate encoder counts

    master

    The ESP32Encoder class provides several methods to interact with the current pulse count:

    • getCount(): Returns the current encoder count as an int64_t.
    • clearCount(): Returns the current count and resets it to 0.
    • pauseCount(): Pauses the counting mechanism and returns the current count.
    • resumeCount(): Resumes counting.
    • setCount(int64_t value): Manually sets the encoder count to a specific value.
    • setFilter(uint16_t value): Sets a digital filter value to mitigate noise on the input pins.
    int64_t current_pos = encoder.getCount();
    encoder.setCount(0); // Reset position
  10. Initialize and configure ESP32Encoder

    master

    To use the ESP32Encoder class, instantiate it with optional interrupt settings. You can enable an interrupt to trigger on every encoder pulse by setting always_interrupt to true. If enabled, you can provide a callback function (enc_isr_cb_t) and a data pointer (enc_isr_cb_data) that will be executed during the ISR.

    Constructor Parameters:

    • always_interrupt (bool): If true, an interrupt is enabled on every encoder pulse. Defaults to false.
    • enc_isr_cb (enc_isr_cb_t): The callback function to execute on every encoder ISR. Only has an effect if always_interrupt is true.
    • enc_isr_cb_data (void*): User-defined data passed to the callback function.
    // Example: Initialize with an interrupt callback
    void my_callback(void* arg) {
        ESP32Encoder* encoder = static_cast<ESP32Encoder*>(arg);
        // Handle interrupt
    }
    
    ESP32Encoder encoder(true, my_callback, &encoder);
  11. InterruptEncoder API Reference

    master

    The InterruptEncoder class exposes the following public members:

    Methods

    • void attach(int aPinNum, int bPinNum): Configures the encoder with the specified pins for phase A and phase B.
    • int64_t read(): Returns the current encoder count.

    Public Members

    • int apin: The pin number assigned to phase A.
    • int bpin: The pin number assigned to phase B.
    • volatile bool aState: The current state of phase A.
    • volatile bool bState: The current state of phase B.
    • volatile int64_t count: The current accumulated encoder count.
    • volatile int64_t microsLastA: Timestamp (in microseconds) of the last transition on phase A.
    • volatile int64_t microsTimeBetweenTicks: The time elapsed between the last two ticks in microseconds.