8000 Wireless mouse leads to core hang up / How to enable logging · Issue #527 · adafruit/Adafruit_TinyUSB_Arduino · GitHub
[go: up one dir, main page]

Skip to content

Wireless mouse leads to core hang up / How to enable logging #527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
int0h opened this issue May 19, 2025 · 4 comments
Open

Wireless mouse leads to core hang up / How to enable logging #527

int0h opened this issue May 19, 2025 · 4 comments
Labels
Bug Something isn't working

Comments

@int0h
Copy link
int0h commented May 19, 2025

Operating System

Linux

Arduino IDE version

2.3.6

Board

Adafruit Feather RP2040 with USB Type A Host

ArduinoCore version

4.5.3 (not sure)

TinyUSB Library version

3.4.4

Sketch as ATTACHED TXT

I used some examples from here: https://github.com/adafruit/Adafruit_TinyUSB_Arduino/blob/master/examples/DualRole/HID/hid_mouse_tremor_filter/hid_mouse_tremor_filter.ino

I did slight modifications: I added HEARTBEAT logging, but code behaves the same way without this changes, I also tried other examples it always behaves the same.

/*********************************************************************
 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 Copyright (c) 2019 Ha Thach for Adafruit Industries
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

/* This example demonstrates use of both device and host, where
 * - Device run on native usb controller (roothub port0)
 * - Host depending on MCUs run on either:
 *   - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
 *   - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
 *
 * Requirements:
 * - For rp2040:
 *   - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
 *   - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
 *   - Provide VBus (5v) and GND for peripheral
 *   - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
 * - For samd21/51, nrf52840, esp32:
 *   - Additional MAX2341e USB Host shield or featherwing is required
 *   - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
 */

/* Example sketch receive mouse report from host interface (from e.g consumer mouse)
 * and apply a butterworth low pass filter with a specific CUTOFF_FREQUENCY on hid mouse movement report.
 * Filtered report are send via device interface (to PC) acting as a "Mouse Tremor Filter".
 */

// USBHost is defined in usbh_helper.h

#define CFG_TUSB_DEBUG 3
#define CFG_TUSB_DEBUG_PRINTF(...) Serial.printf(__VA_ARGS__)

#include <Adafruit_TinyUSB.h>
#include <pio_usb.h>
#include "usbh_helper.h"

#define TU_LOG(...)   Serial.printf(__VA_ARGS__)
#define TU_LOG1(...)  Serial.printf(__VA_ARGS__)
#define TU_LOG2(...)  Serial.printf(__VA_ARGS__)
#define TU_LOG3(...)  Serial.printf(__VA_ARGS__)
#define tu_printf(...)  Serial.printf(__VA_ARGS__)



// HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = {
    TUD_HID_REPORT_DESC_MOUSE()
};

// USB HID object: desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);

//------------- Low pass filter with Butterworth -------------//
// Butterworth low-pass filter coefficients
typedef struct {
  float b0, b1, b2, a1, a2;
} butterworth_coeffs_t;

#define SAMPLING_FREQUENCY 100.0  // Hz
#define CUTOFF_FREQUENCY    10.0  // Hz

// x, y
butterworth_coeffs_t coeffs[2];

butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency);

void filter_report(hid_mouse_report_t const *report);

// extern "C" int _write(int fd, const void *buf, size_t count) {
//   // Redirect printf output to Serial
//   Serial.write((const uint8_t*)buf, count);
//   return count;
// }


void setup() {
  Serial.begin(115200);

  // while (!Serial) delay(10);

  usb_hid.begin();

  coeffs[0] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
  coeffs[1] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);

#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
  // init host stack on controller (rhport) 1
  // For rp2040: this is called in core1's setup1()
  USBHost.begin(1);
#endif

  //while ( !Serial ) delay(10);   // wait for native usb
  Serial.println("TinyUSB Mouse Tremor Filter Example");
}


#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
//--------------------------------------------------------------------+
// Using Host shield MAX3421E controller
//--------------------------------------------------------------------+
void loop() {
  USBHost.task();
  Serial.flush();
}

#elif defined(ARDUINO_ARCH_RP2040)
//--------------------------------------------------------------------+
// For RP2040 use both core0 for device stack, core1 for host stack
//--------------------------------------------------------------------+
void loop() {
  Serial.flush();

  static uint32_t lastHeartbeat0 = 0;
  if (millis() - lastHeartbeat0 > 5000) {
    Serial.printf("[%.3lums] HEARTBEAT0: loop running\n", millis());
    lastHeartbeat0 = millis();
    tu_printf("boo");
   
8000
 TU_LOG("This should appear in Serial\n");
    TU_LOG2("TinyUSB initialized\r\n");
  }
}

//------------- Core1 -------------//
void setup1() {
  // configure pio-usb: defined in usbh_helper.h
  rp2040_configure_pio_usb();

  // run host stack on controller (rhport) 1
  // Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
  // host bit-banging processing works done in core1 to free up core0 for other works
  USBHost.begin(1);
}

void loop1() {
  USBHost.task();

  static uint32_t lastHeartbeat1 = 0;
  if (millis() - lastHeartbeat1 > 5000) {
    Serial.printf("[%.3lums] HEARTBEAT1: loop running\n", millis());
    lastHeartbeat1 = millis();
    Serial.printf("CFG_TUSB_DEBUG: %u\n", CFG_TUSB_DEBUG);
  }
}

#endif

//--------------------------------------------------------------------+
// TinyUSB Host callbacks
//--------------------------------------------------------------------+
extern "C"
{

// Invoked when device with hid interface is mounted
// Report descriptor is also available for use.
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
// it will be skipped therefore report_desc = NULL, desc_len = 0
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
  (void) desc_report;
  (void) desc_len;
  uint16_t vid, pid;
  tuh_vid_pid_get(dev_addr, &vid, &pid);

  Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
  Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);

  uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
  if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
    Serial.printf("HID Mouse\r\n");
    if (!tuh_hid_receive_report(dev_addr, instance)) {
      Serial.printf("Error: cannot request to receive report\r\n");
    }
  }
}

// Invoked when device with hid interface is un-mounted
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
  Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
}


// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
  filter_report((hid_mouse_report_t const *) report);

  // continue to request to receive report
  if (!tuh_hid_receive_report(dev_addr, instance)) {
    Serial.printf("Error: cannot request to receive report\r\n");
  }
}

} // extern C

//--------------------------------------------------------------------+
// Low pass filter Functions
//--------------------------------------------------------------------+

butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency) {
  butterworth_coeffs_t coe;

  float omega = 2.0 * PI * cutoff_frequency / sampling_frequency;
  float s = sin(omega);
  float t = tan(omega / 2.0);
  float alpha = s / (2.0 * t);

  coe.b0 = 1.0 / (1.0 + 2.0 * alpha + 2.0 * alpha * alpha);
  coe.b1 = 2.0 * coe.b0;
  coe.b2 = coe.b0;
  coe.a1 = 2.0 * (alpha * alpha - 1.0) * coe.b0;
  coe.a2 = (1.0 - 2.0 * alpha + 2.0 * alpha * alpha) * coe.b0;

  return coe;
}

float butterworth_filter(float data, butterworth_coeffs_t *coeffs, float *filtered, float *prev1, float *prev2) {
  float output = coeffs->b0 * data + coeffs->b1 * (*prev1) + coeffs->b2 * (*prev2) - coeffs->a1 * (*filtered) -
                 coeffs->a2 * (*prev1);
  *prev2 = *prev1;
  *prev1 = data;
  *filtered = output;
  return output;
}

