Files
Blinds_XIAO/include/encoder.cpp

84 lines
2.5 KiB
C++
Raw Normal View History

#include "encoder.hpp"
#include "driver/gpio.h"
#include "esp_log.h"
2025-12-28 15:31:20 -06:00
#include "soc/gpio_struct.h"
2025-12-28 15:31:20 -06:00
static const char *TAG = "ENCODER";
2025-12-28 15:31:20 -06:00
// 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) {}
2025-12-28 15:31:20 -06:00
// Static ISR - receives Encoder instance via arg
void IRAM_ATTR Encoder::isr_handler(void* arg)
{
Encoder* encoder = static_cast<Encoder*>(arg);
// Read GPIO levels directly from hardware
uint32_t gpio_levels = GPIO.in.val;
2025-12-28 15:31:20 -06:00
uint8_t current_a = (gpio_levels >> encoder->pin_a) & 0x1;
uint8_t current_b = (gpio_levels >> encoder->pin_b) & 0x1;
2025-12-28 15:31:20 -06:00
// Quadrature decoding logic
if (current_a != encoder->last_state_a) {
if (!current_a) {
2025-12-28 15:31:20 -06:00
if (current_b) encoder->last_count_base++;
else encoder->last_count_base--;
}
else {
2025-12-28 15:31:20 -06:00
if (current_b) encoder->last_count_base--;
else encoder->last_count_base++;
}
}
2025-12-28 15:31:20 -06:00
else if (current_b != encoder->last_state_b) {
if (!current_b) {
2025-12-28 15:31:20 -06:00
if (current_a) encoder->last_count_base--;
else encoder->last_count_base++;
}
else {
2025-12-28 15:31:20 -06:00
if (current_a) encoder->last_count_base++;
else encoder->last_count_base--;
}
}
2025-12-28 15:31:20 -06:00
// Accumulate to full detent count
if (encoder->last_count_base > 3) {
encoder->count += 1;
encoder->last_count_base -= 4;
}
2025-12-28 15:31:20 -06:00
else if (encoder->last_count_base < 0) {
encoder->count -= 1;
encoder->last_count_base += 4;
}
2025-12-28 15:31:20 -06:00
encoder->last_state_a = current_a;
encoder->last_state_b = current_b;
}
2025-12-28 15:31:20 -06:00
void Encoder::init()
{
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_ANYEDGE;
2025-12-28 15:31:20 -06:00
io_conf.pin_bit_mask = (1ULL << pin_a) | (1ULL << pin_b);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
2025-12-28 15:31:20 -06:00
// Install ISR service if not already installed
gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
2025-12-28 15:31:20 -06:00
// 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);
2025-12-28 15:31:20 -06:00
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");
}