neu-rah / ArduinoMenu

Arduino generic menu/interactivity system
GNU Lesser General Public License v2.1
931 stars 189 forks source link

ArduinoMenu with rotaryEvent crashing the uC SAMD Xiao #375

Open janczeresnia opened 2 years ago

janczeresnia commented 2 years ago

Hi, First of all, thanks for all the hard work that you have been putting on this library. The last days I have been trying to use this library witch rotaryEvent but I have failed.

Tries to use quadrature rotary encoder by the IO Abstraction library and ArduinoMenu library but when it triggers the event:

the microcontroller hangs.

Maybe I have been doing something wrong or I haven't set the library properly. How to create an encoder via the IO Abstraction library and control it with ArduinoMenu ? What am I doing wrong? Thanks!

/*
 * MenuIO witch SSD1306AsciiOut and rotaryEventIn
 * Rotary encoder over IoAbstraction ioFrom8754
 */

#define LEDPIN LED_BUILTIN

constexpr int OLED_SDA=4;
constexpr int OLED_SDC=5;

#define SSD1306_I2C_ADDRESS 0x3C

#include <SSD1306Ascii.h>
#include <SSD1306AsciiWire.h>

#define menuFont System5x7
#define fontW 5
#define fontH 8

SSD1306AsciiWire oled;

#include <menu.h>
#include <menuIO/SSD1306AsciiOut.h>
#include <menuIO/serialIO.h>
#include <menuIO/chainStream.h>
#include <menuIO/rotaryEventIn.h>

#define MAX_DEPTH 2

using namespace Menu;

#include <IoAbstraction.h>
#include <IoAbstractionWire.h>
#include <TaskManagerIO.h>

#define PCF8574_I2C_ADDR  0x20   // Adres ekspandera PCF8574
#define PCF8574_INT1      A3     // Pin w MCU do obsługi przerwania z PCF8574 Int1
#define PCF8574_PULL_UP   true   // PCF8574 GPIO Pull up

#define LORA_M0M1_PIN   0      // Pin0 podłączony do modułu lora m0 i m1
#define PTT_SW_PIN      1      // Pin1 podłączony do mikrostyku PTT
#define ROTARY_A_PIN    2      // Pin2 podłączony do enkodera A
#define ROTARY_B_PIN    3      // Pin3 podłączony do enkodera B
#define ROTARY_SW_PIN   4      // Pin4 podłączony do enkodera SW
#define ROTARY_LED1_PIN 5      // Pin5 podłączony do enkodera Led1
#define ROTARY_LED2_PIN 6      // Pin6 podłączony do enkodera Led2
#define NC_PIN          7      // Pin7 Not Connected

const int maximumEncoderValue = 255; // Maksymalna wartość enkodera obrotowego
unsigned int currentEncoderValue = 0; // Obecna wartość enkodera obrotowego

unsigned int timeOn=100;
unsigned int timeOff=50;

MENU(mainMenu, "Blink menu", Menu::doNothing, Menu::noEvent, Menu::wrapStyle
  ,FIELD(timeOn,"On","ms",0,1000,10,1, Menu::doNothing, Menu::noEvent, Menu::noStyle)
  ,FIELD(timeOff,"Off","ms",0,10000,10,1,Menu::doNothing, Menu::noEvent, Menu::noStyle)
  ,EXIT("<Exit")
);

RotaryEventIn reIn(
  // register capabilities, see AndroidMenu MenuIO/RotaryEventIn.h file
  RotaryEventIn::EventType::BUTTON_CLICKED |
  RotaryEventIn::EventType::ROTARY_CCW |
  RotaryEventIn::EventType::ROTARY_CW |
  RotaryEventIn::EventType::BUTTON_DOUBLE_CLICKED |
  RotaryEventIn::EventType::BUTTON_LONG_PRESSED);

serialIn serial(Serial);
MENU_INPUTS(in,&reIn,&serial);

// define output device
idx_t serialTops[MAX_DEPTH] = {0};
serialOut outSerial(Serial, serialTops);