void filter_report(hid_mouse_report_t const *report) {
  static float filtered[2] = { 0.0, 0.0 };
  static float prev1[2] = { 0.0, 0.0 };
  static float prev2[2] = { 0.0, 0.0 };

  butterworth_filter(report->x, &coeffs[0], &filtered[0], &prev1[0], &prev2[0]);
  butterworth_filter(report->y, &coeffs[1], &filtered[1], &prev1[1], &prev2[1]);

  hid_mouse_report_t filtered_report = *report;
  filtered_report.x = (int8_t) filtered[0];
  filtered_report.y = (int8_t) filtered[1];

  usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
}

Compiled Log as ATTACHED TXT

[152076ms] Core1 HEARTBEAT: USBHost.task() called
[152687ms] HEARTBEAT: loop running
[153688ms] HEARTBEAT: loop running
[154077ms] Core1 HEARTBEAT: USBHost.task() called
[154689ms] HEARTBEAT: loop running
[155690ms] HEARTBEAT: loop running
[156078ms] Core1 HEARTBEAT: USBHost.task() called
[156691ms] HEARTBEAT: loop running
[157692ms] HEARTBEAT: loop running
[158693ms] HEARTBEAT: loop running
[159694ms] HEARTBEAT: loop running
[160695ms] HEARTBEAT: loop running
[161696ms] HEARTBEAT: loop running

What happened ?

Disclaimer: I started a topic on the forum: https://forums.adafruit.com/viewtopic.php?p=1055930#p1055930 but it was a bit fruitless (pun intended).

All context info I have (I'll share more if needed):

NixOS, Arduino IDE 2.3.6
Windows 11, Arduino IDE 2.3.6
SdFat: 2.2.54
Pico PIO USB: 0.7.1
MIDI Library: 5.0.2
Adafruit SPIFlash: 5.1.1
Adafruit NeoPixel: 1.13.0
rp2040: 4.5.3
Adafruit TinyUSB Library: 3.4.4
---
Mice:
- (working one):  Logitech m500, wired, 8bit XY resolution (), sends reports of 6 bytes;
- (broken one): Logitech Wireless Mouse M185, wireless with dongle, 16 bit XY resolution, sends reports of 7 bytes;

I connect a wireless mouse with dongle to a board (USB A) while the board connected to a laptop (or PC it did not matter) over USB C.

Everything works as expected, I can move mouse over screen for some time (1 - 5 minutes), then it stops, the board apparently stops receiving HID reports (if I can trust Serial.printf logging) and it does not react on any mouse movement and even plugging unplugging the dongle (I don't get mount / unmount messages).


...then I did more investigating)...

I added 2 heartbeat serial logs like so:

void loop() {
  Serial.flush();

  static uint32_t lastHeartbeat0 = 0;
  if (millis() - lastHeartbeat0 > 5000) {
    Serial.printf("[%.3lums] HEARTBEAT0: loop running\n", millis());
    lastHeartbeat0 = millis();
  }
}

Which resulted in this log:

[152076ms] Core1 HEARTBEAT: USBHost.task() called
[152687ms] HEARTBEAT: loop running
[153688ms] HEARTBEAT: loop running
[154077ms] Core1 HEARTBEAT: USBHost.task() called
[154689ms] HEARTBEAT: loop running
[155690ms] HEARTBEAT: loop running
[156078ms] Core1 HEARTBEAT: USBHost.task() called
[156691ms] HEARTBEAT: loop running
[157692ms] HEARTBEAT: loop running
[158693ms] HEARTBEAT: loop running
[159694ms] HEARTBEAT: loop running
[160695ms] HEARTBEAT: loop running
[161696ms] HEARTBEAT: loop running

Which I understand as either the core 1 (the one that handles USB host) "crashes" (I'm not sure if it applicable or possible) or goes into infinite loop. So it makes sense that the board does not react to mouse anymore.


...(then I did more digging)...

I used 120 MHz CPU clock at first and it lasts a couple of minutes and then randomly stops working.
I tried 240 MHz clock and it much better, it would last 30 minutes without a problem but then it stops working again.

I also tried 10ms timeout in task(), like

void loop1() {
  USBHost.task(10);

It might have had a good effect (mouse was responsive for longer period of time, around 5 minutes instead of 2), but it might have been an measurement error. (these hangups feel really random and not consistent)

All mice work without any issues with regular PC's of course.

How to reproduce ?

  1. take any (at least all I tried) host usb sample code
  2. connect wireless (or maybe this specific model) mouse
  3. wait
  4. it stops working

Debug Log

I actually could not enable TinyUSB internal logging, it possibly would really helpful to see if there are any messages leading to the issue. I would appreciate any advice on how to enable the logs.

I use Arduino IDE 2.3.6 on Linux + Adafruit board and Adafruit_TinyUSB, I tried editing ~/.arduino15/packages/rp2040/hardware/rp2040/4.5.3/platform.txt, and adding CFG_TUSB_DEBUG=3 :

compiler.c.extra_flags=-DCFG_TUSB_DEBUG=3
compiler.cpp.extra_flags=-DCFG_TUSB_DEBUG=3

I tried #define CFG_TUSB_DEBUG=3 at the top of the sketch source code and some other things but I cannot see any logs. I also noticed that TinyUSB uses Serial1 for logging (I might be completely wrong though) and I tried SERIAL_TUSB_DEBUG=Serial but it did not work neither.

So if someone can help me turn with that it would be great.

Screenshots

No response

@int0h int0h added the Bug Something isn't working label May 19, 2025
@hathach
Copy link
Member
hathach commented May 20, 2025

There is a few update to pio-usb which isn't released yet, make sure

  • use the git latest on both pio-usb and this repo.
  • after enabed -DCFG_TUSB_DEBUG=2, the log will be output via UART tx/rx. Try to hook an ftdi/cp210x to those pin and use different terminal. USB log cannot be printed to cdc since that is also usb communication, which will just loop forever.

@Edw1n-G
Copy link
Edw1n-G commented May 21, 2025

Hi, I’m experiencing a very similar issue where the core hangs after a few minutes.
Setup:
Wired mouse
dual_role hid_mouse_log_filter.ino example (unchanged)
TinyUSB version 3.5.0
Pico-PIO-USB version 0.7.2
Same board and IDE

Observation:
Without moving the mouse, the core hangs after about 15 minutes.
When moving the mouse:
~5 minutes with Boot Protocol (3 bytes)
1–3 minutes with Report Protocol (11 bytes) added tuh_hid_set_protocol for testing
using high Polling rate (8000hz) or low Polling rate (125hz) did not (noticeably) change anything
I'm just getting started with this board and TinyUSB, so I’m afraid that’s all I can contribute at the moment.

@int0h
Copy link
Author
int0h commented May 25, 2025

Update:

  • I bought a USB UART adapter connected it to the board and managed to see some logs
  • I used 0.7.3 (which was released 3 days ago) and latest (commit hash: 805aa2d41ad9e607c1d086fb7bd197e5a1dd88e2) from this repo

Unfortunately it did not help :(

The logs are quite verbose (with CFG_TUSB_DEBUG=3) but I could not see anything wrong there, no errors, no warnings, no weird messages. All seem to work just fine until it stops.

The fact that it happens so inconsistently and I cannot correlate it to anything makes the troubleshooting process quite uncomfortable.

If anyone has any idea of how it can be fixed please let me know, I'm planning to try another board to see if it's gonna be any better there.

@hathach
Copy link
Member
hathach commented May 29, 2025

use CFG_TUSB_DEBUG=2, then uncomment to have CFG_TUD_LOG_LEVEL=3, https://github.com/adafruit/Adafruit_TinyUSB_Arduino/blob/master/src/arduino/ports/rp2040/tusb_config_rp2040.h#L72 that would disable device stack log. Which make thing easier to follow the host stack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants
0