turned encoder into class
This commit is contained in:
@@ -19,6 +19,9 @@
|
|||||||
#define ENCODER_PIN_A GPIO_NUM_23
|
#define ENCODER_PIN_A GPIO_NUM_23
|
||||||
#define ENCODER_PIN_B GPIO_NUM_16
|
#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 getMovingCW(port) ((movingCW & (1 << port)) >> port)
|
||||||
#define setMovingCW(port) (movingCW |= (1 << port))
|
#define setMovingCW(port) (movingCW |= (1 << port))
|
||||||
#define clearMovingCW(port) (movingCW &= ~(1 << port))
|
#define clearMovingCW(port) (movingCW &= ~(1 << port))
|
||||||
|
|||||||
@@ -1,76 +1,84 @@
|
|||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "defines.h"
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_pm.h"
|
#include "soc/gpio_struct.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "esp_sleep.h"
|
|
||||||
#include "soc/gpio_struct.h" // <--- REQUIRED for GPIO.in.val
|
|
||||||
|
|
||||||
volatile int32_t encoder_count = 0;
|
static const char *TAG = "ENCODER";
|
||||||
static const char *TAG = "ENCODER_DEMO";
|
|
||||||
|
|
||||||
// --- THE SAFE ISR (RAM ONLY) ---
|
// Constructor
|
||||||
static void IRAM_ATTR encoder_isr_handler(void* arg)
|
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;
|
Encoder* encoder = static_cast<Encoder*>(arg);
|
||||||
static uint8_t last_state_b = 0;
|
|
||||||
static int8_t last_count_base = 0;
|
// Read GPIO levels directly from hardware
|
||||||
|
|
||||||
// READ HARDWARE DIRECTLY: This effectively bypasses the Flash crash risk
|
|
||||||
uint32_t gpio_levels = GPIO.in.val;
|
uint32_t gpio_levels = GPIO.in.val;
|
||||||
uint8_t current_a = (gpio_levels >> ENCODER_PIN_A) & 0x1;
|
uint8_t current_a = (gpio_levels >> encoder->pin_a) & 0x1;
|
||||||
uint8_t current_b = (gpio_levels >> ENCODER_PIN_B) & 0x1;
|
uint8_t current_b = (gpio_levels >> encoder->pin_b) & 0x1;
|
||||||
|
|
||||||
// LOGIC
|
// Quadrature decoding logic
|
||||||
if (current_a != last_state_a) {
|
if (current_a != encoder->last_state_a) {
|
||||||
if (!current_a) {
|
if (!current_a) {
|
||||||
if (current_b) last_count_base++;
|
if (current_b) encoder->last_count_base++;
|
||||||
else last_count_base--;
|
else encoder->last_count_base--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (current_b) last_count_base--;
|
if (current_b) encoder->last_count_base--;
|
||||||
else 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_b) {
|
||||||
if (current_a) last_count_base--;
|
if (current_a) encoder->last_count_base--;
|
||||||
else last_count_base++;
|
else encoder->last_count_base++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (current_a) last_count_base++;
|
if (current_a) encoder->last_count_base++;
|
||||||
else last_count_base--;
|
else encoder->last_count_base--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (last_count_base > 3) {
|
|
||||||
encoder_count += 1;
|
// Accumulate to full detent count
|
||||||
last_count_base -= 4;
|
if (encoder->last_count_base > 3) {
|
||||||
|
encoder->count += 1;
|
||||||
|
encoder->last_count_base -= 4;
|
||||||
}
|
}
|
||||||
else if (last_count_base < 0) {
|
else if (encoder->last_count_base < 0) {
|
||||||
encoder_count -= 1;
|
encoder->count -= 1;
|
||||||
last_count_base += 4;
|
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 = {};
|
gpio_config_t io_conf = {};
|
||||||
io_conf.intr_type = GPIO_INTR_ANYEDGE;
|
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;
|
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_up_en = GPIO_PULLUP_ENABLE;
|
||||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
gpio_config(&io_conf);
|
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);
|
// Attach ISR with THIS instance as argument
|
||||||
gpio_isr_handler_add(ENCODER_PIN_B, encoder_isr_handler, NULL);
|
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");
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,30 @@
|
|||||||
#ifndef ENCODER_H
|
#ifndef ENCODER_H
|
||||||
#define ENCODER_H
|
#define ENCODER_H
|
||||||
#include <atomic>
|
#include "driver/gpio.h"
|
||||||
#include "esp_pm.h"
|
|
||||||
|
|
||||||
extern volatile int32_t encoder_count;
|
class Encoder {
|
||||||
extern esp_pm_lock_handle_t encoder_pm_lock;
|
public:
|
||||||
|
// Shared between ISR and main code
|
||||||
void encoder_init();
|
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
|
#endif
|
||||||
15
src/main.cpp
15
src/main.cpp
@@ -19,6 +19,10 @@ void mainApp() {
|
|||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
bmWiFi.init();
|
bmWiFi.init();
|
||||||
|
|
||||||
|
// Create and initialize encoder
|
||||||
|
Encoder encoder(ENCODER_PIN_A, ENCODER_PIN_B);
|
||||||
|
encoder.init();
|
||||||
|
|
||||||
setupLoop();
|
setupLoop();
|
||||||
|
|
||||||
@@ -42,13 +46,16 @@ void mainApp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void encoderTest() {
|
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) {
|
while (1) {
|
||||||
if (encoder_count != prevCount) {
|
int32_t currentCount = encoder.getCount();
|
||||||
prevCount = encoder_count;
|
if (currentCount != prevCount) {
|
||||||
|
prevCount = currentCount;
|
||||||
printf("Encoder Pos: %d\n", prevCount);
|
printf("Encoder Pos: %d\n", prevCount);
|
||||||
}
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|||||||
Reference in New Issue
Block a user