GyverLibs / EncButton

Лёгкая и очень функциональная библиотека для энкодера с кнопкой, энкодера или кнопки с Arduino
MIT License
138 stars 17 forks source link

Работоспособность кода на ESP8266/ESP12F #32

Closed brightproject closed 1 year ago

brightproject commented 1 year ago
/*
   Пример работы с энкодером с прерыванием. Максимальная чёткость работы
   в любом быдлокоде!
*/

#define CLK 2
#define DT 3
#define SW 4

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, isrCLK, CHANGE);    // прерывание на 2 пине! CLK у энка
  attachInterrupt(1, isrDT, CHANGE);    // прерывание на 3 пине! DT у энка
}

void isrCLK() {
  enc1.tick();  // отработка в прерывании
}
void isrDT() {
  enc1.tick();  // отработка в прерывании
}

void loop() {
  enc1.tick();
  if (enc1.isRight()) Serial.println("Right");         // если был поворот
  if (enc1.isLeft()) Serial.println("Left");

  if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
  if (enc1.isLeftH()) Serial.println("Left holded");
}

Данный код перезагружает модуль ЕСП12 и выдает циклически ошибку

19:57:06.723 -> >>>stack>>>
19:57:06.723 -> 
19:57:06.723 -> ctx: cont
19:57:06.723 -> sp: 3fffff00 end: 3fffffc0 offset: 0000
19:57:06.769 -> 3fffff00:  feefeffe feefeffe feefeffe 3ffef314  
19:57:06.823 -> 3fffff10:  000000fe 00000000 00000000 00000000  
19:57:06.870 -> 3fffff20:  00000000 00000000 00000000 00ff0000  
19:57:06.923 -> 3fffff30:  5ffffe00 5ffffe00 00002580 3ffee588  
19:57:06.970 -> 3fffff40:  00000000 00000003 00000001 4020219e  
19:57:07.024 -> 3fffff50:  40100439 00000001 3ffee520 402021b0  
19:57:07.070 -> 3fffff60:  4020272c 00000003 00000001 402026b1  
19:57:07.124 -> 3fffff70:  401000f8 00000000 feefeffe feefeffe  
19:57:07.171 -> 3fffff80:  3fffdad0 00000000 3ffee574 40202750  
19:57:07.224 -> 3fffff90:  3fffdad0 00000000 3ffee574 40201072  
19:57:07.324 -> 3fffffa0:  feefeffe feefeffe feefeffe 40201d2c  
19:57:07.324 -> 3fffffb0:  feefeffe feefeffe 3ffe85d8 40100cf5  
19:57:07.425 -> <<<stack<<<
19:57:07.425 -> 
19:57:07.425 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
19:57:07.472 -> H!⸮⸮)⸮@H⸮⸮tH⸮ISR not in IRAM!
19:57:07.572 -> 
19:57:07.572 -> User exception (panic/abort/assert)
19:57:07.618 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
19:57:07.664 -> 
19:57:07.664 -> Abort called

Автор библиотеки пишет, что нужно в имя функции подставлять IRAM_ATTR void имя(){} https://alexgyver.ru/lessons/interrupts/ Но в таком случае функция isrCLK не декларирована вообще. В статье всего две строки по поводу wemos mini(esp8266)

На esp8266 прерывание можно настроить стандартными средствами на любом пине.

Приведите хотя бы один пример использования прерываний для этих "железок"!

brightproject commented 1 year ago

Работающее решение на прерываниях для ESP8266

#define ENC_A 12
#define ENC_B 14
#define ENC_KEY 13

#include "GyverEncoder.h"
Encoder enc1(ENC_A, ENC_B, ENC_KEY);

void setup() {
  Serial.begin(9600);
  enc1.setType(TYPE2);        // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип\=
  attachInterrupt(0, isr_ENC_A, CHANGE);    // прерывание на 2 пине! CLK у энка
  attachInterrupt(1, isr_ENC_B, CHANGE);    // прерывание на 3 пине! DT у энка
}

//void ICACHE_RAM_ATTR my_int();

ICACHE_RAM_ATTR  void isr_ENC_A() {
  enc1.tick();  // отработка в прерывании
}

ICACHE_RAM_ATTR void isr_ENC_B() {
  enc1.tick();  // отработка в прерывании
}

void loop() {
  enc1.tick();
  if (enc1.isRight()) Serial.println("Right");         // если был поворот
  if (enc1.isLeft()) Serial.println("Left");

  if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
  if (enc1.isLeftH()) Serial.println("Left holded");
}

Исходник как "доработать" функцию, смотрел здесь.

Везде в интернете находил примеры с неверной последовательностью

 void ICACHE_RAM_ATTR MyInterruptHandler()
{
  // do your interrupt handling stuff in here....
}

Но это неверно, либо не работает для esp8266!!!

Также находил код с примером, где ICACHE_RAM_ATTR подставлять в дефайн в начале кода.

Помимо этого находил разные строки для добавления, например встречал вместо ICACHE_RAM_ATTR пишут IRAM_ATTR Ответ почему так нашел здесь.

_Примечание. Начиная с версии 3.0.0 esp8266/Arduino , ICACHE_RAM_ATTR был изменен на IRAMATTR. Для будущих читателей я обновил ссылки на документацию по ESP8266 Arduino Core , но остальную часть вопроса оставил без изменений.

Вообще не понимаю, это своего рода "костыль" от самого espressif?

ICACHE_RAM_ATTR и ICACHE_FLASH_ATTR являются атрибутами компоновщика. После того, как вы скомпилируете свой скетч, вы можете сказать, должна ли функция храниться в ОЗУ или во флэш-памяти (обычно вы ничего не устанавливаете: нет кеша).

ESP8266 является многозадачным, а ESP32 имеет 2 ядра. Таким образом, вы можете выполнять свой код как многопоточный, поскольку он использует RTOS.

А теперь проблема: Вся флешка используется под программу и хранилище. Чтение и запись во флэш-память могут выполняться только через 1 поток. Если вы попытаетесь получить доступ к флэш-памяти одновременно через 2 разных потока, ваш ESP, вероятно, выйдет из строя.

Это потому, что вы можете поместить свою функцию в ОЗУ вместо флэш-памяти. Так что даже если вы что-то записываете в EEPROM или flash, эту функцию можно вызвать без обращения к flash.

С ICACHE_RAM_ATTRвами поставить функцию на ОЗУ.

С ICACHE_FLASH_ATTRвами поставить функцию на FLASH (для экономии оперативной памяти).

Функции прерывания должны использовать ICACHE_RAM_ATTR. Функция, которая вызывается часто, не должна использовать какой-либо атрибут кеша.

Важно: НИКОГДА не обращайтесь к флэш-памяти внутри прерывания! Прерывание может произойти во время доступа к флешке, поэтому если вы попытаетесь получить доступ к флешке в это же время, вы получите сбой (иногда это происходит через 1-2 часа после использования вашего устройства).

Поскольку у вас есть только 32 КБ IRAM (ОЗУ инструкций), вы должны попытаться поместить в ОЗУ только функции прерывания, а не все свои функции, даже если это возможно сделать.

GyverLibs commented 1 year ago

читайте доки на свою версию SDK esp8266, там в разных версиях прерывания нужно декларировать по разному