M5Dial icon indicating copy to clipboard operation
M5Dial copied to clipboard

Encoder works poorly due to undefined CORE_INT40_PIN and CORE_INT41_PIN

Open MitchBradley opened this issue 2 years ago • 5 comments

I am a developer on the same project cited in issue #5. We have discovered an issue whereby, when you spin the dial rapidly in one direction, the sequence of encoder delta values often changes sign. For example, you might see the sequence -1,-1,-1,-2,-1,2,-1 . The (+)2 is spurious; the dial is only spinning in one direction. Furthermore, the magnitude of the delta never exceeds 2.

I have tracked it down to the fact that attach_interrupt in Encoder.h is failing. The reason is that M5Dial.h has

#define DIAL_ENCODER_PIN_A 41
#define DIAL_ENCODER_PIN_B 40

but in Encoder.h, the list of interrupt pin defines ends at 39, i.e.

...
#define CORE_INT36_PIN 36
#define CORE_INT39_PIN 39

I suspect that this is because, on plain ESP32, the highest numbered GPIO is 39, whereas ESP32-S3 has GPIO numbers up to 48, and the code was not updated to reflect that.

When the interrupt does not attach, the update() method runs only when Encoder.read() is called, and that is not necessarily frequently enough to catch all encoder edges during fast rotation.

I manually added the following lines to Encoder.h to fix the problem:

#define CORE_INT40_PIN 40
#define CORE_INT41_PIN 41

A complete fix might include other GPIO numbers as well, although 40 and 41 suffice for the M5Dial hardware that uses those pins.

MitchBradley avatar Dec 16 '23 07:12 MitchBradley

It is also necessary to say

#define CORE_NUM_INTERRUPT 42

for obvious reasons

MitchBradley avatar Dec 18 '23 22:12 MitchBradley

Thanks. I applied this fix but it was not perfect quite yet. I have found that this problem is related to the display. Using a M5Canvas function with M5GFX and creating a specific draw function solved the problem. I took this from Volos project examples on the M5Dial, which I recommend. https://github.com/VolosR/M5Dial/tree/main/M5Dial

aerogarage avatar Jan 11 '24 14:01 aerogarage

We also continued to have encoder problems with the fix, albeit less frequently. We solved it by creating a custom encoder driver that uses the ESP32 PCNT hardware and thus does not need interrupts. With the PCNT driver, the encoder works perfectly. Here is our Encoder.cpp file


#include "sdkconfig.h"
#include "driver/pcnt.h"
#include "driver/gpio.h"
#include "Encoder.h"

/* clang-format: off */
void init_encoder() {
    pcnt_config_t enc_config = {
        .pulse_gpio_num = GPIO_NUM_40,  //Rotary Encoder Chan A
        .ctrl_gpio_num  = GPIO_NUM_41,  //Rotary Encoder Chan B

        .lctrl_mode = PCNT_MODE_KEEP,     // Rising A on HIGH B = CW Step
        .hctrl_mode = PCNT_MODE_REVERSE,  // Rising A on LOW B = CCW Step
        .pos_mode   = PCNT_COUNT_INC,     //Count Only On Rising-Edges
        .neg_mode   = PCNT_COUNT_DEC,     // Discard Falling-Edge

        .counter_h_lim = INT16_MAX,
        .counter_l_lim = INT16_MIN,

        .unit    = PCNT_UNIT_0,
        .channel = PCNT_CHANNEL_0,
    };
    pcnt_unit_config(&enc_config);

    enc_config.pulse_gpio_num = GPIO_NUM_41;
    enc_config.ctrl_gpio_num  = GPIO_NUM_40;
    enc_config.channel        = PCNT_CHANNEL_1;
    enc_config.pos_mode       = PCNT_COUNT_DEC;  //Count Only On Falling-Edges
    enc_config.neg_mode       = PCNT_COUNT_INC;  // Discard Rising-Edge
    pcnt_unit_config(&enc_config);

    pcnt_set_filter_value(PCNT_UNIT_0, 250);  // Filter Runt Pulses

    pcnt_filter_enable(PCNT_UNIT_0);

    gpio_pullup_en(GPIO_NUM_40);
    gpio_pullup_en(GPIO_NUM_41);

    pcnt_counter_pause(PCNT_UNIT_0);  // Initial PCNT init
    pcnt_counter_clear(PCNT_UNIT_0);
    pcnt_counter_resume(PCNT_UNIT_0);
}

int16_t get_encoder() {
    int16_t count;
    pcnt_get_counter_value(PCNT_UNIT_0, &count);
    return count;
}

and the Encoder.h file

#pragma once

#include <Arduino.h>

void    init_encoder();
int16_t get_encoder();

MitchBradley avatar Jan 11 '24 16:01 MitchBradley

@MitchBradley Great work, thank you for sharing!

manuelzi avatar Feb 21 '24 11:02 manuelzi

Thanks for the drivers. M5dial is not developed anymore ., and using BtnA functions made my m5dial to reboot forever. I switched to M5Unified, button is now working good, but there's currently no rotary encoder manager 😅 So thangs again to had provided a solution 👌

SadE54 avatar Mar 03 '25 09:03 SadE54