Excessive Overhead?

Hello:

I’m building a little POV LED spinner. This is the first time I’ve written an Arduino app that was so speed intensive. As the spinner gets to useful RPMs the image stretches, which indicates to me that I’m running up against time constraints. I was concerned about how long it would take to write all those LED values. But when I test I find that the write operation takes ~ 2550 microseconds. It’s the PlatformIO overhead that seems to be killing it. It takes 130 milliseconds from the end of loop() to its start.

Anyone know if this is normal, or if there’s something I can do to reduce this overhead?

My non-write code is minimal (2275 us) and these are my libs:

#include <Arduino.h>
#include <FastLED.h>

Thanks in advance.

PlatformIO overhead? I don’t see how that would be possible.

PlatformIO is an IDE that uses the tools you specify in the platformio.ini file, for example:

framework = arduino
platform = atmelavr
board = ATmega1284P

Of course, it also uses the libraries you specify using #include.
In other words, the development environment runs as software on your computer and compiles machine code for the target embedded device. As far as the target device is concerned, it doesn’t “know” or “care” what IDE compiled the code.
Code compiled from the Arduino IDE should be identical to code compiled using PlatformIO as long as the versions of all tools are the same and the compiler flags used are the same.

To chase down the performance issue, it might be best to share relevant code.
How do you know that it takes 130 ms to restart the loop? That is an extremely long duration for a microcontroller so there’s probably something going on here that is very inefficient.

Are you using a debugger?

1 Like

I normally use CLion, but tried this in the Arduino IDE too.

[env:seeed_xiao_esp32c3]
platform = espressif32
board = seeed_xiao_esp32c3
framework = arduino
lib_deps = fastled/FastLED@^3.6.0

it doesn’t “know” or “care” what IDE compiled the code.

I’m thinking in terms of code that exists in the env as support. IOW, something calls loop(). The support code in the environment might be different if compiled by PlatformIO verses Arduino.

How do you know that it takes 130 ms to restart the loop? / debugger

Since the device spins I cannot plug into it. I tried to capture logs to be printed after a spin cycle, but the Arduino seems to reset when I connect it to my computer. In order to determine the time measurements I use an external LED and binary search a value. To determine loop time I captured micros() at the end of a loop() call and then took the difference between that and micros() at the beginning.

That is an extremely long duration…

Agreed.

My code


#include <Arduino.h>
#include <FastLED.h>


#define LED_PIN_1 D0
#define LED_PIN_2 D1
#define HALL_SENSOR D10
#define LED_ON D4

const unsigned int NUM_LEDS = 30;
const unsigned int FRAME_COUNT = 3;
const unsigned long FRAME_RATE = 1000000; // 1 second
const CRGB BRIGHT_BLUE = 0x7799FF;
const CRGB BRIGHT_GREEN = 0x22FF00;

CRGB frames[FRAME_COUNT][NUM_LEDS][NUM_LEDS] = {
    {
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black },
        { CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black }
    },
    {
// omitted for brevity
    },
    {
// omitted for brevity
    }
};

// Angles are measured in units of 10000.  180 degrees is not enough resolution
const unsigned long ANGLE_ALL = 1440;
const unsigned long QUIET_START_ANGLE = 60;
const unsigned long COLUMN_ANGLE = 1;
const unsigned long ANTI_BOUNCE = 3000;
const unsigned long MAX_SPIN_DURATION = 5000000; // 2 seconds

unsigned long FREQ = 2000;
unsigned long times[4] = {};

enum ROTATION_STATE { IDLE = 1, SETUP = 2, QUIET_START = 3, GRID_1 = 4, QUIET_MIDDLE = 5, GRID_2 = 6, QUIET_END = 7 };

CRGB leds_1[NUM_LEDS];
CRGB leds_2[NUM_LEDS];
//BLECharacteristic *pCharacteristic;
ROTATION_STATE rotationState = IDLE;
volatile unsigned long spinStart = 0; // time of next event, usually a column
volatile unsigned long spinTime = 0; // duration of spin in microseconds
volatile bool bNewSpin = false; // how the Hall sensor communicates to the main loop that a new spin has started
volatile unsigned long nextEvent = 0; // time of next event, e.g. a column of pixels
unsigned int nColumn = 0; // column currently being drawn
volatile unsigned int nFrame = -1; // frame of the animation being drawn
volatile unsigned long nChangeFrameAt = 0;
            volatile unsigned long maxWrite = 0;

void shine(CRGB color) {
  for (int j=0; j<NUM_LEDS; j++) {
    leds_1[j] = color;
//    leds_2[j] = color;
  }
  FastLED.show();
}

void dark() {
  for (int j=0; j<NUM_LEDS; j++) {
    leds_1[j] = CRGB::Black;
//    leds_2[j] = CRGB::Black;
  }
  FastLED.show();
}

//Hall sensor 1 interrupt routine
void ISR_HallSensor() {
  unsigned long now = micros();
  // Check if HYS ms have passed since the last trigger
  if (now - spinStart >= ANTI_BOUNCE) { // assume triggers within ANTI_BOUNCE are bounces
    if (spinStart != 0) { // calculate spinTime only if we have a valid lastHallTrigger
      spinTime = (now - spinStart);
      bNewSpin = true;
    }
    spinStart = now;
  }
}

// writes a column of pixels
void writeColumn(CRGB *frames) {
  for (int j=0; j<NUM_LEDS; j++) {
    leds_1[j] = frames[j];
  }
  FastLED.show();
}

