M5Dial icon indicating copy to clipboard operation
M5Dial copied to clipboard

Encoder interrupts break USB OTG functionality

Open Rob65 opened this issue 2 years ago • 1 comments

When the encoder is used, the encoder interrupt seems to interfere with the USB interrupt. On my sketch with USB Keyboard and Serial, USB stops working when the encoder wheel is rotated fast for a few seconds. WIndows will sometimes report a malfunctioning USB device but most of the times, the device just stops working.

Full code of the sketch is below. I must add that in order for the USB OTG to work in combination with the encoder, the Encoder::read method was changed to not call the noInterrupts() and interrupts() functions since that always breaks the USB device. Note that there should be no harm in doing so since the access to encoder.position in that method is an atomic (32 bit read) action that cannot be interrupted. I also tested this change to be working in combination with the standard "Hardware CDC and JTAG" mode.

Small explanation of the example: the loop reads the encoder and prints the position. It will then simulate a cursor left or right, depending on the CCW/CW rotation of the encoder. Printing of the encoder position at the top of loop() is done constantly to show that the sketch keeps working when the encoder is not rotated. It will happily print text for 15 minutes in a row but as soon as the encoder is rotated for a few seconds, USB stops working.

#include "src/M5Dial/M5Dial.h"
#include "USB.h"
#include "USBHIDKeyboard.h"

USBHIDKeyboard Keyboard;

void setup() {
  //auto cfg = M5.config();
  M5Dial.begin(true, false);
  Keyboard.begin();
  Serial.begin();
  USB.begin();
  Serial.println("Running");
}

long oldPosition = 0;

void loop() {

  long newPosition = (M5Dial.Encoder.read()+2) >> 2;
  Serial.printf("Pos = %d\n", newPosition);
  if(newPosition < oldPosition) {
    oldPosition--;
    Keyboard.press(KEY_LEFT_ARROW);
    Keyboard.releaseAll();
  }
  if(newPosition > oldPosition) {
    oldPosition++;
    Keyboard.press(KEY_RIGHT_ARROW);
    Keyboard.releaseAll();
  }

  delay(1);
}

Rob65 avatar Dec 20 '23 16:12 Rob65

@Rob65: Have you tried the encoder.h and encoder.cpp-Version of MitchBradley (see issue #8)? This alternative to the M5Stack-Encoder-driver uses the ESP32 PCNT hardware – no need for interrupts.

Under MacOS I also encounter an issue with the HID-functionality: As soon as USB.begin() and Keyboard.begin() is called, the Serial-connection is lost and can only be recovered by the annoying method of switching the device off and re-power it while Btn-0 is pressed. This happens independently of the encoder-usage, but the HID-Keyboard remains active.

wichjan avatar Mar 14 '24 18:03 wichjan