New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Encoder works poorly due to undefined CORE_INT40_PIN and CORE_INT41_PIN #8
Comments
It is also necessary to say #define CORE_NUM_INTERRUPT 42 for obvious reasons |
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 |
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 Great work, thank you for sharing! |
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
but in Encoder.h, the list of interrupt pin defines ends at 39, i.e.
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:
A complete fix might include other GPIO numbers as well, although 40 and 41 suffice for the M5Dial hardware that uses those pins.
The text was updated successfully, but these errors were encountered: