From 2a79df305008b6e94eec715595e5098e6f072bbf Mon Sep 17 00:00:00 2001 From: pulipakaa24 Date: Sun, 28 Dec 2025 15:31:20 -0600 Subject: [PATCH] turned encoder into class --- include/defines.h | 3 ++ include/encoder.cpp | 94 ++++++++++++++++++++++++--------------------- include/encoder.hpp | 31 ++++++++++++--- src/main.cpp | 15 ++++++-- 4 files changed, 90 insertions(+), 53 deletions(-) diff --git a/include/defines.h b/include/defines.h index 67b9b16..49b216d 100644 --- a/include/defines.h +++ b/include/defines.h @@ -19,6 +19,9 @@ #define ENCODER_PIN_A GPIO_NUM_23 #define ENCODER_PIN_B GPIO_NUM_16 +#define InputEnc_PIN_A GPIO_NUM_1 +#define InputEnc_PIN_B GPIO_NUM_2 + #define getMovingCW(port) ((movingCW & (1 << port)) >> port) #define setMovingCW(port) (movingCW |= (1 << port)) #define clearMovingCW(port) (movingCW &= ~(1 << port)) diff --git a/include/encoder.cpp b/include/encoder.cpp index 4a43792..0759baa 100644 --- a/include/encoder.cpp +++ b/include/encoder.cpp @@ -1,76 +1,84 @@ #include "encoder.hpp" -#include "defines.h" #include "driver/gpio.h" #include "esp_log.h" -#include "esp_pm.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_sleep.h" -#include "soc/gpio_struct.h" // <--- REQUIRED for GPIO.in.val +#include "soc/gpio_struct.h" -volatile int32_t encoder_count = 0; -static const char *TAG = "ENCODER_DEMO"; +static const char *TAG = "ENCODER"; -// --- THE SAFE ISR (RAM ONLY) --- -static void IRAM_ATTR encoder_isr_handler(void* arg) +// Constructor +Encoder::Encoder(gpio_num_t pinA, gpio_num_t pinB) + : pin_a(pinA), pin_b(pinB), count(0), + last_state_a(0), last_state_b(0), last_count_base(0) {} + +// Static ISR - receives Encoder instance via arg +void IRAM_ATTR Encoder::isr_handler(void* arg) { - static uint8_t last_state_a = 0; - static uint8_t last_state_b = 0; - static int8_t last_count_base = 0; - - // READ HARDWARE DIRECTLY: This effectively bypasses the Flash crash risk + Encoder* encoder = static_cast(arg); + + // Read GPIO levels directly from hardware uint32_t gpio_levels = GPIO.in.val; - uint8_t current_a = (gpio_levels >> ENCODER_PIN_A) & 0x1; - uint8_t current_b = (gpio_levels >> ENCODER_PIN_B) & 0x1; + uint8_t current_a = (gpio_levels >> encoder->pin_a) & 0x1; + uint8_t current_b = (gpio_levels >> encoder->pin_b) & 0x1; - // LOGIC - if (current_a != last_state_a) { + // Quadrature decoding logic + if (current_a != encoder->last_state_a) { if (!current_a) { - if (current_b) last_count_base++; - else last_count_base--; + if (current_b) encoder->last_count_base++; + else encoder->last_count_base--; } else { - if (current_b) last_count_base--; - else last_count_base++; + if (current_b) encoder->last_count_base--; + else encoder->last_count_base++; } } - else if (current_b != last_state_b) { + else if (current_b != encoder->last_state_b) { if (!current_b) { - if (current_a) last_count_base--; - else last_count_base++; + if (current_a) encoder->last_count_base--; + else encoder->last_count_base++; } else { - if (current_a) last_count_base++; - else last_count_base--; + if (current_a) encoder->last_count_base++; + else encoder->last_count_base--; } } - if (last_count_base > 3) { - encoder_count += 1; - last_count_base -= 4; + + // Accumulate to full detent count + if (encoder->last_count_base > 3) { + encoder->count += 1; + encoder->last_count_base -= 4; } - else if (last_count_base < 0) { - encoder_count -= 1; - last_count_base += 4; + else if (encoder->last_count_base < 0) { + encoder->count -= 1; + encoder->last_count_base += 4; } - last_state_a = current_a; - last_state_b = current_b; + + encoder->last_state_a = current_a; + encoder->last_state_b = current_b; } -void encoder_init(void) +void Encoder::init() { gpio_config_t io_conf = {}; io_conf.intr_type = GPIO_INTR_ANYEDGE; - io_conf.pin_bit_mask = (1ULL << ENCODER_PIN_A) | (1ULL << ENCODER_PIN_B); + io_conf.pin_bit_mask = (1ULL << pin_a) | (1ULL << pin_b); io_conf.mode = GPIO_MODE_INPUT; - // Internal Pull-ups prevent "floating" inputs waking the chip randomly io_conf.pull_up_en = GPIO_PULLUP_ENABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; gpio_config(&io_conf); - gpio_install_isr_service(ESP_INTR_FLAG_IRAM); // IRAM is vital for Sleep + // Install ISR service if not already installed + gpio_install_isr_service(ESP_INTR_FLAG_IRAM); - gpio_isr_handler_add(ENCODER_PIN_A, encoder_isr_handler, NULL); - gpio_isr_handler_add(ENCODER_PIN_B, encoder_isr_handler, NULL); + // Attach ISR with THIS instance as argument + gpio_isr_handler_add(pin_a, Encoder::isr_handler, this); + gpio_isr_handler_add(pin_b, Encoder::isr_handler, this); - ESP_LOGI(TAG, "Encoder initialized with Sleep Wakeup support."); + ESP_LOGI(TAG, "Encoder initialized on pins %d and %d", pin_a, pin_b); +} + +void Encoder::deinit() +{ + gpio_isr_handler_remove(pin_a); + gpio_isr_handler_remove(pin_b); + ESP_LOGI(TAG, "Encoder deinitialized"); } \ No newline at end of file diff --git a/include/encoder.hpp b/include/encoder.hpp index 9bf4d19..f55d805 100644 --- a/include/encoder.hpp +++ b/include/encoder.hpp @@ -1,11 +1,30 @@ #ifndef ENCODER_H #define ENCODER_H -#include -#include "esp_pm.h" +#include "driver/gpio.h" -extern volatile int32_t encoder_count; -extern esp_pm_lock_handle_t encoder_pm_lock; - -void encoder_init(); +class Encoder { +public: + // Shared between ISR and main code + volatile int32_t count; + + // ISR-only state + uint8_t last_state_a; + uint8_t last_state_b; + int8_t last_count_base; + + // Configuration + gpio_num_t pin_a; + gpio_num_t pin_b; + + // Static ISR that receives instance pointer via arg + static void isr_handler(void* arg); + + // Constructor and methods + Encoder(gpio_num_t pinA, gpio_num_t pinB); + void init(); + int32_t getCount() const { return count; } + void setCount(int32_t value) { count = value; } + void deinit(); +}; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a6bf92c..3947830 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,10 @@ void mainApp() { ESP_ERROR_CHECK(ret); bmWiFi.init(); + + // Create and initialize encoder + Encoder encoder(ENCODER_PIN_A, ENCODER_PIN_B); + encoder.init(); setupLoop(); @@ -42,13 +46,16 @@ void mainApp() { } void encoderTest() { - encoder_init(); + // Create encoder instance + Encoder encoder(ENCODER_PIN_A, ENCODER_PIN_B); + encoder.init(); - int32_t prevCount = encoder_count; + int32_t prevCount = encoder.getCount(); while (1) { - if (encoder_count != prevCount) { - prevCount = encoder_count; + int32_t currentCount = encoder.getCount(); + if (currentCount != prevCount) { + prevCount = currentCount; printf("Encoder Pos: %d\n", prevCount); } vTaskDelay(pdMS_TO_TICKS(100));