XIAO ESP32C2 ~5 ms pause/freeze every 2 seconds

Hi there,

Yes, this is the Rtos that handles the WIFi, etc… Even with radios disabled, the ESP32-C6 runs FreeRTOS on a single application core. Unlike the ESP32/ESP32-S3, the C6 has:

  • One application core (RISC-V) for user code
  • One low-power core for Wi-Fi/BLE and low-level tasks

So even though there are two cores, user code does not run independently from the OS services. That means:

  • Periodic tasks (e.g. watchdog, timers, even idle task management) can interrupt fine-grained timing.
  • Bit-banging GPIO for step pulses is not timing-guaranteed unless it’s running under a hardware peripheral (LEDC, MCPWM, etc).

That tiny stutter every 2 seconds? Likely a FreeRTOS housekeeping or system tick. I haven’t had my coffee yet to have total recall :grin: , let me look and I’ll get back…

HTH
GL :slight_smile: PJ :v:

One cup Later and some AI…

Bit-banging via digitalWrite() or even gpio_set_level() in a loop is not real-time. Especially when tight pulse spacing is required like:

digitalWrite(STEP, HIGH);
delayMicroseconds(5);
digitalWrite(STEP, LOW);
delayMicroseconds(500); // etc.

Even tiny delays in delayMicroseconds() caused by interrupts can introduce jitter or pauses.

:brain: Options to Consider

:white_check_mark: Option 1: Use LEDC (again)

Even if the library doesn’t support LEDC out of the box, you can patch AccelStepper to optionally use LEDC or a timer-driven ISR for the step() routine. It’s been done before with ESP32.

:white_check_mark: Option 2: Use a timer-based ISR

Use hw_timer_t (on other ESPs) or esp_timer on ESP32C6 to schedule a timer interrupt that toggles STEP at fixed intervals, avoiding loop() entirely.

:white_check_mark: Option 3: Use taskDISABLE_INTERRUPTS() block (NOT recommended long-term)

Temporarily disabling interrupts during pulse output might help prove the cause, but is not safe for long durations:

portDISABLE_INTERRUPTS();
digitalWrite(STEP, HIGH);
delayMicroseconds(5);
digitalWrite(STEP, LOW);
portENABLE_INTERRUPTS();

This could stop the stutter, confirming it’s an interrupt issue.
(good to be sure , so a test would be good too)

:white_check_mark: Option 4: Use a different library

Some variants of FastAccelStepper or custom stepper drivers (written for ESP32) use hardware timers, and may be better suited than AccelStepper on ESP32C6.

:white_check_mark: Option 5: Add external step pulse generator

If ultra-smooth motion is needed, some projects offload the pulse generation to an external chip (e.g. TMC2209 in stealth mode, or FPGA/CPLD pulse gen), and the MCU just sets direction/speed.

:warning: Summary Recommendation

Tell the user:

On the ESP32-C6, bit-banging digitalWrite() for stepper pulses isn’t timing-accurate due to the FreeRTOS scheduler—even if radios are off. Because the C6 only has a single application core, periodic OS tasks can cause tiny delays that ruin smooth stepper motion.

Either patch AccelStepper to use LEDC (hardware PWM), or switch to esp_timer-based pulse generation. If your application must use bit-banged pulses, it won’t be reliable on the C6 without real-time hardware assistance.

The S3 has two true Cores, it may perform better too.