GyverLibs/EncButton

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

brightproject opened this issue · 2 comments

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

#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 прерывание можно настроить стандартными средствами на любом пине.

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

Работающее решение на прерываниях для 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 был изменен на IRAM_ATTR. Для будущих читателей я обновил ссылки на документацию по 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 (ОЗУ инструкций), вы должны попытаться поместить в ОЗУ только функции прерывания, а не все свои функции, даже если это возможно сделать.

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