// describing a menu output device without macros
// define at least one panel for menu output
const panel panels[] MEMMODE = {{0, 0, 128 / fontW, 64 / fontH}};
navNode* nodes[sizeof(panels) / sizeof(panel)]; // navNodes to store navigation status
panelsList pList(panels, nodes, 1); // a list of panels and nodes
idx_t tops[MAX_DEPTH] = {0, 0}; // store cursor positions for each level
SSD1306AsciiOut outOLED(&oled, tops, pList, 8, 1+((fontH-1)>>3) ); // oled output device menu driver
menuOut* constMEM outputs[] MEMMODE = {&outOLED, &outSerial}; // list of output devices oled and serial
//menuOut* constMEM outputs[] MEMMODE = {&outOLED}; // list of output devices only oled
outputsList out(outputs, sizeof(outputs) / sizeof(menuOut*)); // outputs list

// macro to create navigation control root object (nav) using mainMenu
NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);

// ISR Rotary Encoder
void onEncoderChangeIsr(int newValue) {
  Serial.print("Encoder Change: ");
  Serial.println(newValue);
  if (newValue != currentEncoderValue) 
  {
  Serial.print("Encoder Direction: ");
    if (newValue > currentEncoderValue)
    {
      Serial.println("CW");
      reIn.registerEvent(RotaryEventIn::EventType::ROTARY_CW); // Crash / Hang uC
    }
    if (newValue < currentEncoderValue)
    {
      Serial.println("CCW");
      reIn.registerEvent(RotaryEventIn::EventType::ROTARY_CCW); // Crash / Hang uC
    }
    currentEncoderValue = newValue;
  }
}
// IRS rotary button
void onPttSwitchIsr(uint8_t /*pin*/, bool heldDown) {
  Serial.print("PTT Switch Pressed.");
  Serial.println(heldDown ? "Held" : "Pressed");
  reIn.registerEvent(RotaryEventIn::EventType::BUTTON_CLICKED); // Crash / Hang uC 
}

void onPttSwitchReleasedIsr(uint8_t /*pin*/, bool heldDown) {
  Serial.print("PTT Switch Released - Previously: ");
  Serial.println(heldDown ? "Held" : "Pressed");
}

void setup(void) {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Menu 4.x");
  Serial.println("Use keys + - * /");
  Serial.println("to control the menu navigation");
  Serial.flush();
  Wire.begin();

  // PCF8574 I/O Abstraction
  switches.initialiseInterrupt(ioFrom8754(PCF8574_I2C_ADDR, PCF8574_INT1), PCF8574_PULL_UP);
  ioDevicePinMode(switches.getIoAbstraction(), LORA_M0M1_PIN, OUTPUT);
  ioDevicePinMode(switches.getIoAbstraction(), PTT_SW_PIN, INPUT);
  switches.addSwitch(PTT_SW_PIN, onPttSwitchIsr);
  switches.onRelease(PTT_SW_PIN, onPttSwitchReleasedIsr);
  setupRotaryEncoderWithInterrupt(ROTARY_A_PIN, ROTARY_B_PIN, onEncoderChangeIsr);
  switches.changeEncoderPrecision(maximumEncoderValue, 128);

  // OLED SSD1306 Display
  oled.begin(&Adafruit128x64, SSD1306_I2C_ADDRESS);
  oled.displayRemap(true); // obrót wyświetlacza
  oled.setFont(menuFont);

  oled.clear();
  oled.setCursor(0, 0);
  oled.print("Menu 4.x");
  oled.setCursor(0, 2);
  oled.print("SSD1306Ascii");
  delay(2000);
  oled.clear();
}

void loop(void) {
  taskManager.runLoop(); // I/O Abstraction i Task Manager
  nav.poll();
  digitalWrite(LEDPIN, blink(timeOn,timeOff));
}

bool blink(int timeOn,int timeOff) {
  return millis()%(unsigned long)(timeOn+timeOff)<(unsigned long)timeOn;
}
pocasmen commented 2 years ago

Hi! I might have the same problem! If I use serialIn (input from serial port) everything works! If I use rotary input the CPU (arduino Due) hangs! Any progress??

MXPicture commented 1 year ago

Hi all, I've got the same issue. Have you found a solution? Thanks :)

pocasmen commented 1 year ago

Hi! I didnt find a solution, and I think it must be a bug in the libraries... I have changed from de arduino due to nodemcu maintaining the basic code and everything works...