ftrias / TeensyThreads

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Specific timing of thread start causes hard fault (invalid EXC_RETURN) in Teensy core

Merlin04 opened this issue · comments

There's a very weird bug I've encountered while using TeensyThreads - I'm not sure if it's an issue with this library or with the Teensyduino core, so I'm reporting the issue to both places.

I'm not entirely sure exactly what triggers it, but it seems that certain timing between the end of a thread and the start of another causes a hard fault. This sketch is the most reliable way I've found to cause the issue:

#include <TeensyThreads.h>
#include <CrashReport.h>

volatile unsigned int d = 1;

void threadFn() {
  next();
}

IntervalTimer t;

void a() {
  threads.addThread(threadFn);
  t.end();
}

void next() {
  d += 1;
  threads.addThread(threadFn);
  t.begin(a, d);
}

void setup() {
  // put your setup code here, to run once:
  delay(5000);
  Serial.println(CrashReport);
  delay(5000);
  threads.setSliceMicros(400);

  threads.addThread(threadFn);

  // we're going to scan through a list of possible delays to figure out what triggers the fault
  next();
}

void loop() {}

The output from it looks something like this:

19:23:49.492 -> CrashReport:
19:23:49.492 -> A problem occurred at (system time) 19:23:35
19:23:49.492 -> Code was executing from address 0x22BA
19:23:49.492 -> CFSR: 40000
19:23:49.492 -> (INVPC) Usage fault: invalid EXC_RETURN
19:23:49.492 -> Temperature inside the chip was 56.82 °C
19:23:49.492 -> Startup CPU clock speed is 600MHz
19:23:49.492 -> Reboot was caused by auto reboot after fault or bad interrupt detected

The address changes a bit per run, but from using addr2line I've determined it always points to somewhere inside the yield function in packages/teensy/hardware/avr/1.58.1/cores/teensy4/yield.cpp.

I actually found this happening and being a very big problem in a real application (took me forever to try to figure out the root cause) - I have a thread which does some debouncing stuff and is triggered by an interrupt on some pins connected to switches, and repeatedly pressing the switches would eventually cause this exact fault. I've put together a simplified example of this in case it helps with testing:

Interrupt-triggered thread example
#include <TeensyThreads.h>
#include <CrashReport.h>

void removeI() {
  detachInterrupt(41);
}

void addI() {
  attachInterrupt(41, []() {
    removeI();
    threads.addThread(threadFn);
  }, LOW);
}

void threadFn() {
  Serial.println("hi!");
  addI();
}

void setup() {
  delay(5000); // give time for serial monitor to auto-reconnect
  Serial.println(CrashReport);
  delay(5000);
  pinMode(41, INPUT_PULLUP);
  threads.setSliceMicros(400);

  threads.addThread(threadFn);
}

void loop() {}

Specifically, I've found the fault occurs after threads.addThread was run, but before the thread function itself runs.

Let me know if there's any way I can help get to the bottom of this, I'm really curious what the actual issue is (and I also really need it to be fixed so I can get my hardware project working reliably).