void setup() {
  FastLED.addLeds<NEOPIXEL, LED_PIN_1>(leds_1, NUM_LEDS);
  FastLED.addLeds<NEOPIXEL, LED_PIN_2>(leds_2, NUM_LEDS);
  Serial.begin(250000);
  pinMode(HALL_SENSOR, INPUT);
  pinMode(LED_ON, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(HALL_SENSOR), ISR_HallSensor, RISING);
}

volatile int test1 = -1;

void loop() {
  unsigned long now = micros();

  int duration = (test1 != -1) ? (int)micros() - test1 : 0;
  if (duration > maxWrite) {
    maxWrite = duration;
    if (maxWrite > 131250) {
      digitalWrite(LED_ON, HIGH);
    }
  }

  if (bNewSpin) {
    rotationState = SETUP;
    bNewSpin = false;
    if (now > nChangeFrameAt) {
      nFrame = ++nFrame % FRAME_COUNT;
      nChangeFrameAt = now + FRAME_RATE;
    }
  }

  unsigned long progress = now - spinStart;
  switch (rotationState) {
    case IDLE: // just wait here for a new rotation
      break;
    case SETUP: // just wait here for a new rotation
      nextEvent =  progress + ((spinTime * QUIET_START_ANGLE) / ANGLE_ALL);
      rotationState = QUIET_START;
      break;
    case QUIET_START:
      if (progress > nextEvent) {
        nColumn = 0;
        rotationState = GRID_1;
      }
      break;
    case GRID_1:
      if (nColumn > NUM_LEDS) {
        dark();
        rotationState = QUIET_MIDDLE;
      } else {
        if (progress > nextEvent) {
          writeColumn(frames[nFrame][nColumn++]);
          nextEvent = progress + ((spinTime * COLUMN_ANGLE) / ANGLE_ALL);
        }
      }
      break;
    case QUIET_MIDDLE:
      break;
    } // switch on rotationState

  test1 = micros();
}

I’ve only dabbled very briefly with an esp32 MCU more than a year ago so I might not be the best person to try to help.

At a glance, I don’t see anything wrong with the code you’ve shared. You could look at how the Arduino framework implements app_main() for esp32. I found it at the following default path:

C:\Users\[username]\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp

The loop() method is called from loopTask(), defined as follows:

void loopTask(void *pvParameters)
{
    setup();
    for(;;) {
#if CONFIG_FREERTOS_UNICORE
        yieldIfNecessary();
#endif
        if(loopTaskWDTEnabled){
            esp_task_wdt_reset();
        }
        loop();
        if (serialEventRun) serialEventRun();
    }
}

Which in turn is referenced in app_main() with a call to an RTOS method xTaskCreateUniversal():

extern "C" void app_main()
{
#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE
    Serial.begin();
#endif
#if ARDUINO_USB_MSC_ON_BOOT && !ARDUINO_USB_MODE
    MSC_Update.begin();
#endif
#if ARDUINO_USB_DFU_ON_BOOT && !ARDUINO_USB_MODE
    USB.enableDFU();
#endif
#if ARDUINO_USB_ON_BOOT && !ARDUINO_USB_MODE
    USB.begin();
#endif
    loopTaskWDTEnabled = false;
    initArduino();
    xTaskCreateUniversal(loopTask, "loopTask", getArduinoLoopTaskStackSize(), NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
}

So I’m guessing that your delay is caused by the RTOS. I have no experience here but I’m guessing you might be able to configure the RTOS and hopefully speed up the execution of loopTask.

Perhaps others on the forum would care to comment.

-------------------------- EDIT ----------------------------

Ooops… actually, somehow I missed the for-loop enclosing loop().

Three methods that might delay your loop:
yieldIfNecessary()
esp_task_wdt_reset()
serialEventRun()

Again, I don’t know esp32 nor FreeRTOS so you’ll need to research this further.

I would try the following:

  • make sure I’m not calling yield in loop unnecessarily
  • disable watchdog timer
  • look into serialEventRun() to make sure I’m not delaying the loop because of USB traffic or something

Good luck!

Remove from loop all micro chaos and toggle led = measure with scope.
And 130ms say your loop never work , but restart repeat… Connect and show serial log output.
Check ESPC3 requirments … Esp32-c3-mini-1 serial monitor not working - Development Platforms - PlatformIO Community

Hi Diamet,

I have developed multiple POV displays - I started my journey with an Arduino nano, continued with a nano/ESP01s combo, then worked quite a bit with RP2040/ESP32 combo, and I now ended up with an Raspberry Pi pico W. I think that is the ideal controller for POV displays.
However, I did quite some research on an ESP32 only displays - ESP32 is such a nice processor. But I gave up on the ESP32 for the time critical control of the LEDs. There is much overhead from RTOS and the WiFi function and there is very little timer functionality and user control. The RP2040 is „a entirely different world“ and so much more powerful, when it comes to time critical tasks.
One word on Neopixel. Please check out my second video. In the end I am elaborating on Neopixel and did some math which shows, that the LED is too slow for POV applications. There used to be a fast variant, but it disappeared from the market, apparently.

So, here are the links of the videos. In the bio of the videos, there are links for my GitHub repositories.

Arduino nano / ESP01s:

RP2040/ESP32:

Raspberry Pi Pico W:

I trust that helps, best regards
Ludwin

@john1 - Very helpful information. I wonder if I can profile or optimize those overhead routines to increase performance. Thank you.

@marian.mlcoch Great suggestion. I do not have a scope handy, but I can get access to one.

@lhm0 Great project. Very cool POV. I do have some RP2040s Xiaos here. I will try them out. Excellent advice.

After juggling my profile code to different parts of the system , and then returning to overhead I find that the number is 4.3ms, which seems much more correct than 130ms. My bad. Nevertheless, 4.3ms will still be too much overhead for my project. I will try the RP2040 and streamline overhead.