Universal Arduino Benchmark

Well, I’ve built a benchmarking tool for Arduino.

I have run it on Uno, Uno R4, Uno Q, Nano, Nano ESP32, Xiao RP2040, ESP32 Devkit, and Multiduino.

Wondering if anyone is interested in results, and especially if anyone is able to run on a few specific boards and let me know if there are issues?

Specifically Teensy, Pico, Due, Giga R1, ESP8266, ESP32-C6, etc

/*
 * Universal Arduino Benchmark Suite
 * Compatible with: Arduino (AVR, ARM, SAMD), ESP32, ESP8266, RP2040 (Pico), STM32, and more!
 * 
 * This benchmark tests:
 * - CPU: Integer, Float, String operations
 * - Memory: SRAM, EEPROM, PSRAM (if available)
 * - I/O: Digital/Analog pins, Serial speed
 * - Board-specific: WiFi, BLE, Flash, etc.
 * 
 * METHODOLOGY:
 * - All computation benchmarks use volatile accumulators to prevent compiler optimization
 * - Results are checksummed and printed to ensure actual execution
 * - Integer operations use uint64_t to prevent silent overflow
 * - Checksums are consumed outside timed blocks for accuracy
 * - GPIO benchmarks include direct register writes alongside digitalWrite() to measure overhead
 * - Serial timing includes flush() to measure actual transmission time
 * - ESP32: CPU cycle counter used to cross-check micros() jitter
 * - EEPROM timing includes flash commit separately (ESP32/ESP8266)
 * - Memory benchmarks accumulate values to prevent dead code elimination
 * - All performance metrics reported as operations per millisecond (ops/ms)
 * - Temperature tracking (CPU stress test only) shows start temp and total gain
 * 
 * Upload to ANY Arduino-compatible board and view results in Serial Monitor (115200 baud)
 */

// ==================== BOARD DETECTION ====================

// ESP32 Family (all variants)
#if defined(ESP32)
#if defined(ARDUINO_NANO_ESP32)
#define BOARD_NAME "Arduino Nano ESP32"
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define BOARD_NAME "ESP32-S3"
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define BOARD_NAME "ESP32-S2"
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#define BOARD_NAME "ESP32-C3"
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define BOARD_NAME "ESP32-C6"
#elif defined(CONFIG_IDF_TARGET_ESP32H2)
#define BOARD_NAME "ESP32-H2"
#else
#define BOARD_NAME "ESP32"
#endif
#define HAS_WIFI
#define HAS_BLE
#ifdef BOARD_HAS_PSRAM
#define HAS_PSRAM
#endif
#include <WiFi.h>
#include <EEPROM.h>
#include <BLEDevice.h>
#include <BLEScan.h>
#include <driver/gpio.h>
#include "soc/gpio_struct.h"
#include "soc/gpio_reg.h"
#include "mbedtls/md5.h"
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
#include "mbedtls/md.h"
#include "mbedtls/pkcs5.h"
#include "mbedtls/version.h"
#if defined(MBEDTLS_SHA3_C)
#include "mbedtls/sha3.h"
#endif
#define EEPROM_SIZE 512

// ESP8266 Family
#elif defined(ESP8266)
#define BOARD_NAME "ESP8266"
#define HAS_WIFI
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#define EEPROM_SIZE 512

// RP2040 Family (Pico, Pico W, Arduino Nano RP2040 Connect)
#elif defined(ARDUINO_ARCH_RP2040)
#if defined(ARDUINO_NANO_RP2040_CONNECT)
#define BOARD_NAME "Arduino Nano RP2040 Connect"
#define HAS_WIFI
#define HAS_BLE
#include <WiFiNINA.h>
#elif defined(ARDUINO_RASPBERRY_PI_PICO_W)
#define BOARD_NAME "Raspberry Pi Pico W"
#define HAS_WIFI
#include <WiFi.h>
#elif defined(ARDUINO_RASPBERRY_PI_PICO)
#define BOARD_NAME "Raspberry Pi Pico"
#elif defined(ARDUINO_NANO_RP2040_CONNECT)
#define BOARD_NAME "Arduino Nano RP2040 Connect"
#define HAS_WIFI
#include <WiFiNINA.h>
#else
#ifndef BOARD_NAME
#define BOARD_NAME "RP2040"
#endif
#endif
#include <EEPROM.h>
// RP2040 temperature sensor - analogReadTemp already declared in Arduino.h
#define HAS_TEMPERATURE
// RP2040 hardware register access
#include "hardware/gpio.h"
#if defined(ARDUINO_ARCH_RP2040) && __has_include("pico/multicore.h")
#include "pico/multicore.h"
#define HAS_PICO_MULTICORE
#endif

// Renesas RA4M1 (Arduino Uno R4 WiFi & Minima)
#elif defined(ARDUINO_UNOR4_WIFI)
#define BOARD_NAME "Arduino Uno R4 WiFi"
#define HAS_WIFI
#define HAS_LED_MATRIX
#include <WiFiS3.h>
#include <EEPROM.h>
#include "Arduino_LED_Matrix.h"
#elif defined(ARDUINO_UNOR4_MINIMA)
#define BOARD_NAME "Arduino Uno R4 Minima"
#define HAS_LED_MATRIX
#include <EEPROM.h>
#include "Arduino_LED_Matrix.h"
#elif defined(ARDUINO_ARCH_RENESAS)
#define BOARD_NAME "Renesas (Uno R4 family)"
#include <EEPROM.h>

// Arduino SAMD Family (Zero, MKR, Nano 33 IoT)
#elif defined(ARDUINO_SAMD_ZERO)
#define BOARD_NAME "Arduino Zero"
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_MKR1000)
#define BOARD_NAME "Arduino MKR1000"
#define HAS_WIFI
#define BOARD_SAMD
#include <WiFi101.h>
#elif defined(ARDUINO_SAMD_MKRZERO)
#define BOARD_NAME "Arduino MKR Zero"
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
#define BOARD_NAME "Arduino MKR WiFi 1010"
#define HAS_WIFI
#define BOARD_SAMD
#include <WiFiNINA.h>
#elif defined(ARDUINO_SAMD_MKRFOX1200)
#define BOARD_NAME "Arduino MKR FOX 1200"
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310)
#define BOARD_NAME "Arduino MKR WAN 1300/1310"
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_MKRGSM1400)
#define BOARD_NAME "Arduino MKR GSM 1400"
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_MKRNB1500)
#define BOARD_NAME "Arduino MKR NB 1500"
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_MKRVIDOR4000)
#define BOARD_NAME "Arduino MKR Vidor 4000"
#define HAS_FPGA
#define BOARD_SAMD
#elif defined(ARDUINO_SAMD_NANO_33_IOT)
#define BOARD_NAME "Arduino Nano 33 IoT"
#define HAS_WIFI
#define HAS_BLE
#define HAS_IMU
#define BOARD_SAMD
#include <WiFiNINA.h>
#elif defined(ARDUINO_ARCH_SAMD)
#define BOARD_NAME "SAMD (ARM Cortex-M0+)"
#define BOARD_SAMD

// Arduino Nano 33 BLE Family (nRF52840)
#elif defined(ARDUINO_ARDUINO_NANO33BLE)
#define BOARD_NAME "Arduino Nano 33 BLE"
#define HAS_BLE
#define HAS_IMU
#define BOARD_NRF52
#elif defined(ARDUINO_NANO33BLE)
#define BOARD_NAME "Arduino Nano 33 BLE (Rev2)"
#define HAS_BLE
#define HAS_IMU
#define BOARD_NRF52

// Arduino Portenta Family
#elif defined(ARDUINO_PORTENTA_H7_M7)
#define BOARD_NAME "Arduino Portenta H7"
#define HAS_WIFI
#define HAS_BLE
#define HAS_DUAL_CORE
#define BOARD_STM32H7
#elif defined(ARDUINO_PORTENTA_C33)
#define BOARD_NAME "Arduino Portenta C33"
#define HAS_WIFI
#define HAS_BLE

// Arduino Giga Family
#elif defined(ARDUINO_GIGA)
#define BOARD_NAME "Arduino Giga R1 WiFi"
#define HAS_WIFI
#define HAS_BLE
#define HAS_DUAL_CORE
#define BOARD_STM32H7

// Arduino Mega + WiFi
#elif defined(ARDUINO_AVR_MEGA2560)
#define BOARD_NAME "Arduino Mega 2560"
#include <EEPROM.h>
#define BOARD_AVR
#elif defined(ARDUINO_AVR_ADK)
#define BOARD_NAME "Arduino Mega ADK"
#include <EEPROM.h>
#define BOARD_AVR

// Multiduino (your custom Uno-derivative)
#elif defined(ARDUINO_AVR_MULTIDUINO)
#define BOARD_NAME "Multiduino"
#include <EEPROM.h>
#include <Wire.h>
#include <RTClib.h>  // Adafruit RTClib for DS1307
#define BOARD_AVR
#define HAS_RTC
#define RTC_I2C_ADDRESS 0x68  // Standard DS1307 I2C address

// Arduino Uno
#elif defined(ARDUINO_AVR_UNO)
#define BOARD_NAME "Arduino Uno"
#include <EEPROM.h>
#define BOARD_AVR
#elif defined(ARDUINO_AVR_UNO_WIFI_REV2)
#define BOARD_NAME "Arduino Uno WiFi Rev2"
#define HAS_WIFI
#include <EEPROM.h>
#include <WiFiNINA.h>
#define BOARD_AVR


// Arduino Nano Family (Classic)
#elif defined(ARDUINO_AVR_NANO)
#define BOARD_NAME "Arduino Nano"
#include <EEPROM.h>
#define BOARD_AVR
#elif defined(ARDUINO_AVR_NANO_EVERY)
#define BOARD_NAME "Arduino Nano Every"
#include <EEPROM.h>
#define BOARD_AVR

// Arduino Leonardo/Micro
#elif defined(ARDUINO_AVR_LEONARDO)
#define BOARD_NAME "Arduino Leonardo"
#include <EEPROM.h>
#define BOARD_AVR
#elif defined(ARDUINO_AVR_MICRO)
#define BOARD_NAME "Arduino Micro"
#include <EEPROM.h>
#define BOARD_AVR

// Arduino Pro/Mini
#elif defined(ARDUINO_AVR_PRO)
#define BOARD_NAME "Arduino Pro"
#include <EEPROM.h>
#define BOARD_AVR
#elif defined(ARDUINO_AVR_MINI)
#define BOARD_NAME "Arduino Mini"
#include <EEPROM.h>
#define BOARD_AVR

// Arduino Due (SAM)
#elif defined(ARDUINO_SAM_DUE)
#define BOARD_NAME "Arduino Due"
#define BOARD_SAM

// Generic AVR catch-all
#elif defined(__AVR__)
#define BOARD_NAME "AVR-based Arduino"
#include <EEPROM.h>
#define BOARD_AVR

// Arduino Uno Q (Dual-processor: STM32U585 MCU + Qualcomm QRB2210 Linux MPU)
#elif defined(ARDUINO_UNO_Q)
#define BOARD_NAME "Arduino Uno Q (MCU)"
#define BOARD_STM32U5
#define BOARD_SRAM_KB 786
#define BOARD_FLASH_KB 2048
#define HAS_DUAL_PROCESSOR  // MCU + Linux MPU
#define HAS_FPU
#define HAS_DSP
#define HAS_RNG
#define USING_ZEPHYR
#define HAS_ROUTER_BRIDGE
#define HAS_RPC_BRIDGE
#include "Arduino_RouterBridge.h"

// STM32 Family (Blue Pill, Black Pill, Nucleo)
#elif defined(ARDUINO_ARCH_STM32)
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
#define BOARD_NAME "STM32 Blue Pill"
#elif defined(ARDUINO_BLACKPILL_F401CC) || defined(ARDUINO_BLACKPILL_F411CE)
#define BOARD_NAME "STM32 Black Pill"
#elif defined(ARDUINO_NUCLEO_F401RE)
#define BOARD_NAME "STM32 Nucleo-F401RE"
#elif defined(ARDUINO_NUCLEO_F411RE)
#define BOARD_NAME "STM32 Nucleo-F411RE"
#else
#define BOARD_NAME "STM32"
#endif
#include <EEPROM.h>
#define BOARD_STM32

// Teensy Family
#elif defined(TEENSYDUINO)
#if defined(__IMXRT1062__)
#if defined(ARDUINO_TEENSY41)
#define BOARD_NAME "Teensy 4.1"
#else
#define BOARD_NAME "Teensy 4.0"
#endif
#elif defined(__MK66FX1M0__)
#define BOARD_NAME "Teensy 3.6"
#elif defined(__MK64FX512__)
#define BOARD_NAME "Teensy 3.5"
#elif defined(__MK20DX256__)
#define BOARD_NAME "Teensy 3.2"
#elif defined(__MK20DX128__)
#define BOARD_NAME "Teensy 3.1/3.0"
#elif defined(__MKL26Z64__)
#define BOARD_NAME "Teensy LC"
#else
#define BOARD_NAME "Teensy"
#endif
#include <EEPROM.h>
#define BOARD_TEENSY

// Adafruit Feather Family
#elif defined(ADAFRUIT_FEATHER_M0)
#define BOARD_NAME "Adafruit Feather M0"
#define BOARD_SAMD
#elif defined(ADAFRUIT_FEATHER_M4)
#define BOARD_NAME "Adafruit Feather M4"
#define BOARD_SAMD

// Seeed Studio
#elif defined(SEEED_XIAO_M0)
#define BOARD_NAME "Seeeduino XIAO"
#define BOARD_SAMD
#elif defined(ARDUINO_SEEED_XIAO_NRF52840) || defined(ARDUINO_Seeed_XIAO_nRF52840)
#define BOARD_NAME "Seeed XIAO nRF52840"
#define HAS_BLE
#define BOARD_NRF52
#elif defined(ARDUINO_SEEED_XIAO_RP2040)
#define BOARD_NAME "Seeed XIAO RP2040"
#elif defined(SEEED_WIO_TERMINAL)
#define BOARD_NAME "Seeed Wio Terminal"
#define HAS_WIFI
#define HAS_BLE
#define HAS_LCD
#define BOARD_SAMD

// Unknown/Generic
#else
#define BOARD_NAME "Unknown Arduino-Compatible"
#endif

// ==================== CONFIGURATION ====================
#define BENCHMARK_ITERATIONS 10000
#define MEMORY_TEST_SIZE 1024


#if defined(ARDUINO_ARCH_RP2040)
#include <Hash.h>
#endif

#include "BenchmarkHelpers.h"
#if defined(ESP32)
#include <HEXBuilder.h>
#endif

// ==================== SERIAL OUTPUT ABSTRACTION ====================
// Uno Q uses Monitor instead of Serial for output
#if defined(ARDUINO_UNO_Q)
  #define SERIAL_OUT Monitor
  #define F_STR(x) x  // Monitor doesn't support F() macro
#else
  #define SERIAL_OUT Serial
  #define F_STR(x) F(x)  // Use F() macro for flash storage on other boards
#endif

// Serial baud rate
#define SERIAL_BAUD 115200

// ==================== GLOBAL VARIABLES ====================
uint8_t testBuffer[256];
unsigned long gMinBenchUs = 20000;
const uint8_t kJitterTrials = 5;

#ifdef HAS_RTC
RTC_DS1307 rtc;
#endif


// ==================== HELPER FUNCTIONS ====================

void printDivider() {
  SERIAL_OUT.println(F_STR("========================================"));
}

void printHeader(const char *title) {
  SERIAL_OUT.println();
  printDivider();
  SERIAL_OUT.println(title);
  printDivider();
}

unsigned long benchmarkStart;

void startBenchmark() {
  benchmarkStart = micros();
}

unsigned long endBenchmark() {
  return micros() - benchmarkStart;
}

template<typename T, size_t N>
struct MedianCollector {
  T values[N];
  uint8_t count;

  void add(T value) {
    if (count < N) {
      values[count++] = value;
    }
  }

  T median() const {
    if (count == 0) {
      return T();
    }
    T sorted[N];
    for (uint8_t i = 0; i < count; i++) {
      sorted[i] = values[i];
    }
    for (uint8_t i = 1; i < count; i++) {
      T key = sorted[i];
      int8_t j = i - 1;
      while (j >= 0 && sorted[j] > key) {
        sorted[j + 1] = sorted[j];
        j--;
      }
      sorted[j + 1] = key;
    }
    uint8_t mid = count / 2;
    if (count % 2 == 1) {
      return sorted[mid];
    }
    return (sorted[mid - 1] + sorted[mid]) / 2;
  }
};

void calibrateBenchmarkTime() {
  unsigned long start = micros();
  unsigned long next = start;
  uint32_t spins = 0;
  while (next == start && spins < 100000) {
    next = micros();
    spins++;
  }
  unsigned long microsResolution = next - start;

  unsigned long delayStart = micros();
  delayMicroseconds(1000);
  unsigned long delayElapsed = micros() - delayStart;
  long delayError = abs((long)delayElapsed - 1000);

  if (microsResolution <= 2 && delayError <= 5) {
    gMinBenchUs = 5000;
  } else if (microsResolution <= 8 && delayError <= 25) {
    gMinBenchUs = 20000;
  } else {
    gMinBenchUs = 50000;
  }
}

// ==================== CPU BENCHMARKS ====================

void benchmarkCPUStress() {
  printHeader("CPU: STRESS TEST with Temperature");

  // Check if temperature sensor is available
  bool hasTempSensor = false;
#if defined(ESP32)
  hasTempSensor = true;
#elif defined(ARDUINO_ARCH_RP2040)
  hasTempSensor = true;
#elif defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA)
  hasTempSensor = false;  // RA4M1 has sensor but not easily accessible
#elif defined(BOARD_TEENSY) && defined(__IMXRT1062__)
  hasTempSensor = true;  // Teensy 4.x has temp sensor
#endif

  if (!hasTempSensor) {
    SERIAL_OUT.println(F_STR("Temperature sensor not available on this board"));
    SERIAL_OUT.println(F_STR("Running stress test without temperature monitoring..."));
    SERIAL_OUT.println();
  }

  // Initial temperature reading
  float startTemp = 0;
#if defined(ESP32)
  startTemp = temperatureRead();
  SERIAL_OUT.print(F_STR("Start Temperature: "));
  SERIAL_OUT.print(startTemp);
  SERIAL_OUT.println(F_STR(" °C"));
#elif defined(ARDUINO_ARCH_RP2040)
  startTemp = analogReadTemp(3.3f);
  SERIAL_OUT.print(F_STR("Start Temperature: "));
  SERIAL_OUT.print(startTemp);
  SERIAL_OUT.println(F_STR(" °C"));
#elif defined(BOARD_TEENSY) && defined(__IMXRT1062__)
  startTemp = tempmonGetTemp();
  SERIAL_OUT.print(F_STR("Start Temperature: "));
  SERIAL_OUT.print(startTemp);
  SERIAL_OUT.println(F_STR(" °C"));
#endif

  SERIAL_OUT.print(F_STR("Running intensive computation for 10 seconds..."));
  SERIAL_OUT.println();

  // CPU stress test - run all cores
  unsigned long stressStart = millis();
  unsigned long lastService = millis();
#if defined(ARDUINO_ARCH_RP2040)
  unsigned long lastIo = millis();
#endif
  unsigned long iterations = 0;
  volatile float result = 1.0f;
  const float twoPi = 6.2831853f;
#if defined(ARDUINO_ARCH_RP2040)
  uint32_t lcg = 0x12345678u;
#endif

  while (millis() - stressStart < 10000) {
    // Mix of integer and float operations
    for (int i = 0; i < 100; i++) {
#if defined(ARDUINO_ARCH_RP2040)
      lcg = lcg * 1664525u + 1013904223u;
      uint32_t mixed = lcg ^ (lcg >> 16);
      float f1 = (mixed & 0xFFFF) * 0.0001f;
      float f2 = (mixed & 0xFF) * 0.00001f;
      result = result * 1.0001f + f1;
      result = result * 0.9999f + f2;
#else
  #if defined(ARDUINO_UNO_Q) || defined(ARDUINO_UNO_Q_MCU)
      // Keep it deterministic and heavy without libm (no sin/cos/fmod/sqrt)
      // Mix float + integer-ish noise
      uint32_t x = (uint32_t)iterations * 1664525u + 1013904223u;
      float f1 = (float)(x & 0xFFFFu) * 0.0001f;
      float f2 = (float)((x >> 16) & 0xFFFFu) * 0.00005f;
      result = result * 1.00013f + f1;
      result = result * 0.99991f + f2;
  #else
      result = result * 1.0001f + sqrtf((float)i);
    #if defined(__ZEPHYR__) || defined(BOARD_STM32U5)
      // Manual fmod implementation for Zephyr (avoids libm linking issues)
      float divisor = twoPi;
      result = result - ((int)(result / divisor)) * divisor;
    #else
      result = fmodf(result, twoPi);
    #endif
      result = sinf(result) + cosf(result);
  #endif
#endif
      iterations++;
    }

    // Periodic yield to prevent watchdog timeout (but don't print)
    if (millis() - lastService >= 5) {
#if defined(ARDUINO_ARCH_RP2040) || defined(ESP32) || defined(ESP8266)
      yield();
#if defined(ESP32) || defined(ESP8266)
      delay(0);
#endif
#endif
      lastService = millis();
    }

#if defined(ARDUINO_ARCH_RP2040)
    if (millis() - lastIo >= 250) {
      SERIAL_OUT.write('.');
      lastIo = millis();
    }
#endif
  }

  unsigned long stressDuration = millis() - stressStart;

  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("Stress test complete: "));
  SERIAL_OUT.print(iterations);
  SERIAL_OUT.print(F_STR(" iterations in "));
  SERIAL_OUT.print(stressDuration);
  SERIAL_OUT.println(F_STR(" ms"));

  SERIAL_OUT.print(F_STR("Performance: "));
  SERIAL_OUT.print((float)iterations / stressDuration);
  SERIAL_OUT.println(F_STR(" iterations/ms"));

  // Final temperature reading
  if (hasTempSensor) {
    delay(100);  // Let sensor stabilize
    float endTemp = 0;
#if defined(ESP32)
    endTemp = temperatureRead();
#elif defined(ARDUINO_ARCH_RP2040)
    endTemp = analogReadTemp(3.3f);
#elif defined(BOARD_TEENSY) && defined(__IMXRT1062__)
    endTemp = tempmonGetTemp();
#endif

    SERIAL_OUT.println();
    SERIAL_OUT.print(F_STR("Final Temperature: "));
    SERIAL_OUT.print(endTemp);
    SERIAL_OUT.println(F_STR(" °C"));

    SERIAL_OUT.print(F_STR("Total Temperature Gain: +"));
    SERIAL_OUT.print(endTemp - startTemp);
    SERIAL_OUT.println(F_STR(" °C"));

    if (endTemp - startTemp > 10) {
      SERIAL_OUT.println(F_STR("⚠️  Significant heating detected - ensure adequate cooling"));
    } else if (endTemp - startTemp > 5) {
      SERIAL_OUT.println(F_STR("ℹ️  Normal temperature increase under load"));
    } else {
      SERIAL_OUT.println(F_STR("✓ Minimal temperature increase - good thermal performance"));
    }
  }
}

void benchmarkIntegerOps() {
  printHeader("CPU: INTEGER OPERATIONS");

  const uint32_t minDurationMs = 5;

  // Addition - use volatile uint64_t to prevent optimization and overflow
  volatile uint64_t acc = 0;
  startBenchmark();
  for (uint32_t i = 0; i < BENCHMARK_ITERATIONS; i++) {
    acc += i;
  }
  unsigned long addTime = endBenchmark();
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println((uint32_t)(acc & 0xFFFFFFFF));

  // Multiplication - use LCG-style updates to prevent optimization
  acc = 1;
  TimedLoopResult mulResult = runTimedLoop(minDurationMs, 100, [&]() {
    for (uint32_t i = 1; i <= 100; i++) {
      acc = (acc * (i | 1)) & 0xFFFFFFFF;  // Ensure odd multiplier, prevent overflow
    }
  });
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println((uint32_t)acc);

  // Division - vary both dividend and divisor
  acc = 0xFFFFFFFFULL;
  TimedLoopResult divResult = runTimedLoop(minDurationMs, 100, [&]() {
    for (uint32_t i = 1; i <= 100; i++) {
      uint32_t divisor = (i % 127) + 2;  // 2-128, avoid div-by-1
      acc = (acc / divisor) + i;         // Accumulate to prevent optimization
    }
  });
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println((uint32_t)acc);

  SERIAL_OUT.print(F_STR("Addition ("));
  SERIAL_OUT.print(BENCHMARK_ITERATIONS);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(addTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print((float)BENCHMARK_ITERATIONS / addTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Multiplication ("));
  SERIAL_OUT.print(mulResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(mulResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(mulResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Division ("));
  SERIAL_OUT.print(divResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(divResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(divResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

#if defined(BOARD_STM32U5) || defined(HAS_DSP)
  // Enhanced tests for Cortex-M33 with DSP extensions
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("--- DSP-Enhanced Integer Tests (Cortex-M33) ---"));

  // 64-bit integer operations (emulated on 32-bit MCU)
  volatile uint64_t acc64 = 0x123456789ABCDEFULL;
  TimedLoopResult mul64Result = runTimedLoop(minDurationMs, 50, [&]() {
    for (uint32_t i = 1; i <= 50; i++) {
      acc64 = (acc64 * (i | 1));  // 64-bit multiply
    }
  });
  SERIAL_OUT.print(F_STR("64-bit Multiply ("));
  SERIAL_OUT.print(mul64Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(mul64Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms"));

  // 64-bit division (expensive on 32-bit MCU)
  acc64 = 0xFFFFFFFFFFFFFFFFULL;
  TimedLoopResult div64Result = runTimedLoop(minDurationMs, 50, [&]() {
    for (uint32_t i = 1; i <= 50; i++) {
      uint64_t divisor = ((uint64_t)i * 123456) + 2;
      acc64 = (acc64 / divisor) + i;
    }
  });
  SERIAL_OUT.print(F_STR("64-bit Divide ("));
  SERIAL_OUT.print(div64Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(div64Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms"));

  // MAC (Multiply-Accumulate) style operations - DSP strength
  volatile int32_t macAcc = 0;
  volatile int32_t macResult[4] = { 0, 0, 0, 0 };
  startBenchmark();
  for (uint32_t i = 0; i < 1000; i++) {
    // Simulate DSP-style MAC operations
    int32_t a = (int32_t)(i & 0xFFFF);
    int32_t b = (int32_t)((i >> 8) & 0xFFFF);
    macAcc += a * b;  // MAC operation
    macResult[i % 4] += macAcc;
  }
  unsigned long macTime = endBenchmark();
  SERIAL_OUT.print(F_STR("MAC Operations (1000 ops): "));
  SERIAL_OUT.print(macTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(1000000.0 / macTime);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
  SERIAL_OUT.print(F_STR("MAC Checksum: "));
  SERIAL_OUT.println(macAcc);

  // Saturating arithmetic (DSP-style)
  volatile int32_t satAcc = 0;
  startBenchmark();
  for (uint32_t i = 0; i < 1000; i++) {
    int32_t val = (int32_t)i * 1000000;
    // Simulate saturating add (clamp to INT32_MAX)
    if (satAcc > INT32_MAX - val) {
      satAcc = INT32_MAX;
    } else {
      satAcc += val;
    }
  }
  unsigned long satTime = endBenchmark();
  SERIAL_OUT.print(F_STR("Saturating Add (1000 ops): "));
  SERIAL_OUT.print(satTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(1000000.0 / satTime);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
#endif
}

void benchmarkFloatOps() {
  printHeader("CPU: FLOATING POINT OPERATIONS");

  const uint32_t minDurationMs = 5;

  // Float addition - volatile prevents optimization
  volatile float fresult = 0.0f;
  startBenchmark();
  for (uint32_t i = 0; i < BENCHMARK_ITERATIONS / 10; i++) {
    fresult += 3.14159f;
  }
  unsigned long faddTime = endBenchmark();
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(fresult);

  // Float multiplication
  fresult = 1.0f;
  startBenchmark();
  for (uint32_t i = 0; i < BENCHMARK_ITERATIONS / 10; i++) {
    fresult *= 1.0001f;
  }
  unsigned long fmulTime = endBenchmark();
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(fresult);

#if !defined(ARDUINO_UNO_Q) && !defined(ARDUINO_UNO_Q_MCU)
  // Sqrt - accumulate to prevent optimization (skipped on Uno Q - no libm)
  fresult = 0.0f;
  TimedLoopResult sqrtResult = runTimedLoop(minDurationMs, 100, [&]() {
    for (uint32_t i = 0; i < 100; i++) {
      fresult += sqrt((float)i);
    }
  });
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(fresult);

  // Sin/Cos - accumulate to prevent optimization (skipped on Uno Q - no libm)
  fresult = 0.0f;
  TimedLoopResult trigResult = runTimedLoop(minDurationMs, 100, [&]() {
    for (uint32_t i = 0; i < 100; i++) {
      fresult += sin((float)i / 100.0f) + cos((float)i / 100.0f);
    }
  });
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(fresult);
#endif

  SERIAL_OUT.print(F_STR("Float Addition ("));
  SERIAL_OUT.print(BENCHMARK_ITERATIONS / 10);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(faddTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print((float)(BENCHMARK_ITERATIONS / 10) / faddTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Float Multiply ("));
  SERIAL_OUT.print(BENCHMARK_ITERATIONS / 10);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(fmulTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print((float)(BENCHMARK_ITERATIONS / 10) / fmulTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

#if !defined(ARDUINO_UNO_Q) && !defined(ARDUINO_UNO_Q_MCU)
  SERIAL_OUT.print(F_STR("Square Root ("));
  SERIAL_OUT.print(sqrtResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(sqrtResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(sqrtResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Sin/Cos ("));
  SERIAL_OUT.print(trigResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(trigResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(trigResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
#else
  SERIAL_OUT.println(F_STR("Sqrt/Sin/Cos: Skipped (Uno Q - no libm)"));
#endif
}

void benchmarkStringOps() {
  printHeader("CPU: STRING OPERATIONS");

  const uint32_t minDurationMs = max(5UL, (gMinBenchUs + 999UL) / 1000UL);

  // String concatenation
  String testString = "";
  TimedLoopResult concatResult = runTimedLoop(minDurationMs, 100, [&]() {
    testString = "";
    for (int i = 0; i < 100; i++) {
      testString += "X";
    }
  });

  // String comparison
  String str1 = "TestString123";
  String str2 = "TestString123";
  volatile bool cmpResult;
  TimedLoopResult cmpResultData = runTimedLoop(minDurationMs, 1000, [&]() {
    for (int i = 0; i < 1000; i++) {
      cmpResult = (str1 == str2);
    }
  });

  // Integer to String
  String numStr;
  TimedLoopResult toStrResult = runTimedLoop(minDurationMs, 1000, [&]() {
    for (int i = 0; i < 1000; i++) {
      numStr = String(i);
    }
  });

  // snprintf into fixed buffer (no heap allocation)
  char fixedBuffer[32];
  volatile int snprintfTotal = 0;
  TimedLoopResult snprintfResult = runTimedLoop(minDurationMs, 1000, [&]() {
    for (int i = 0; i < 1000; i++) {
      snprintfTotal += snprintf(fixedBuffer, sizeof(fixedBuffer), "%d", i);
    }
  });

  SERIAL_OUT.print(F_STR("Arduino String (heap stress) - Concatenation ("));
  SERIAL_OUT.print(concatResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(concatResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(concatResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Arduino String (heap stress) - Comparison ("));
  SERIAL_OUT.print(cmpResultData.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(cmpResultData.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(cmpResultData.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Arduino String (heap stress) - Int to String ("));
  SERIAL_OUT.print(toStrResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(toStrResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(toStrResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("snprintf (fixed buffer, "));
  SERIAL_OUT.print(snprintfResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(snprintfResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(snprintfResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
}

// ==================== MEMORY BENCHMARKS ====================

void benchmarkSRAM() {
  printHeader("MEMORY: SRAM READ/WRITE");

  const uint32_t minDurationMs = 5;

  // Sequential write
  TimedLoopResult writeResult = runTimedLoop(minDurationMs, 256, [&]() {
    for (uint16_t i = 0; i < 256; i++) {
      testBuffer[i] = (uint8_t)i;
    }
  });

  // Sequential read - accumulate to prevent optimization
  volatile uint32_t checksum = 0;
  TimedLoopResult readResult = runTimedLoop(minDurationMs, 256, [&]() {
    for (uint16_t i = 0; i < 256; i++) {
      checksum += testBuffer[i];
    }
  });
  SERIAL_OUT.print(F_STR("Read checksum: "));
  SERIAL_OUT.println((uint32_t)checksum);

  // Random access - accumulate to prevent optimization
  MedianCollector<float, kJitterTrials> randomOpsMedian = {};
  MedianCollector<unsigned long, kJitterTrials> randomElapsedMedian = {};
  MedianCollector<uint32_t, kJitterTrials> randomTotalOpsMedian = {};
  for (uint8_t trial = 0; trial < kJitterTrials; trial++) {
    checksum = 0;
    TimedLoopResult randomResult = runTimedLoop(minDurationMs, 256, [&]() {
      for (uint16_t i = 0; i < 256; i++) {
        uint8_t idx = (i * 7 + 13) % 256;  // Pseudo-random
        checksum += testBuffer[idx];
      }
    });
    randomOpsMedian.add(randomResult.opsPerMs);
    randomElapsedMedian.add(randomResult.elapsedMicros);
    randomTotalOpsMedian.add(randomResult.totalOps);
  }
  float randomOpsPerMs = randomOpsMedian.median();
  unsigned long randomElapsedMicros = randomElapsedMedian.median();
  uint32_t randomTotalOps = randomTotalOpsMedian.median();
  SERIAL_OUT.print(F_STR("Random checksum: "));
  SERIAL_OUT.println((uint32_t)checksum);

  SERIAL_OUT.print(F_STR("Sequential Write ("));
  SERIAL_OUT.print(writeResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(writeResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(writeResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Sequential Read ("));
  SERIAL_OUT.print(readResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(readResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(readResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Random Access ("));
  SERIAL_OUT.print(randomTotalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(randomElapsedMicros);
  SERIAL_OUT.print(F_STR(" μs (median "));
  SERIAL_OUT.print(randomOpsPerMs);
  SERIAL_OUT.print(F_STR(" ops/ms, "));
  SERIAL_OUT.print(kJitterTrials);
  SERIAL_OUT.println(F_STR(" trials)"));

  // Enhanced memory tests - scaled by available RAM
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("--- Memory Bandwidth Tests ---"));

  // Scale buffer size based on available RAM
  size_t bufSize;
#if defined(BOARD_STM32U5)
  bufSize = 8192;  // 8 KB for 786 KB RAM
  SERIAL_OUT.println(F_STR("Using 8 KB buffers (786 KB SRAM)"));
#elif defined(ESP32)
  bufSize = 8192;  // 8 KB
  SERIAL_OUT.println(F_STR("Using 8 KB buffers (large heap)"));
#elif defined(ARDUINO_ARCH_RP2040)
  bufSize = 4096;  // 4 KB for 264 KB RAM
  SERIAL_OUT.println(F_STR("Using 4 KB buffers (264 KB RAM)"));
#elif defined(ARDUINO_SAM_DUE)
  bufSize = 2048;        // 2 KB for 96 KB RAM
  SERIAL_OUT.println(F_STR("Using 2 KB buffers (96 KB RAM)"));
#elif defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA)
  bufSize = 1024;  // 1 KB for 32 KB RAM
  SERIAL_OUT.println(F_STR("Using 1 KB buffers (32 KB RAM)"));
#elif defined(__AVR_ATmega2560__)
  bufSize = 512;  // 512 bytes for 8 KB RAM
  SERIAL_OUT.println(F_STR("Using 512 byte buffers (8 KB RAM)"));
#elif defined(__AVR__)
  bufSize = 256;  // 256 bytes for 2 KB RAM (already tested above)
  SERIAL_OUT.println(F_STR("Using 256 byte buffers (2 KB RAM)"));
#else
  bufSize = 512;  // Conservative default
  SERIAL_OUT.println(F_STR("Using 512 byte buffers"));
#endif

  // Allocate buffers on heap for safety
  uint8_t *largeSrc = (uint8_t *)malloc(bufSize);
  uint8_t *largeDst = (uint8_t *)malloc(bufSize);

  if (largeSrc == NULL || largeDst == NULL) {
    SERIAL_OUT.println(F_STR("ERROR: Could not allocate test buffers"));
    if (largeSrc) free(largeSrc);
    if (largeDst) free(largeDst);
  } else {
    // Initialize source buffer
    for (size_t i = 0; i < bufSize; i++) {
      largeSrc[i] = (uint8_t)(i & 0xFF);
    }

    // memcpy throughput test
    int iterations = (bufSize >= 1024) ? 100 : 200;  // More iterations for small buffers
    startBenchmark();
    for (int iter = 0; iter < iterations; iter++) {
      memcpy(largeDst, largeSrc, bufSize);
    }
    unsigned long memcpyTime = endBenchmark();

    SERIAL_OUT.print(F_STR("memcpy ("));
    SERIAL_OUT.print(bufSize * iterations);
    SERIAL_OUT.print(F_STR(" bytes): "));
    SERIAL_OUT.print(memcpyTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print((bufSize * iterations * 1.0) / memcpyTime);
    SERIAL_OUT.println(F_STR(" MB/s)"));

    // memset throughput test
    startBenchmark();
    for (int iter = 0; iter < iterations; iter++) {
      memset(largeDst, 0xAA, bufSize);
    }
    unsigned long memsetTime = endBenchmark();

    SERIAL_OUT.print(F_STR("memset ("));
    SERIAL_OUT.print(bufSize * iterations);
    SERIAL_OUT.print(F_STR(" bytes): "));
    SERIAL_OUT.print(memsetTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print((bufSize * iterations * 1.0) / memsetTime);
    SERIAL_OUT.println(F_STR(" MB/s)"));

    // Memory bandwidth test - tight loop
    volatile uint32_t *ramPtr = (volatile uint32_t *)largeDst;
    const size_t numWords = bufSize / 4;

    startBenchmark();
    for (int iter = 0; iter < iterations; iter++) {
      for (size_t i = 0; i < numWords; i++) {
        ramPtr[i] = i;  // Sequential write
      }
    }
    unsigned long bandwidthWriteTime = endBenchmark();

    startBenchmark();
    volatile uint32_t sum = 0;
    for (int iter = 0; iter < iterations; iter++) {
      for (size_t i = 0; i < numWords; i++) {
        sum += ramPtr[i];  // Sequential read
      }
    }
    unsigned long bandwidthReadTime = endBenchmark();

    SERIAL_OUT.print(F_STR("RAM Write Bandwidth: "));
    SERIAL_OUT.print((bufSize * iterations * 1.0) / bandwidthWriteTime);
    SERIAL_OUT.println(F_STR(" MB/s"));

    SERIAL_OUT.print(F_STR("RAM Read Bandwidth: "));
    SERIAL_OUT.print((bufSize * iterations * 1.0) / bandwidthReadTime);
    SERIAL_OUT.println(F_STR(" MB/s"));

    // Clean up
    free(largeSrc);
    free(largeDst);
  }
}

#if defined(EEPROM_h) || defined(ESP32) || defined(ESP8266)
void benchmarkEEPROM() {
  printHeader("MEMORY: EEPROM");

#if defined(ESP32) || defined(ESP8266)
  EEPROM.begin(EEPROM_SIZE);
#endif

  int eepromSize = 0;
#if defined(ESP32) || defined(ESP8266)
  eepromSize = EEPROM_SIZE;
#elif defined(EEPROM_h)
  eepromSize = EEPROM.length();
#endif

  if (eepromSize > 0) {
    SERIAL_OUT.print(F_STR("EEPROM Size: "));
    SERIAL_OUT.print(eepromSize);
    SERIAL_OUT.println(F_STR(" bytes"));

    // Write test (smaller sample)
    int testSize = min(64, eepromSize);

#if defined(ESP32) || defined(ESP8266)
    // ESP32/ESP8266: write to RAM buffer
    startBenchmark();
    for (int i = 0; i < testSize; i++) {
      EEPROM.write(i, (uint8_t)i);
    }
    unsigned long ramWriteTime = endBenchmark();

    SERIAL_OUT.print(F_STR("RAM Buffer Write ("));
    SERIAL_OUT.print(testSize);
    SERIAL_OUT.print(F_STR(" bytes): "));
    SERIAL_OUT.print(ramWriteTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print((float)testSize / ramWriteTime * 1000);
    SERIAL_OUT.println(F_STR(" ops/ms)"));

    // Commit multiple times to measure min/median/max (captures erase events)
    SERIAL_OUT.println(F_STR("Flash Commit Test (10 commits):"));
    unsigned long commitTimes[10];

    for (int trial = 0; trial < 10; trial++) {
      // Write alternating pattern to force bit transitions
      for (int i = 0; i < testSize; i++) {
        EEPROM.write(i, (trial % 2) ? 0xFF : 0x00);
      }

      // Time the commit
      startBenchmark();
      EEPROM.commit();
      commitTimes[trial] = endBenchmark();
    }

    // Sort to find min/median/max
    for (int i = 0; i < 9; i++) {
      for (int j = i + 1; j < 10; j++) {
        if (commitTimes[j] < commitTimes[i]) {
          unsigned long temp = commitTimes[i];
          commitTimes[i] = commitTimes[j];
          commitTimes[j] = temp;
        }
      }
    }

    unsigned long minCommit = commitTimes[0];
    unsigned long medianCommit = commitTimes[5];
    unsigned long maxCommit = commitTimes[9];

    SERIAL_OUT.print(F_STR("  Min: "));
    SERIAL_OUT.print(minCommit);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(minCommit / 1000.0);
    SERIAL_OUT.println(F_STR(" ms)"));

    SERIAL_OUT.print(F_STR("  Median: "));
    SERIAL_OUT.print(medianCommit);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(medianCommit / 1000.0);
    SERIAL_OUT.println(F_STR(" ms)"));

    SERIAL_OUT.print(F_STR("  Max: "));
    SERIAL_OUT.print(maxCommit);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(maxCommit / 1000.0);
    SERIAL_OUT.println(F_STR(" ms) ← Includes erase"));
#else
    // AVR/native EEPROM: each write goes to hardware
    startBenchmark();
    for (int i = 0; i < testSize; i++) {
      EEPROM.write(i, (uint8_t)i);
    }
    unsigned long writeTime = endBenchmark();

    SERIAL_OUT.print(F_STR("Hardware Write ("));
    SERIAL_OUT.print(testSize);
    SERIAL_OUT.print(F_STR(" bytes): "));
    SERIAL_OUT.print(writeTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print((float)testSize / writeTime * 1000);
    SERIAL_OUT.println(F_STR(" ops/ms)"));
#endif

    // Read test - measure actual reads with checksum
    delay(10);  // Let EEPROM settle
    volatile uint32_t checksum = 0;
    startBenchmark();
    for (int i = 0; i < testSize; i++) {
      checksum += EEPROM.read(i);
    }
    unsigned long readTime = endBenchmark();

    SERIAL_OUT.print(F_STR("Read ("));
    SERIAL_OUT.print(testSize);
    SERIAL_OUT.print(F_STR(" bytes): "));
    SERIAL_OUT.print(readTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print((float)testSize / readTime * 1000);
    SERIAL_OUT.println(F_STR(" ops/ms)"));
    SERIAL_OUT.print(F_STR("Read checksum: "));
    SERIAL_OUT.println((uint32_t)checksum);
  } else {
    SERIAL_OUT.println(F_STR("EEPROM not available"));
  }

#if defined(ESP32) || defined(ESP8266)
  EEPROM.end();
#endif
}
#endif

#ifdef HAS_PSRAM
void benchmarkPSRAM() {
  printHeader("MEMORY: PSRAM");

  if (psramFound()) {
    SERIAL_OUT.print(F_STR("PSRAM Size: "));
    SERIAL_OUT.print(ESP.getPsramSize() / 1024);
    SERIAL_OUT.println(F_STR(" KB"));

    SERIAL_OUT.print(F_STR("Free PSRAM: "));
    SERIAL_OUT.print(ESP.getFreePsram() / 1024);
    SERIAL_OUT.println(F_STR(" KB"));

    // Allocate test buffer in PSRAM
    uint8_t *psramBuffer = (uint8_t *)ps_malloc(4096);
    if (psramBuffer != NULL) {
      // Write test
      startBenchmark();
      for (int i = 0; i < 4096; i++) {
        psramBuffer[i] = i & 0xFF;
      }
      unsigned long writeTime = endBenchmark();

      // Read test - accumulate to prevent optimization
      volatile uint32_t checksum = 0;
      startBenchmark();
      for (int i = 0; i < 4096; i++) {
        checksum += psramBuffer[i];
      }
      unsigned long readTime = endBenchmark();

      SERIAL_OUT.print(F_STR("Write (4096 bytes): "));
      SERIAL_OUT.print(writeTime);
      SERIAL_OUT.print(F_STR(" μs ("));
      SERIAL_OUT.print(4096.0 / writeTime * 1000);
      SERIAL_OUT.println(F_STR(" ops/ms)"));

      SERIAL_OUT.print(F_STR("Read (4096 bytes): "));
      SERIAL_OUT.print(readTime);
      SERIAL_OUT.print(F_STR(" μs ("));
      SERIAL_OUT.print(4096.0 / readTime * 1000);
      SERIAL_OUT.println(F_STR(" ops/ms)"));

      SERIAL_OUT.print(F_STR("Read checksum: "));
      SERIAL_OUT.println((uint32_t)checksum);

      free(psramBuffer);
    } else {
      SERIAL_OUT.println(F_STR("Failed to allocate PSRAM"));
    }
  } else {
    SERIAL_OUT.println(F_STR("PSRAM not found"));
  }
}
#endif

// ==================== I/O BENCHMARKS ====================

void benchmarkDigitalIO() {
  printHeader("I/O: DIGITAL PIN OPERATIONS");

  const uint32_t minDurationMs = 5;

  // Find a safe digital pin to test
  int testPin;
#if defined(LED_BUILTIN)
  testPin = LED_BUILTIN;
#elif defined(ESP32)
  testPin = 2;  // Most ESP32 boards have LED on GPIO2
#elif defined(ESP8266)
  testPin = 2;
#elif defined(ARDUINO_ARCH_RP2040)
  testPin = 25;
#else
  testPin = 13;  // Classic Arduino default
#endif

  pinMode(testPin, OUTPUT);

  // digitalWrite benchmark
  MedianCollector<float, kJitterTrials> writeOpsMedian = {};
  MedianCollector<unsigned long, kJitterTrials> writeElapsedMedian = {};
  uint32_t dwOpsPerTrial = 0;
  for (uint8_t trial = 0; trial < kJitterTrials; trial++) {
    volatile uint32_t dwOps = 0;
    startBenchmark();
    for (int i = 0; i < 1000; i++) {
      digitalWrite(testPin, HIGH);
      digitalWrite(testPin, LOW);
      dwOps += 2;
    }
    unsigned long writeTime = endBenchmark();
    if (trial == 0) {
      dwOpsPerTrial = dwOps;
    }
    writeElapsedMedian.add(writeTime);
    writeOpsMedian.add(dwOps * 1000.0f / writeTime);
  }
  unsigned long writeTime = writeElapsedMedian.median();
  float writeOpsPerMs = writeOpsMedian.median();

// Direct port manipulation (AVR only)
#ifdef __AVR__
  volatile uint8_t *out = portOutputRegister(digitalPinToPort(testPin));
  uint8_t mask = digitalPinToBitMask(testPin);
  MedianCollector<float, kJitterTrials> portOpsMedian = {};
  MedianCollector<unsigned long, kJitterTrials> portElapsedMedian = {};
  MedianCollector<uint32_t, kJitterTrials> portTotalOpsMedian = {};
  for (uint8_t trial = 0; trial < kJitterTrials; trial++) {
    TimedLoopResult portResult = runTimedLoop(minDurationMs, 2000, [&]() {
      for (int i = 0; i < 1000; i++) {
        *out |= mask;   // Set
        *out &= ~mask;  // Clear
      }
    });
    portOpsMedian.add(portResult.opsPerMs);
    portElapsedMedian.add(portResult.elapsedMicros);
    portTotalOpsMedian.add(portResult.totalOps);
  }
  float portOpsPerMs = portOpsMedian.median();
  unsigned long portElapsedMicros = portElapsedMedian.median();
  uint32_t portTotalOps = portTotalOpsMedian.median();
#endif

// Direct register write (ESP32)
#ifdef ESP32
  MedianCollector<float, kJitterTrials> regOpsMedian = {};
  MedianCollector<unsigned long, kJitterTrials> regElapsedMedian = {};
  MedianCollector<uint32_t, kJitterTrials> regTotalOpsMedian = {};
  for (uint8_t trial = 0; trial < kJitterTrials; trial++) {
    TimedLoopResult regResult = runTimedLoop(minDurationMs, 2000, [&]() {
      for (int i = 0; i < 1000; i++) {
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
        if (testPin < 32) {
          GPIO.out_w1ts = 1u << testPin;
          GPIO.out_w1tc = 1u << testPin;
        } else {
          GPIO.out1_w1ts.data = 1u << (testPin - 32);
          GPIO.out1_w1tc.data = 1u << (testPin - 32);
        }
#else
          digitalWrite(testPin, HIGH);
          digitalWrite(testPin, LOW);
#endif
      }
    });
    regOpsMedian.add(regResult.opsPerMs);
    regElapsedMedian.add(regResult.elapsedMicros);
    regTotalOpsMedian.add(regResult.totalOps);
  }
  float regOpsPerMs = regOpsMedian.median();
  unsigned long regElapsedMicros = regElapsedMedian.median();
  uint32_t regTotalOps = regTotalOpsMedian.median();
#endif

// Direct register write (RP2040)
#ifdef ARDUINO_ARCH_RP2040
  MedianCollector<float, kJitterTrials> regOpsMedian = {};
  MedianCollector<unsigned long, kJitterTrials> regElapsedMedian = {};
  MedianCollector<uint32_t, kJitterTrials> regTotalOpsMedian = {};
  for (uint8_t trial = 0; trial < kJitterTrials; trial++) {
    TimedLoopResult regResult = runTimedLoop(minDurationMs, 2000, [&]() {
      for (int i = 0; i < 1000; i++) {
        sio_hw->gpio_set = 1ul << testPin;  // Set
        sio_hw->gpio_clr = 1ul << testPin;  // Clear
      }
    });
    regOpsMedian.add(regResult.opsPerMs);
    regElapsedMedian.add(regResult.elapsedMicros);
    regTotalOpsMedian.add(regResult.totalOps);
  }
  float regOpsPerMs = regOpsMedian.median();
  unsigned long regElapsedMicros = regElapsedMedian.median();
  uint32_t regTotalOps = regTotalOpsMedian.median();
#endif

  SERIAL_OUT.print(F_STR("digitalWrite() ("));
  SERIAL_OUT.print(dwOpsPerTrial);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(writeTime);
  SERIAL_OUT.print(F_STR(" μs (median "));
  SERIAL_OUT.print(writeOpsPerMs);
  SERIAL_OUT.print(F_STR(" ops/ms, "));
  SERIAL_OUT.print(kJitterTrials);
  SERIAL_OUT.println(F_STR(" trials)"));

#ifdef __AVR__
  SERIAL_OUT.print(F_STR("Direct Port ("));
  SERIAL_OUT.print(portTotalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(portElapsedMicros);
  SERIAL_OUT.print(F_STR(" μs (median "));
  SERIAL_OUT.print(portOpsPerMs);
  SERIAL_OUT.print(F_STR(" ops/ms, "));
  SERIAL_OUT.print(kJitterTrials);
  SERIAL_OUT.println(F_STR(" trials)"));
  SERIAL_OUT.print(F_STR("Speedup: "));
  SERIAL_OUT.print(portOpsPerMs / writeOpsPerMs);
  SERIAL_OUT.println(F_STR("x faster"));
#endif

#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
  SERIAL_OUT.print(F_STR("Direct Register ("));
  SERIAL_OUT.print(regTotalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(regElapsedMicros);
  SERIAL_OUT.print(F_STR(" μs (median "));
  SERIAL_OUT.print(regOpsPerMs);
  SERIAL_OUT.print(F_STR(" ops/ms, "));
  SERIAL_OUT.print(kJitterTrials);
  SERIAL_OUT.println(F_STR(" trials)"));
  SERIAL_OUT.print(F_STR("Speedup: "));
  SERIAL_OUT.print(regOpsPerMs / writeOpsPerMs);
  SERIAL_OUT.println(F_STR("x faster"));
#endif
}

void benchmarkAnalogIO() {
  printHeader("I/O: ANALOG OPERATIONS");

  const uint32_t minDurationMs = max(5UL, (gMinBenchUs + 999UL) / 1000UL);

  // Find analog pins
#if defined(ESP32)
  #if defined(ARDUINO_NANO_ESP32)
    int analogInPin = A0;
  #elif defined(CONFIG_IDF_TARGET_ESP32S3)
    int analogInPin = 1;
  #elif defined(CONFIG_IDF_TARGET_ESP32S2)
    int analogInPin = 1;
  #elif defined(CONFIG_IDF_TARGET_ESP32C3)
    int analogInPin = 0;
  #elif defined(CONFIG_IDF_TARGET_ESP32C6)
    int analogInPin = 0;
  #elif defined(CONFIG_IDF_TARGET_ESP32H2)
    int analogInPin = 0;
  #else
    int analogInPin = 36;
  #endif
  #if defined(CONFIG_IDF_TARGET_ESP32)
    int analogOutPin = 25;   // DAC1
  #else
    int analogOutPin = -1;
  #endif

#elif defined(ESP8266)
  int analogInPin = A0;
  int analogOutPin = -1;

#elif defined(ARDUINO_UNO_Q) || defined(ARDUINO_UNO_Q_MCU)
  // UNO Q does have A0..A5 on the header. Keep output format identical to other boards:
  // single analogRead benchmark on a representative pin.
  int analogInPin = A0;
  int analogOutPin = -1; // no DAC; treat PWM separately elsewhere

  // Make ADC resolution deterministic if the core supports it.
  #if defined(analogReadResolution)
    analogReadResolution(12);
  #endif

#elif defined(__AVR__)
  int analogInPin = A0;
  int analogOutPin = 9;      // PWM

#elif defined(ARDUINO_ARCH_RP2040)
  int analogInPin = 26;      // A0
  int analogOutPin = 15;     // PWM

#else
  int analogInPin = A0;
  int analogOutPin = 3;
#endif

  // ------------------------------
  // analogRead benchmark
  // ------------------------------
  if (analogInPin >= 0) {
    // Some cores behave better with explicit INPUT and a short warm-up.
    pinMode(analogInPin, INPUT);
    for (int i = 0; i < 8; i++) (void)analogRead(analogInPin);

    volatile uint32_t sum = 0;
    bool allZero = true;

    TimedLoopResult readResult = runTimedLoop(minDurationMs, 1, [&]() {
      int value = analogRead(analogInPin);
      sum += (uint32_t)((value < 0) ? 0 : value);
      if (value != 0) allZero = false;
    });

    SERIAL_OUT.print(F_STR("analogRead() ("));
    SERIAL_OUT.print(readResult.totalOps);
    SERIAL_OUT.print(F_STR(" ops): "));
    SERIAL_OUT.print(readResult.elapsedMicros);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(readResult.opsPerMs);
    SERIAL_OUT.println(F_STR(" ops/ms)"));

    SERIAL_OUT.print(F_STR("ADC average: "));
    SERIAL_OUT.println((uint32_t)(sum / readResult.totalOps));

    if (allZero) {
      SERIAL_OUT.println(F_STR("Warning: ADC reads were all zero; ADC pin may be invalid or tied low."));
    }
  }

  // ------------------------------
  // analogWrite/PWM benchmark
  // ------------------------------
  if (analogOutPin >= 0) {
#if defined(ESP32)
    const int pwmFreq = 5000;
    const int pwmResolution = 8;

    startBenchmark();
  #if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3
    (void)ledcAttach(analogOutPin, pwmFreq, pwmResolution);
  #else
    const int pwmChannel = 0;
    ledcSetup(pwmChannel, pwmFreq, pwmResolution);
    ledcAttachPin(analogOutPin, pwmChannel);
  #endif
    unsigned long setupTime = endBenchmark();

    uint32_t pwmValue = 0;
    TimedLoopResult updateResult = runTimedLoop(minDurationMs, 1, [&]() {
  #if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3
      ledcWrite(analogOutPin, pwmValue % 256);
  #else
      ledcWrite(pwmChannel, pwmValue % 256);
  #endif
      pwmValue++;
    });

    SERIAL_OUT.print(F_STR("PWM setup: "));
    SERIAL_OUT.print(setupTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(1000.0 / (double)setupTime);
    SERIAL_OUT.println(F_STR(" ops/ms)"));

    SERIAL_OUT.print(F_STR("PWM duty update ("));
    SERIAL_OUT.print(updateResult.totalOps);
    SERIAL_OUT.print(F_STR(" ops): "));
    SERIAL_OUT.print(updateResult.elapsedMicros);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(updateResult.opsPerMs);
    SERIAL_OUT.println(F_STR(" ops/ms)"));
#else
    pinMode(analogOutPin, OUTPUT);

    uint32_t pwmValue = 0;
    TimedLoopResult writeResult = runTimedLoop(minDurationMs, 1, [&]() {
      analogWrite(analogOutPin, pwmValue % 256);
      pwmValue++;
    });

    SERIAL_OUT.print(F_STR("analogWrite() ("));
    SERIAL_OUT.print(writeResult.totalOps);
    SERIAL_OUT.print(F_STR(" ops): "));
    SERIAL_OUT.print(writeResult.elapsedMicros);
    SERIAL_OUT.print(F_STR(" μs ("));
    SERIAL_OUT.print(writeResult.opsPerMs);
    SERIAL_OUT.println(F_STR(" ops/ms)"));
#endif
  }
}

void benchmarkSerial() {
  printHeader("I/O: SERIAL COMMUNICATION");

  // Calculate expected bytes
  int expectedBytes = 0;
  for (int i = 0; i < 100; i++) {
    expectedBytes += (i < 10) ? 1 : (i < 100) ? 2
                                              : 3;  // digit count
  }

  // Print benchmark - measure enqueue time (CPU overhead)
  MedianCollector<unsigned long, kJitterTrials> enqueueTimeMedian = {};
  MedianCollector<float, kJitterTrials> enqueueRateMedian = {};
  for (uint8_t trial = 0; trial < kJitterTrials; trial++) {
    SERIAL_OUT.flush();
    startBenchmark();
    for (int i = 0; i < 100; i++) {
      SERIAL_OUT.print(i);
    }
    unsigned long enqueueTime = endBenchmark();
    enqueueTimeMedian.add(enqueueTime);
    enqueueRateMedian.add(expectedBytes * 1000.0f / enqueueTime);
  }
  unsigned long enqueueTime = enqueueTimeMedian.median();
  float enqueueRate = enqueueRateMedian.median();

  // Measure what flush() actually does
  unsigned long flushStart = micros();
  SERIAL_OUT.flush();  // Wait for TX buffer to drain to UART FIFO
  unsigned long flushTime = micros() - flushStart;

  // Calculate theoretical wire time (10 bits per byte: start + 8 data + stop)
  // At 115200 baud: each bit = 1/115200 sec = 8.68 μs
  // Each byte = 10 bits = 86.8 μs
  unsigned long theoreticalWireTime = (unsigned long)(expectedBytes * 10 * 1000000.0 / SERIAL_BAUD);

  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("Serial Enqueue ("));
  SERIAL_OUT.print(expectedBytes);
  SERIAL_OUT.print(F_STR(" bytes): "));
  SERIAL_OUT.print(enqueueTime);
  SERIAL_OUT.print(F_STR(" μs (median "));
  SERIAL_OUT.print(enqueueRate);
  SERIAL_OUT.print(F_STR(" bytes/ms CPU, "));
  SERIAL_OUT.print(kJitterTrials);
  SERIAL_OUT.println(F_STR(" trials)"));

  SERIAL_OUT.print(F_STR("flush() time (implementation-dependent): "));
  SERIAL_OUT.print(flushTime);
  SERIAL_OUT.print(F_STR(" μs"));
  SERIAL_OUT.println();

  SERIAL_OUT.print(F_STR("Theoretical Wire Time: "));
  SERIAL_OUT.print(theoreticalWireTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(theoreticalWireTime / 1000.0);
  SERIAL_OUT.println(F_STR(" ms)"));

  SERIAL_OUT.print(F_STR("Wire Throughput: "));
  SERIAL_OUT.print(expectedBytes * 1000.0 / theoreticalWireTime);
  SERIAL_OUT.print(F_STR(" bytes/ms ("));
  SERIAL_OUT.print(SERIAL_BAUD / 10);  // 8N1 = 10 bits per byte
  SERIAL_OUT.println(F_STR(" bytes/sec theoretical)"));

  // Compare enqueue vs wire
  SERIAL_OUT.print(F_STR("Enqueue/Wire Ratio: "));
  SERIAL_OUT.print((float)enqueueTime / theoreticalWireTime * 100);
  SERIAL_OUT.print(F_STR("% ("));
  if (enqueueTime < theoreticalWireTime) {
    SERIAL_OUT.println(F_STR("buffered, won't block)"));
  } else {
    SERIAL_OUT.println(F_STR("CPU-bound)"));
  }
}

// ==================== BOARD-SPECIFIC BENCHMARKS ====================

#ifdef HAS_LED_MATRIX
void benchmarkLEDMatrix() {
  printHeader("DISPLAY: LED Matrix (Uno R4)");

  SERIAL_OUT.println(F_STR("12x8 LED Matrix Available: YES"));
  SERIAL_OUT.println(F_STR("Running LED animation test..."));

  ArduinoLEDMatrix matrix;
  matrix.begin();

  // Test 1: Frame loading speed - all pixels on (with delays for visual effect)
  uint32_t frameOn[3] = {
    0xFFFFFFFF,
    0xFFFFFFFF,
    0xFFFFFFFF
  };
  uint32_t frameOff[3] = {
    0x00000000,
    0x00000000,
    0x00000000
  };

  unsigned long blinkStart = millis();
  for (int i = 0; i < 20; i++) {
    matrix.loadFrame(frameOn);
    delay(50);
    matrix.loadFrame(frameOff);
    delay(50);
  }
  unsigned long blinkTime = millis() - blinkStart;

  // Test 2: Pattern switching speed (no delays)
  uint32_t pattern1[3] = {
    0x55555555,
    0xAAAAAAAA,
    0x55555555
  };
  uint32_t pattern2[3] = {
    0xAAAAAAAA,
    0x55555555,
    0xAAAAAAAA
  };

  startBenchmark();
  for (int i = 0; i < 100; i++) {
    matrix.loadFrame(i % 2 == 0 ? pattern1 : pattern2);
  }
  unsigned long patternTime = endBenchmark();

  // Test 3: Bitmap rendering - must pass array name directly
  uint8_t bitmap[8][12] = {
    { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 },
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
    { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 },
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
    { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 },
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
    { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 },
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }
  };

  startBenchmark();
  for (int i = 0; i < 50; i++) {
    matrix.renderBitmap(bitmap, 8, 12);
  }
  unsigned long bitmapTime = endBenchmark();

  matrix.loadFrame(frameOff);

  SERIAL_OUT.print(F_STR("Blink animation (20 cycles): "));
  SERIAL_OUT.print(blinkTime);
  SERIAL_OUT.println(F_STR(" ms"));

  SERIAL_OUT.print(F_STR("Pattern switching (100 frames): "));
  SERIAL_OUT.print(patternTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(100.0 / patternTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("Bitmap rendering (50 frames): "));
  SERIAL_OUT.print(bitmapTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(50.0 / bitmapTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
}
#endif

#ifdef HAS_WIFI
void benchmarkWiFi() {
  printHeader("WIRELESS: WiFi CAPABILITIES");

  SERIAL_OUT.print(F_STR("WiFi Available: YES"));

// Identify WiFi chip/library
#if defined(ARDUINO_UNOR4_WIFI)
  SERIAL_OUT.println(F_STR(" (ESP32-S3 via WiFiS3)"));
#elif defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_NANO_RP2040_CONNECT)
  SERIAL_OUT.println(F_STR(" (Nina W102 via WiFiNINA)"));
#elif defined(ARDUINO_SAMD_MKR1000)
  SERIAL_OUT.println(F_STR(" (WINC1500 via WiFi101)"));
#elif defined(ESP32) || defined(ESP8266)
  SERIAL_OUT.println(F_STR(" (Native)"));
#elif defined(ARDUINO_RASPBERRY_PI_PICO_W)
  SERIAL_OUT.println(F_STR(" (CYW43439)"));
#else
  SERIAL_OUT.println();
#endif

// MAC Address - different methods for different libraries
#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
  // ESP and Pico W need mode set first
  WiFi.mode(WIFI_STA);
  delay(100);
  SERIAL_OUT.print(F_STR("MAC Address: "));
  SERIAL_OUT.println(WiFi.macAddress());
#elif defined(ARDUINO_UNOR4_WIFI)
  // Uno R4 WiFi - no mode setting needed
  SERIAL_OUT.print(F_STR("MAC Address: "));
  byte mac[6];
  WiFi.macAddress(mac);
  for (int i = 5; i >= 0; i--) {
    if (mac[i] < 16) SERIAL_OUT.print("0");
    SERIAL_OUT.print(mac[i], HEX);
    if (i > 0) SERIAL_OUT.print(":");
  }
  SERIAL_OUT.println();
#else
  // WiFiNINA/WiFi101 - need to get MAC as byte array
  byte mac[6];
  WiFi.macAddress(mac);
  SERIAL_OUT.print(F_STR("MAC Address: "));
  for (int i = 5; i >= 0; i--) {
    if (mac[i] < 16) SERIAL_OUT.print("0");
    SERIAL_OUT.print(mac[i], HEX);
    if (i > 0) SERIAL_OUT.print(":");
  }
  SERIAL_OUT.println();
#endif

  // Scan networks
  SERIAL_OUT.print(F_STR("Scanning networks... "));
  int n = WiFi.scanNetworks();
  SERIAL_OUT.print(n);
  SERIAL_OUT.println(F_STR(" networks found"));

  if (n > 0) {
    SERIAL_OUT.println(F_STR("Strongest 3 networks:"));
    for (int i = 0; i < min(3, n); i++) {
      SERIAL_OUT.print(F_STR("  "));
      SERIAL_OUT.print(i + 1);
      SERIAL_OUT.print(F_STR(": "));
      SERIAL_OUT.print(WiFi.SSID(i));
      SERIAL_OUT.print(F_STR(" ("));
      SERIAL_OUT.print(WiFi.RSSI(i));
      SERIAL_OUT.println(F_STR(" dBm)"));
    }
  }

// Clean up - different methods for different libraries
#if defined(ESP32) || defined(ESP8266)
  WiFi.scanDelete();
  WiFi.mode(WIFI_OFF);
#elif defined(ARDUINO_UNOR4_WIFI)
  // WiFiS3 doesn't have scanDelete or mode
  // Just let it finish naturally
#else
  // WiFiNINA/WiFi101 - end() to clean up
  WiFi.end();
#endif
}
#endif

#ifdef HAS_BLE
void benchmarkBLE() {
  printHeader("WIRELESS: Bluetooth LE");
  SERIAL_OUT.println(F_STR("BLE Available: YES"));

#if defined(ESP32)
  SERIAL_OUT.println(F_STR("Initializing BLE..."));
  BLEDevice::init("");

  BLEScan *pBLEScan = BLEDevice::getScan();
  pBLEScan->setActiveScan(true);
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);

  SERIAL_OUT.print(F_STR("Scanning for BLE devices (5 sec)... "));
  BLEScanResults *foundDevices = pBLEScan->start(5, false);
  int deviceCount = foundDevices->getCount();
  SERIAL_OUT.print(deviceCount);
  SERIAL_OUT.println(F_STR(" devices found"));

  if (deviceCount > 0) {
    SERIAL_OUT.println(F_STR("Discovered devices:"));
    for (int i = 0; i < min(5, deviceCount); i++) {
      BLEAdvertisedDevice device = foundDevices->getDevice(i);
      SERIAL_OUT.print(F_STR("  "));
      SERIAL_OUT.print(i + 1);
      SERIAL_OUT.print(F_STR(": "));
      if (device.haveName()) {
        SERIAL_OUT.print(device.getName().c_str());
      } else {
        SERIAL_OUT.print(F_STR("Unknown"));
      }
      SERIAL_OUT.print(F_STR(" ["));
      SERIAL_OUT.print(device.getAddress().toString().c_str());
      SERIAL_OUT.print(F_STR("] RSSI: "));
      SERIAL_OUT.print(device.getRSSI());
      SERIAL_OUT.println(F_STR(" dBm"));
    }
  }

  pBLEScan->clearResults();
  BLEDevice::deinit(false);

#elif defined(BOARD_NRF52) || defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_SAMD_NANO_33_IOT)
  // For boards using ArduinoBLE library
  SERIAL_OUT.println(F_STR("BLE scan requires ArduinoBLE library"));
  SERIAL_OUT.println(F_STR("Install via Library Manager: 'ArduinoBLE'"));
  SERIAL_OUT.println(F_STR("Scan example:"));
  SERIAL_OUT.println(F_STR("  BLE.begin() → BLE.scan() → check BLE.available()"));
#else
  SERIAL_OUT.println(F_STR("BLE hardware detected but scan not implemented"));
#endif
}
#endif

void benchmarkFlash() {
  printHeader("STORAGE: Flash Information");

#if defined(ESP32)
  SERIAL_OUT.print(F_STR("Flash Size: "));
  SERIAL_OUT.print(ESP.getFlashChipSize() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));

  SERIAL_OUT.print(F_STR("Flash Speed: "));
  SERIAL_OUT.print(ESP.getFlashChipSpeed() / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));

  SERIAL_OUT.print(F_STR("Sketch Size: "));
  SERIAL_OUT.print(ESP.getSketchSize() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));

  SERIAL_OUT.print(F_STR("Free Sketch Space: "));
  SERIAL_OUT.print(ESP.getFreeSketchSpace() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
#elif defined(ESP8266)
  SERIAL_OUT.print(F_STR("Flash Size: "));
  SERIAL_OUT.print(ESP.getFlashChipSize() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));

  SERIAL_OUT.print(F_STR("Flash Speed: "));
  SERIAL_OUT.print(ESP.getFlashChipSpeed() / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));

  SERIAL_OUT.print(F_STR("Sketch Size: "));
  SERIAL_OUT.print(ESP.getSketchSize() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));

  SERIAL_OUT.print(F_STR("Free Sketch Space: "));
  SERIAL_OUT.print(ESP.getFreeSketchSpace() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
#else
  SERIAL_OUT.println(F_STR("Flash info not available on this platform"));
#endif
}

// ==================== ADVANCED MATH BENCHMARKS ====================

void benchmarkAdvancedMath() {
  printHeader("ADVANCED MATH: Transcendental Functions");

#if defined(ARDUINO_UNO_Q) || defined(ARDUINO_UNO_Q_MCU)
  SERIAL_OUT.println(F_STR("Uno Q: libm not available (sin/cos/log/exp/pow/atan2)"));
  SERIAL_OUT.println(F_STR("Skipping advanced math benchmark"));
  return;
#endif

  volatile float checksum = 0;

  // atan2 test
  startBenchmark();
  for (int i = 0; i < 100; i++) {
    checksum += atan2((float)i, (float)(100 - i));
  }
  unsigned long atan2Time = endBenchmark();

  // log test
  startBenchmark();
  for (int i = 1; i <= 100; i++) {
    checksum += log((float)i);
  }
  unsigned long logTime = endBenchmark();

  // exp test
  startBenchmark();
  for (int i = 0; i < 100; i++) {
    checksum += exp((float)i / 10.0f);
  }
  unsigned long expTime = endBenchmark();

  // pow test
  startBenchmark();
  for (int i = 1; i <= 100; i++) {
    checksum += pow((float)i, 1.5f);
  }
  unsigned long powTime = endBenchmark();

  // fmod test
  startBenchmark();
  for (int i = 0; i < 1000; i++) {
#if defined(__ZEPHYR__) || defined(BOARD_STM32U5)
    // Manual fmod for Zephyr (avoids libm linking issues)
    float val = (float)i;
    float divisor = 7.3f;
    checksum += val - ((int)(val / divisor)) * divisor;
#else
    checksum += fmod((float)i, 7.3f);
#endif
  }
  unsigned long fmodTime = endBenchmark();

  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(checksum);

  SERIAL_OUT.print(F_STR("atan2() (100 ops): "));
  SERIAL_OUT.print(atan2Time);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(100.0 / atan2Time * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("log() (100 ops): "));
  SERIAL_OUT.print(logTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(100.0 / logTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("exp() (100 ops): "));
  SERIAL_OUT.print(expTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(100.0 / expTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("pow() (100 ops): "));
  SERIAL_OUT.print(powTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(100.0 / powTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("fmod() (1000 ops): "));
  SERIAL_OUT.print(fmodTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(1000.0 / fmodTime * 1000);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
}

#if defined(ARDUINO_ARCH_RP2040)
void benchmarkSHA1() {
  printHeader("CRYPTO: SHA1");

  SERIAL_OUT.println(F_STR("Example digests:"));
  SERIAL_OUT.print(F_STR("SHA1:"));
  SERIAL_OUT.println(sha1("abc"));

  uint8_t hash[20];
  sha1("test", &hash[0]);
  SERIAL_OUT.print(F_STR("SHA1:"));
  for (uint16_t i = 0; i < 20; i++) {
    SERIAL_OUT.printf("%02x", hash[i]);
  }
  SERIAL_OUT.println();

  const uint32_t minDurationMs = max(5UL, (gMinBenchUs + 999UL) / 1000UL);
  volatile uint32_t checksum = 0;

  TimedLoopResult stringResult = runTimedLoop(minDurationMs, 10, [&]() {
    for (uint8_t i = 0; i < 10; i++) {
      String digest = sha1("abc");
      checksum += digest.length();
    }
  });

  TimedLoopResult bufferResult = runTimedLoop(minDurationMs, 10, [&]() {
    for (uint8_t i = 0; i < 10; i++) {
      sha1("test", &hash[0]);
      checksum += hash[0];
    }
  });

  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(checksum);

  SERIAL_OUT.print(F_STR("SHA1 String ("));
  SERIAL_OUT.print(stringResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(stringResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(stringResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("SHA1 Buffer ("));
  SERIAL_OUT.print(bufferResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(bufferResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(bufferResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
}
#endif

#if defined(ESP32)
static inline int benchmarkMd5(const unsigned char *input, size_t size, unsigned char *output) {
#if defined(MBEDTLS_VERSION_MAJOR) && MBEDTLS_VERSION_MAJOR >= 3
  return mbedtls_md5(input, size, output);
#else
  return mbedtls_md5_ret(input, size, output);
#endif
}

static inline int benchmarkSha1(const unsigned char *input, size_t size, unsigned char *output) {
#if defined(MBEDTLS_VERSION_MAJOR) && MBEDTLS_VERSION_MAJOR >= 3
  return mbedtls_sha1(input, size, output);
#else
  return mbedtls_sha1_ret(input, size, output);
#endif
}

static inline int benchmarkSha256(const unsigned char *input, size_t size, unsigned char *output) {
#if defined(MBEDTLS_VERSION_MAJOR) && MBEDTLS_VERSION_MAJOR >= 3
  return mbedtls_sha256(input, size, output, 0);
#else
  return mbedtls_sha256_ret(input, size, output, 0);
#endif
}

static inline int benchmarkSha512(const unsigned char *input, size_t size, unsigned char *output) {
#if defined(MBEDTLS_VERSION_MAJOR) && MBEDTLS_VERSION_MAJOR >= 3
  return mbedtls_sha512(input, size, output, 0);
#else
  return mbedtls_sha512_ret(input, size, output, 0);
#endif
}

void benchmarkESP32Crypto() {
  printHeader("CRYPTO: Hashing (ESP32)");

  constexpr uint8_t inputSize = 128;
  uint8_t input[inputSize];
  for (uint8_t i = 0; i < inputSize; i++) {
    input[i] = (uint8_t)(i * 3 + 7);
  }

  uint8_t digest[64];
  char hexDigest[129];
  char hexInput[(inputSize * 2) + 1];
  volatile uint32_t checksum = 0;
  uint32_t lastProgressMs = millis();
  const uint32_t maxCryptoMs = 15000;
  const uint32_t cryptoStartMs = lastProgressMs;
  bool cryptoTimedOut = false;
  bool cryptoAbortPrinted = false;
  auto benchYield = []() {
#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)
    yield();
#endif
  };
  auto checkCryptoTimeout = [&]() -> bool {
    if (!cryptoTimedOut && (millis() - cryptoStartMs > maxCryptoMs)) {
      SERIAL_OUT.println(F_STR("Warning: crypto benchmark timed out."));
      cryptoTimedOut = true;
    }
    return cryptoTimedOut;
  };
  auto abortCryptoIfTimedOut = [&]() -> bool {
    if (cryptoTimedOut && !cryptoAbortPrinted) {
      SERIAL_OUT.println(F_STR("Crypto benchmark aborted due to timeout."));
      cryptoAbortPrinted = true;
    }
    return cryptoTimedOut;
  };

  auto toHex = [&](const uint8_t *data, size_t len, char *out, size_t outCapacity) -> bool {
    const size_t requiredSize = (len * 2) + 1;
    if (outCapacity < requiredSize) {
      return false;
    }
#if defined(ESP32)
    size_t written = HEXBuilder::bytes2hex(out, outCapacity, data, len);
    return written >= requiredSize;
#else
    static const char kHexChars[] = "0123456789abcdef";
    for (size_t i = 0; i < len; ++i) {
      const uint8_t byteValue = data[i];
      out[i * 2] = kHexChars[(byteValue >> 4) & 0x0F];
      out[(i * 2) + 1] = kHexChars[byteValue & 0x0F];
    }
    out[len * 2] = '\0';
    return true;
#endif
  };

  const uint32_t minDurationMs = max(5UL, (gMinBenchUs + 999UL) / 1000UL);

  SERIAL_OUT.println(F_STR("Example digests:"));
  benchmarkMd5(input, inputSize, digest);
  if (!toHex(digest, 16, hexDigest, sizeof(hexDigest))) {
    SERIAL_OUT.println(F_STR("MD5 hex buffer too small."));
    return;
  }
  SERIAL_OUT.print(F_STR("MD5: "));
  SERIAL_OUT.println(hexDigest);

  benchmarkSha1(input, inputSize, digest);
  if (!toHex(digest, 20, hexDigest, sizeof(hexDigest))) {
    SERIAL_OUT.println(F_STR("SHA1 hex buffer too small."));
    return;
  }
  SERIAL_OUT.print(F_STR("SHA1: "));
  SERIAL_OUT.println(hexDigest);

  benchmarkSha256(input, inputSize, digest);
  if (!toHex(digest, 32, hexDigest, sizeof(hexDigest))) {
    SERIAL_OUT.println(F_STR("SHA256 hex buffer too small."));
    return;
  }
  SERIAL_OUT.print(F_STR("SHA256: "));
  SERIAL_OUT.println(hexDigest);

  benchmarkSha512(input, inputSize, digest);
  if (!toHex(digest, 64, hexDigest, sizeof(hexDigest))) {
    SERIAL_OUT.println(F_STR("SHA512 hex buffer too small."));
    return;
  }
  SERIAL_OUT.print(F_STR("SHA512: "));
  SERIAL_OUT.println(hexDigest);

#if defined(MBEDTLS_SHA3_C)
  {
    mbedtls_sha3_context sha3;
    mbedtls_sha3_init(&sha3);
    mbedtls_sha3_starts(&sha3, 256);
    mbedtls_sha3_update(&sha3, input, inputSize);
    mbedtls_sha3_finish(&sha3, digest);
    mbedtls_sha3_free(&sha3);
    if (!toHex(digest, 32, hexDigest, sizeof(hexDigest))) {
      SERIAL_OUT.println(F_STR("SHA3-256 hex buffer too small."));
      return;
    }
    SERIAL_OUT.print(F_STR("SHA3-256: "));
    SERIAL_OUT.println(hexDigest);
  }
#else
  SERIAL_OUT.println(F_STR("SHA3-256: not available in this build"));
#endif

  SERIAL_OUT.println(F_STR("...running HEX encode"));
  TimedLoopResult hexResult = runTimedLoop(minDurationMs, 20, [&]() -> bool {
    for (uint8_t i = 0; i < 20; i++) {
      if (checkCryptoTimeout()) {
        return false;
      }
      if (!toHex(input, inputSize, hexInput, sizeof(hexInput))) {
        SERIAL_OUT.println(F_STR("HEX encode buffer too small."));
        return false;
      }
      checksum += hexInput[0];
      if ((i % 5) == 0) {
        benchYield();
      }
    }
    return true;
  });
  if (abortCryptoIfTimedOut()) {
    return;
  }
  SERIAL_OUT.println(F_STR("...running MD5"));
  TimedLoopResult md5Result = runTimedLoop(minDurationMs, 10, [&]() -> bool {
    for (uint8_t i = 0; i < 10; i++) {
      if (checkCryptoTimeout()) {
        return false;
      }
      benchmarkMd5(input, inputSize, digest);
      checksum += digest[0];
      if ((i % 3) == 0) {
        benchYield();
      }
    }
    return true;
  });
  if (abortCryptoIfTimedOut()) {
    return;
  }
  SERIAL_OUT.println(F_STR("...running SHA1"));
  TimedLoopResult sha1Result = runTimedLoop(minDurationMs, 10, [&]() -> bool {
    for (uint8_t i = 0; i < 10; i++) {
      if (checkCryptoTimeout()) {
        return false;
      }
      benchmarkSha1(input, inputSize, digest);
      checksum += digest[0];
      if ((i % 3) == 0) {
        benchYield();
      }
    }
    return true;
  });
  if (abortCryptoIfTimedOut()) {
    return;
  }
  SERIAL_OUT.println(F_STR("...running SHA256"));
  TimedLoopResult sha256Result = runTimedLoop(minDurationMs, 10, [&]() -> bool {
    for (uint8_t i = 0; i < 10; i++) {
      if (checkCryptoTimeout()) {
        return false;
      }
      benchmarkSha256(input, inputSize, digest);
      checksum += digest[0];
      if ((i % 3) == 0) {
        benchYield();
      }
    }
    return true;
  });
  if (abortCryptoIfTimedOut()) {
    return;
  }
  SERIAL_OUT.println(F_STR("...running SHA512"));
  TimedLoopResult sha512Result = runTimedLoop(minDurationMs, 10, [&]() -> bool {
    for (uint8_t i = 0; i < 10; i++) {
      if (checkCryptoTimeout()) {
        return false;
      }
      benchmarkSha512(input, inputSize, digest);
      checksum += digest[0];
      if ((i % 2) == 0) {
        benchYield();
      }
    }
    return true;
  });
  if (abortCryptoIfTimedOut()) {
    return;
  }
#if defined(MBEDTLS_SHA3_C)
  SERIAL_OUT.println(F_STR("...running SHA3-256"));
  TimedLoopResult sha3Result = runTimedLoop(minDurationMs, 5, [&]() -> bool {
    for (uint8_t i = 0; i < 5; i++) {
      if (checkCryptoTimeout()) {
        return false;
      }
      mbedtls_sha3_context sha3;
      mbedtls_sha3_init(&sha3);
      mbedtls_sha3_starts(&sha3, 256);
      mbedtls_sha3_update(&sha3, input, inputSize);
      mbedtls_sha3_finish(&sha3, digest);
      mbedtls_sha3_free(&sha3);
      checksum += digest[0];
      benchYield();
    }
    return true;
  });
  if (abortCryptoIfTimedOut()) {
    return;
  }
#endif

  const uint8_t saltSize = 16;
  uint8_t salt[saltSize];
  for (uint8_t i = 0; i < saltSize; i++) {
    salt[i] = (uint8_t)(0xA5 ^ i);
  }
  const char *password = "esp32-benchmark";
  const uint32_t pbkdf2Iterations = 500;

  SERIAL_OUT.println(F_STR("...running PBKDF2-HMAC-SHA256"));
  TimedLoopResult pbkdf2Result = runTimedLoop(minDurationMs, 1, [&]() -> bool {
    if (checkCryptoTimeout()) {
      return false;
    }
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
    if (mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA256,
                                      reinterpret_cast<const unsigned char *>(password),
                                      strlen(password),
                                      salt,
                                      saltSize,
                                      pbkdf2Iterations,
                                      32,
                                      digest)
        == 0) {
      checksum += digest[0];
    }
#else
      mbedtls_md_context_t ctx;
      mbedtls_md_init(&ctx);
      const mbedtls_md_info_t *info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
      if (info != nullptr && mbedtls_md_setup(&ctx, info, 1) == 0) {
        if (mbedtls_pkcs5_pbkdf2_hmac(&ctx,
                                      reinterpret_cast<const unsigned char *>(password),
                                      strlen(password),
                                      salt,
                                      saltSize,
                                      pbkdf2Iterations,
                                      32,
                                      digest)
            == 0) {
          checksum += digest[0];
        }
      }
      mbedtls_md_free(&ctx);
#endif
    if (millis() - lastProgressMs > 1000) {
      SERIAL_OUT.print('.');
      lastProgressMs = millis();
    }
    benchYield();
    return !checkCryptoTimeout();
  });
  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(checksum);

  SERIAL_OUT.print(F_STR("HEX encode ("));
  SERIAL_OUT.print(hexResult.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(hexResult.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(hexResult.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("MD5 ("));
  SERIAL_OUT.print(md5Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(md5Result.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(md5Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("SHA1 ("));
  SERIAL_OUT.print(sha1Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(sha1Result.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(sha1Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("SHA256 ("));
  SERIAL_OUT.print(sha256Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(sha256Result.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(sha256Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

  SERIAL_OUT.print(F_STR("SHA512 ("));
  SERIAL_OUT.print(sha512Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(sha512Result.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(sha512Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));

#if defined(MBEDTLS_SHA3_C)
  SERIAL_OUT.print(F_STR("SHA3-256 ("));
  SERIAL_OUT.print(sha3Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(sha3Result.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(sha3Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
#endif

  SERIAL_OUT.print(F_STR("PBKDF2-HMAC-SHA256 ("));
  SERIAL_OUT.print(pbkdf2Result.totalOps);
  SERIAL_OUT.print(F_STR(" ops): "));
  SERIAL_OUT.print(pbkdf2Result.elapsedMicros);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(pbkdf2Result.opsPerMs);
  SERIAL_OUT.println(F_STR(" ops/ms)"));
  SERIAL_OUT.print(F_STR("  Iterations per op: "));
  SERIAL_OUT.println(pbkdf2Iterations);
}
#endif

// ==================== TIMING PRECISION BENCHMARKS ====================

void benchmarkTimingPrecision() {
  printHeader("TIMING: millis() and micros() Precision");

  // Test millis() accuracy
  unsigned long startMillis = millis();
  delay(1000);
  unsigned long endMillis = millis();
  long millisError = abs((long)(endMillis - startMillis) - 1000);

  SERIAL_OUT.print(F_STR("millis() 1-second test: "));
  SERIAL_OUT.print(endMillis - startMillis);
  SERIAL_OUT.print(F_STR(" ms (±"));
  SERIAL_OUT.print(millisError);
  SERIAL_OUT.println(F_STR(" ms error)"));

  // Test micros() resolution - wait for value to change to measure granularity
  unsigned long micro1 = micros();
  unsigned long micro2 = micro1;
  uint16_t iterations = 0;
  const uint16_t maxIterations = 10000;

  // Wait for micros() to increment
  while (micro2 == micro1 && iterations < maxIterations) {
    micro2 = micros();
    iterations++;
  }

  unsigned long microResolution = micro2 - micro1;

  SERIAL_OUT.print(F_STR("micros() resolution: "));
  if (iterations >= maxIterations) {
    SERIAL_OUT.println(F_STR("TIMEOUT (timer may not be running)"));
  } else {
    SERIAL_OUT.print(microResolution);
    SERIAL_OUT.print(F_STR(" μs (detected after "));
    SERIAL_OUT.print(iterations);
    SERIAL_OUT.println(F_STR(" reads)"));
  }

  // Additional resolution test - measure minimum measurable difference
  unsigned long minDiff = 0xFFFFFFFF;
  for (int i = 0; i < 100; i++) {
    unsigned long t1 = micros();
    unsigned long t2 = micros();
    while (t2 == t1) {
      t2 = micros();
    }
    unsigned long diff = t2 - t1;
    if (diff > 0 && diff < minDiff) {
      minDiff = diff;
    }
  }

  SERIAL_OUT.print(F_STR("Minimum step size (100 samples): "));
  SERIAL_OUT.print(minDiff);
  SERIAL_OUT.println(F_STR(" μs"));

#if defined(__AVR__)
  SERIAL_OUT.println(F_STR("Note: AVR micros() typically advances in 4 μs steps"));
#endif

  // Test micros() consistency over short period
  unsigned long startMicros = micros();
  delayMicroseconds(1000);
  unsigned long endMicros = micros();
  long microsError = abs((long)(endMicros - startMicros) - 1000);

  SERIAL_OUT.print(F_STR("micros() 1ms test: "));
  SERIAL_OUT.print(endMicros - startMicros);
  SERIAL_OUT.print(F_STR(" μs (±"));
  SERIAL_OUT.print(microsError);
  SERIAL_OUT.println(F_STR(" μs error)"));

// ESP32: CPU cycle counter cross-check
#ifdef ESP32
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("ESP32 CPU Cycle Counter:"));

  // Get CPU frequency
  uint32_t cpuFreqMHz = ESP.getCpuFreqMHz();
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(cpuFreqMHz);
  SERIAL_OUT.println(F_STR(" MHz"));

  // Test cycle counter vs micros()
  uint32_t cycleStart = ESP.getCycleCount();
  unsigned long microsStart = micros();

  // Busy wait for ~1000 us
  delayMicroseconds(1000);

  uint32_t cycleEnd = ESP.getCycleCount();
  unsigned long microsEnd = micros();

  uint32_t cycleDelta = cycleEnd - cycleStart;
  unsigned long microsDelta = microsEnd - microsStart;

  SERIAL_OUT.print(F_STR("Cycles elapsed: "));
  SERIAL_OUT.println(cycleDelta);
  SERIAL_OUT.print(F_STR("micros() elapsed: "));
  SERIAL_OUT.print(microsDelta);
  SERIAL_OUT.println(F_STR(" μs"));

  // Calculate expected cycles
  float expectedCycles = microsDelta * cpuFreqMHz;
  SERIAL_OUT.print(F_STR("Expected cycles: "));
  SERIAL_OUT.println((uint32_t)expectedCycles);

  // Calculate jitter
  float jitterPercent = abs((float)cycleDelta - expectedCycles) / expectedCycles * 100.0f;
  SERIAL_OUT.print(F_STR("Timing jitter: "));
  SERIAL_OUT.print(jitterPercent, 2);
  SERIAL_OUT.println(F_STR("%"));
#endif

  // Clock frequency estimate
  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("Clock accuracy: "));
  float accuracy = 100.0f - ((float)millisError / 10.0f);
  SERIAL_OUT.print(accuracy);
  SERIAL_OUT.println(F_STR("%"));
}

// ==================== STACK DEPTH BENCHMARK ====================

volatile int recursionCounter = 0;

int testRecursion(int depth) {
  recursionCounter++;
  volatile char buffer[32];  // Consume stack space
  buffer[0] = (char)depth;

  if (depth > 0) {
    return testRecursion(depth - 1) + 1;
  }
  return 1;
}

void benchmarkStackDepth() {
  printHeader("MEMORY: Stack Depth Test");

  // Scale test depth based on available RAM to avoid overflow
  int testDepth;

#if defined(BOARD_STM32U5)
  testDepth = 500;  // 786 KB RAM - can go deep
  SERIAL_OUT.println(F_STR("Testing deep recursion (786 KB SRAM)"));
#elif defined(ESP32)
  testDepth = 500;  // ESP32 has plenty of RAM
  SERIAL_OUT.println(F_STR("Testing deep recursion (large heap)"));
#elif defined(ARDUINO_ARCH_RP2040)
  testDepth = 300;  // 264 KB RAM
  SERIAL_OUT.println(F_STR("Testing deep recursion (264 KB RAM)"));
#elif defined(ARDUINO_SAM_DUE)
  testDepth = 200;        // 96 KB RAM
  SERIAL_OUT.println(F_STR("Testing moderate recursion (96 KB RAM)"));
#elif defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA)
  testDepth = 100;  // 32 KB RAM - be conservative
  SERIAL_OUT.println(F_STR("Testing moderate recursion (32 KB RAM)"));
#elif defined(BOARD_SAMD) || defined(BOARD_NRF52)
  testDepth = 100;  // Typically 32-256 KB
  SERIAL_OUT.println(F_STR("Testing moderate recursion (ARM)"));
#elif defined(__AVR_ATmega2560__)
  testDepth = 40;  // 8 KB RAM - deeper than Uno
  SERIAL_OUT.println(F_STR("Testing shallow recursion (8 KB RAM)"));
#elif defined(__AVR__)
  testDepth = 20;  // 2-2.5 KB RAM - very conservative
  SERIAL_OUT.println(F_STR("Testing shallow recursion (2 KB RAM)"));
#else
  testDepth = 50;  // Conservative default
  SERIAL_OUT.println(F_STR("Testing moderate recursion (unknown RAM)"));
#endif

  // Test safe recursion depth
  recursionCounter = 0;
  int result = testRecursion(testDepth);
  (void)result;

  SERIAL_OUT.print(F_STR("Recursion test ("));
  SERIAL_OUT.print(testDepth);
  SERIAL_OUT.print(F_STR(" deep): "));
  if (recursionCounter == testDepth + 1) {
    SERIAL_OUT.println(F_STR("PASS"));
    SERIAL_OUT.print(F_STR("Successfully executed "));
    SERIAL_OUT.print(testDepth);
    SERIAL_OUT.println(F_STR(" nested function calls"));
  } else {
    SERIAL_OUT.print(F_STR("FAIL - reached depth "));
    SERIAL_OUT.println(recursionCounter);
  }

  // Estimate stack usage per call (very rough)
  // Each recursive call typically uses 20-50 bytes on ARM, more on some platforms
#if defined(BOARD_STM32U5) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
  SERIAL_OUT.print(F_STR("Estimated stack usage: ~"));
  SERIAL_OUT.print(testDepth * 40);  // Rough estimate: 40 bytes/call
  SERIAL_OUT.println(F_STR(" bytes"));
#elif defined(__AVR__)
  SERIAL_OUT.print(F_STR("Estimated stack usage: ~"));
  SERIAL_OUT.print(testDepth * 30);  // AVR: ~30 bytes/call typical
  SERIAL_OUT.println(F_STR(" bytes"));
#endif

  SERIAL_OUT.println(F_STR("Note: Actual stack usage varies by compiler and optimization."));
}

// ==================== MULTI-CORE BENCHMARKS ====================

#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)

#ifdef ESP32
TaskHandle_t Task1;
TaskHandle_t Task2;
volatile unsigned long core0Count = 0;
volatile unsigned long core1Count = 0;
volatile bool testRunning = false;

void core0Task(void *parameter) {
  volatile uint32_t accumulator = 0;
  while (true) {
    if (testRunning) {
      core0Count++;
      accumulator += 3;
      accumulator ^= (accumulator << 1);
    }
  }
}

void core1Task(void *parameter) {
  volatile uint32_t accumulator = 0;
  while (true) {
    if (testRunning) {
      core1Count++;
      accumulator += 3;
      accumulator ^= (accumulator << 1);
    }
  }
}
#endif

#if defined(ARDUINO_ARCH_RP2040) && defined(HAS_PICO_MULTICORE)
volatile unsigned long rp2040Core0Count = 0;
volatile unsigned long rp2040Core1Count = 0;
volatile bool rp2040TestRunning = false;
volatile bool rp2040Core1Ready = false;

void rp2040Core1Task() {
  volatile uint32_t accumulator = 0;
  rp2040Core1Ready = true;
  while (true) {
    if (rp2040TestRunning) {
      rp2040Core1Count++;
      accumulator += 3;
      accumulator ^= (accumulator << 1);
    }
  }
}
#endif

void benchmarkMultiCore() {
  printHeader("MULTI-CORE: Parallel Performance");

#ifdef ESP32
  SERIAL_OUT.println(F_STR("ESP32 Dual-Core Test"));

  // Create tasks on both cores
  xTaskCreatePinnedToCore(
    core0Task,
    "Task0",
    10000,
    NULL,
    1,
    &Task1,
    0);

  xTaskCreatePinnedToCore(
    core1Task,
    "Task1",
    10000,
    NULL,
    1,
    &Task2,
    1);

  delay(100);  // Let tasks start

  // Run test
  core0Count = 0;
  core1Count = 0;
  testRunning = true;
  delay(1000);
  testRunning = false;

  SERIAL_OUT.print(F_STR("Core 0 iterations: "));
  SERIAL_OUT.println(core0Count);
  SERIAL_OUT.print(F_STR("Core 1 iterations: "));
  SERIAL_OUT.println(core1Count);
  SERIAL_OUT.print(F_STR("Total iterations: "));
  SERIAL_OUT.println(core0Count + core1Count);
  SERIAL_OUT.print(F_STR("Core balance: "));
  float balance = (float)min(core0Count, core1Count) / (float)max(core0Count, core1Count) * 100.0f;
  SERIAL_OUT.print(balance);
  SERIAL_OUT.println(F_STR("%"));

  // Clean up
  vTaskDelete(Task1);
  vTaskDelete(Task2);

#elif defined(ARDUINO_ARCH_RP2040)
  SERIAL_OUT.println(F_STR("RP2040 Dual-Core Test"));
#if defined(HAS_PICO_MULTICORE)
  SERIAL_OUT.println(F_STR("Running dual-core workload for 1 second..."));

  rp2040Core0Count = 0;
  rp2040Core1Count = 0;
  rp2040TestRunning = false;
  rp2040Core1Ready = false;

  multicore_reset_core1();
  multicore_launch_core1(rp2040Core1Task);

  unsigned long readyStart = millis();
  while (!rp2040Core1Ready && millis() - readyStart < 200) {
    delay(1);
  }

  rp2040TestRunning = true;
  unsigned long start = millis();
  volatile uint32_t accumulator = 0;
  while (millis() - start < 1000) {
    rp2040Core0Count++;
    accumulator += 3;
    accumulator ^= (accumulator << 1);
  }
  rp2040TestRunning = false;

  unsigned long total = rp2040Core0Count + rp2040Core1Count;
  unsigned long dominant = max(rp2040Core0Count, rp2040Core1Count);
  float scaling = dominant > 0 ? (float)total / (float)dominant : 0.0f;

  SERIAL_OUT.print(F_STR("Core 0 iterations: "));
  SERIAL_OUT.println(rp2040Core0Count);
  SERIAL_OUT.print(F_STR("Core 1 iterations: "));
  SERIAL_OUT.println(rp2040Core1Count);
  SERIAL_OUT.print(F_STR("Total iterations: "));
  SERIAL_OUT.println(total);
  SERIAL_OUT.print(F_STR("Scaling efficiency: "));
  SERIAL_OUT.print(scaling, 2);
  SERIAL_OUT.println(F_STR("x"));
#else
  SERIAL_OUT.println(F_STR("Single core performance:"));

  volatile unsigned long count = 0;
  unsigned long start = millis();
  while (millis() - start < 1000) {
    count++;
  }

  SERIAL_OUT.print(F_STR("Iterations in 1 second: "));
  SERIAL_OUT.println(count);
  SERIAL_OUT.println(F_STR("Note: Full dual-core requires multicore library"));
#endif
#endif
}
#endif

// ==================== SERIAL BAUD RATE BENCHMARK ====================
// NOTE: Baud rate sweeping causes boards to disconnect and require replug
// Disabled for stability

/*
void benchmarkSerialBaudRates() {
  printHeader("SERIAL: Baud Rate Sweep");
  
  const long baudRates[] = {9600, 57600, 115200, 230400, 460800, 921600};
  const int numRates = 6;
  
  SERIAL_OUT.println(F_STR("Testing throughput at different baud rates..."));
  delay(100);
  
  for (int i = 0; i < numRates; i++) {
    SERIAL_OUT.end();
    delay(100);
    SERIAL_OUT.begin(baudRates[i]);
    delay(100);
    
    // Test throughput at this baud rate
    const char testData[] = "0123456789";
    startBenchmark();
    for (int j = 0; j < 19; j++) {
      SERIAL_OUT.print(testData);
    }
    SERIAL_OUT.flush();
    unsigned long baudTime = endBenchmark();
    
    SERIAL_OUT.print(F_STR("Baud "));
    SERIAL_OUT.print(baudRates[i]);
    SERIAL_OUT.print(F_STR(": "));
    SERIAL_OUT.print(baudTime);
    SERIAL_OUT.print(F_STR(" μs ("));
    float bytesPerSec = 190000000.0f / baudTime;
    SERIAL_OUT.print(bytesPerSec, 0);
    SERIAL_OUT.println(F_STR(" bytes/sec)"));
    
    delay(50);
  }
  
  // Return to standard baud
  SERIAL_OUT.end();
  delay(100);
  SERIAL_OUT.begin(115200);
  delay(500);
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("Returned to 115200 baud"));
}
*/

// ==================== HARDWARE RNG BENCHMARK ====================

// Include Zephyr RNG for STM32U5 boards
#if defined(BOARD_STM32U5) && defined(__ZEPHYR__)
#include <zephyr/random/random.h>
#endif

#if defined(ESP32) || defined(BOARD_STM32U5)
void benchmarkHardwareRNG() {
  printHeader("CRYPTO: Hardware RNG");

#if defined(ESP32)
  SERIAL_OUT.println(F_STR("Using ESP32 hardware RNG"));
#elif defined(BOARD_STM32U5)
  #if defined(__ZEPHYR__)
  SERIAL_OUT.println(F_STR("Using STM32U585 hardware RNG (Zephyr)"));
  #else
  SERIAL_OUT.println(F_STR("Using STM32U585 RNG"));
  #endif
#endif

  // Test RNG speed
  startBenchmark();
  volatile uint32_t rngSum = 0;
  for (int i = 0; i < 1000; i++) {
#if defined(ESP32)
    rngSum += esp_random();
#elif defined(BOARD_STM32U5) && defined(__ZEPHYR__)
    rngSum += sys_rand32_get();  // True hardware RNG via Zephyr
#elif defined(BOARD_STM32U5)
    rngSum += random(0, 0xFFFFFFFF);  // Fallback to Arduino random
#endif
  }
  unsigned long rngTime = endBenchmark();

  SERIAL_OUT.print(F_STR("Checksum: "));
  SERIAL_OUT.println(rngSum);

  SERIAL_OUT.print(F_STR("Hardware RNG (1000 values): "));
  SERIAL_OUT.print(rngTime);
  SERIAL_OUT.print(F_STR(" μs ("));
  SERIAL_OUT.print(1000.0f / rngTime * 1000, 2);
  SERIAL_OUT.println(F_STR(" values/ms)"));

  // Test randomness distribution
  uint32_t bins[4] = { 0, 0, 0, 0 };
  for (int i = 0; i < 10000; i++) {
#if defined(ESP32)
    uint32_t val = esp_random();
#elif defined(BOARD_STM32U5) && defined(__ZEPHYR__)
    uint32_t val = sys_rand32_get();
#elif defined(BOARD_STM32U5)
    uint32_t val = random(0, 0xFFFFFFFF);
#endif
    bins[val % 4]++;
  }

  SERIAL_OUT.println(F_STR("Distribution (10000 samples):"));
  for (int i = 0; i < 4; i++) {
    SERIAL_OUT.print(F_STR("  Bin "));
    SERIAL_OUT.print(i);
    SERIAL_OUT.print(F_STR(": "));
    SERIAL_OUT.print(bins[i]);
    SERIAL_OUT.print(F_STR(" ("));
    SERIAL_OUT.print(bins[i] / 100.0f, 1);
    SERIAL_OUT.println(F_STR("%)"));
  }
  SERIAL_OUT.println(F_STR("(Ideal: 25% each bin)"));
}
#endif

// ==================== SOFTWARE ATSE BENCHMARK ====================

// Arduino Uno R4 WiFi has an ESP32-S3 WiFi module with secure element capabilities
// SoftwareATSE library is included with the WiFiS3 library on Uno R4 WiFi
#if defined(ARDUINO_UNOR4_WIFI)

#include <SoftwareATSE.h>

constexpr int kAtseKeyId = 999;  // Reserved for benchmark use to avoid clobbering other keys.

void benchmarkSoftwareATSE() {
  printHeader("CRYPTO: SoftwareATSE (Uno R4 WiFi)");

  SERIAL_OUT.println(F_STR("Initializing SoftwareATSE..."));

  // Initialize SoftwareATSE
  if (!SATSE.begin()) {
    SERIAL_OUT.println(F_STR("SoftwareATSE initialization failed"));
    SERIAL_OUT.println(F_STR("The WiFi module may not be responding or"));
    SERIAL_OUT.println(F_STR("secure element features may not be available."));
    return;
  }

  SERIAL_OUT.println(F_STR("SoftwareATSE initialized successfully!"));
  SERIAL_OUT.println();

  // ===== Public Key Generation Benchmark =====
  SERIAL_OUT.println(F_STR("--- Public Key Generation ---"));

  bool keyGenSupported = false;
  const uint16_t keySlot = kAtseKeyId;
  unsigned long keyGenStart = millis();
  byte publicKey[64];   // Buffer for public key
  byte privateKey[32];  // Buffer for private key

  if (SATSE.generatePrivateKey(keySlot, privateKey) == 1) {
    // Try to generate public key in the same slot
    if (SATSE.generatePublicKey(kAtseKeyId, publicKey) == 1) {
      unsigned long keyGenTime = millis() - keyGenStart;
      keyGenSupported = true;

      SERIAL_OUT.print(F_STR("SoftwareATSE: Public key generation (ms): "));
      SERIAL_OUT.println(keyGenTime);

      SERIAL_OUT.print(F_STR("  Rate: "));
      if (keyGenTime > 0) {
        SERIAL_OUT.print(1000.0f / keyGenTime, 3);
        SERIAL_OUT.println(F_STR(" keys/sec"));
      } else {
        SERIAL_OUT.println(F_STR("N/A (too fast)"));
      }
    } else {
      SERIAL_OUT.println(F_STR("SoftwareATSE: Public key generation - not supported"));
    }
  } else {
    SERIAL_OUT.println(F_STR("SoftwareATSE: Private key generation failed; skipping public key test"));
  }

  SERIAL_OUT.println();

  // ===== Configuration Write Benchmark =====
  SERIAL_OUT.println(F_STR("--- Secure Storage Operations ---"));

  uint8_t testConfig[256];
  for (int i = 0; i < 256; i++) {
    testConfig[i] = i & 0xFF;
  }

  unsigned long writeStart = micros();
  bool writeSuccess = false;

  if (SATSE.writeConfiguration(testConfig) == 1) {
    unsigned long writeTime = micros() - writeStart;
    writeSuccess = true;

    SERIAL_OUT.print(F_STR("Config write (\xC2\xB5s): "));
    SERIAL_OUT.println(writeTime);
    SERIAL_OUT.print(F_STR("  (ms): "));
    SERIAL_OUT.println(writeTime / 1000.0f, 3);

    SERIAL_OUT.print(F_STR("  Write speed: "));
    if (writeTime > 0) {
      SERIAL_OUT.print(256.0f * 1000000.0f / writeTime, 2);
      SERIAL_OUT.println(F_STR(" bytes/sec"));
    } else {
      SERIAL_OUT.println(F_STR("N/A (too fast)"));
    }
  } else {
    SERIAL_OUT.println(F_STR("Config write - not supported"));
  }

  SERIAL_OUT.println();

  // ===== Signing Benchmark =====
  SERIAL_OUT.println(F_STR("--- EC Signing ---"));

  if (keyGenSupported) {
    uint8_t testData[32];
    for (int i = 0; i < 32; i++) {
      testData[i] = (uint8_t)(i * 7 + 13);
    }

    uint8_t signature[64];

    // Signing benchmark
    const int NUM_SIGN_OPS = 10;
    unsigned long signStart = micros();
    int successfulSigns = 0;

    for (int i = 0; i < NUM_SIGN_OPS; i++) {
      if (SATSE.ecSign(kAtseKeyId, testData, signature)) {
        successfulSigns++;
      }
      yield();
    }

    unsigned long signTime = micros() - signStart;

    if (successfulSigns > 0) {
      float avgSignTimeMs = (signTime / 1000.0f) / successfulSigns;
      SERIAL_OUT.print(F_STR("EC signing (avg ms/op): "));
      SERIAL_OUT.println(avgSignTimeMs, 3);

      SERIAL_OUT.print(F_STR("  Rate: "));
      SERIAL_OUT.print(1000.0f / avgSignTimeMs, 2);
      SERIAL_OUT.println(F_STR(" ops/sec"));

      SERIAL_OUT.print(F_STR("  Successful operations: "));
      SERIAL_OUT.print(successfulSigns);
      SERIAL_OUT.print(F_STR("/"));
      SERIAL_OUT.println(NUM_SIGN_OPS);
    } else {
      SERIAL_OUT.println(F_STR("EC signing - not supported"));
    }
  } else {
    SERIAL_OUT.println(F_STR("Signing tests skipped (key generation not supported)"));
  }

  SERIAL_OUT.println();

  // ===== Secure RNG Benchmark =====
  SERIAL_OUT.println(F_STR("--- Secure Random Number Generator ---"));

  uint8_t rngTest[16];
  if (SATSE.random(rngTest, 16)) {

    // Benchmark RNG throughput
    const int RNG_BUFFER_SIZE = 256;
    const int RNG_ITERATIONS = 20;
    uint8_t rngBuffer[RNG_BUFFER_SIZE];

    unsigned long rngStart = micros();
    int successfulReads = 0;
    uint32_t rngChecksum = 0;

    for (int i = 0; i < RNG_ITERATIONS; i++) {
      if (SATSE.random(rngBuffer, RNG_BUFFER_SIZE)) {
        successfulReads++;
        for (int j = 0; j < RNG_BUFFER_SIZE; j++) {
          rngChecksum += rngBuffer[j];
        }
      }
      yield();
    }

    unsigned long rngTime = micros() - rngStart;

    SERIAL_OUT.print(F_STR("RNG checksum: "));
    SERIAL_OUT.println(rngChecksum);

    if (successfulReads > 0) {
      unsigned long totalBytes = successfulReads * RNG_BUFFER_SIZE;
      float bytesPerSec = (totalBytes * 1000000.0f) / rngTime;

      SERIAL_OUT.print(F_STR("Secure RNG throughput: "));
      SERIAL_OUT.print(bytesPerSec, 2);
      SERIAL_OUT.println(F_STR(" bytes/sec"));

      SERIAL_OUT.print(F_STR("  Total bytes generated: "));
      SERIAL_OUT.println(totalBytes);

      SERIAL_OUT.print(F_STR("  Time: "));
      SERIAL_OUT.print(rngTime / 1000.0f, 2);
      SERIAL_OUT.println(F_STR(" ms"));

      SERIAL_OUT.print(F_STR("  Successful reads: "));
      SERIAL_OUT.print(successfulReads);
      SERIAL_OUT.print(F_STR("/"));
      SERIAL_OUT.println(RNG_ITERATIONS);

      // Distribution test
      SERIAL_OUT.println(F_STR("Distribution test (first 1000 bytes):"));
      uint32_t byteBins[4] = { 0, 0, 0, 0 };

      for (int i = 0; i < 1000; i++) {
        uint8_t randomByte;
        if (SATSE.random(&randomByte, 1)) {
          byteBins[randomByte % 4]++;
        }
      }

      for (int i = 0; i < 4; i++) {
        SERIAL_OUT.print(F_STR("  Bin "));
        SERIAL_OUT.print(i);
        SERIAL_OUT.print(F_STR(": "));
        SERIAL_OUT.print(byteBins[i]);
        SERIAL_OUT.print(F_STR(" ("));
        SERIAL_OUT.print(byteBins[i] / 10.0f, 1);
        SERIAL_OUT.println(F_STR("%)"));
      }
      SERIAL_OUT.println(F_STR("  (Ideal: 25% each bin)"));
    } else {
      SERIAL_OUT.println(F_STR("Secure RNG - read operations failed"));
    }
  } else {
    SERIAL_OUT.println(F_STR("Secure RNG - not supported"));
  }

  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("SoftwareATSE benchmarks complete"));
}

#else  // !ARDUINO_UNOR4_WIFI

// Stub function for non-Uno R4 WiFi boards
void benchmarkSoftwareATSE() {
  // This function intentionally left empty for non-R4 boards
  // It won't be called due to compile-time guards in setup()
}

#endif  // ARDUINO_UNOR4_WIFI

// ==================== ARDUINO BRIDGE (UNO Q MCU<->LINUX) ====================

#if defined(BOARD_STM32U5) && defined(HAS_DUAL_PROCESSOR)

void benchmarkArduinoBridge() {
  printHeader("ARDUINO BRIDGE (MCU<->LINUX RPC)");

#ifdef HAS_RPC_BRIDGE
  SERIAL_OUT.println(F_STR("Testing MCU<->Linux RPC communication..."));
  SERIAL_OUT.println(F_STR("Using MessagePack RPC over Serial1"));
  SERIAL_OUT.println();

  // Note: For RouterBridge, Bridge object is pre-initialized
  // For RPClite, we need to create transport and client

#ifdef HAS_ROUTER_BRIDGE
  // Using Arduino_RouterBridge high-level API
  SERIAL_OUT.println(F_STR("Bridge Type: RouterBridge (high-level API)"));
  SERIAL_OUT.println();

  // Test 1: Simple RPC call latency
  SERIAL_OUT.println(F_STR("1. RPC Call Latency Test"));
  const int PING_COUNT = 50;
  unsigned long totalLatency = 0;
  int successfulCalls = 0;

  for (int i = 0; i < PING_COUNT; i++) {
    unsigned long start = micros();

    // Call a simple echo/ping function on Linux side
    // Assumes Linux has registered an "echo" or "ping" method
    String result;
    bool ok = Bridge.call("echo", result, "ping").result(result);

    unsigned long elapsed = micros() - start;

    if (ok) {
      totalLatency += elapsed;
      successfulCalls++;
    }

    if (i % 10 == 0) {
      yield();
    }
  }

  if (successfulCalls > 0) {
    SERIAL_OUT.print(F_STR("  Successful calls: "));
    SERIAL_OUT.print(successfulCalls);
    SERIAL_OUT.print(F_STR("/"));
    SERIAL_OUT.println(PING_COUNT);
    SERIAL_OUT.print(F_STR("  Average latency: "));
    SERIAL_OUT.print(totalLatency / successfulCalls);
    SERIAL_OUT.println(F_STR(" µs"));
    SERIAL_OUT.print(F_STR("  Calls per second: "));
    SERIAL_OUT.println((successfulCalls * 1000000.0) / totalLatency, 0);
  } else {
    SERIAL_OUT.println(F_STR("  ERROR: No successful RPC calls"));
    SERIAL_OUT.println(F_STR("  Make sure Linux side has 'echo' method registered"));
  }
  SERIAL_OUT.println();

  // Test 2: Integer arithmetic RPC
  SERIAL_OUT.println(F_STR("2. Integer Arithmetic RPC Test"));
  int mathTests = 0;
  int mathSuccess = 0;
  unsigned long mathTime = micros();

  for (int i = 0; i < 20; i++) {
    int sum;
    if (Bridge.call("add", sum, i, i + 1).result(sum)) {
      if (sum == (i + i + 1)) {
        mathSuccess++;
      }
      mathTests++;
    }
  }

  mathTime = micros() - mathTime;
  SERIAL_OUT.print(F_STR("  Tests: "));
  SERIAL_OUT.print(mathSuccess);
  SERIAL_OUT.print(F_STR("/"));
  SERIAL_OUT.println(mathTests);
  SERIAL_OUT.print(F_STR("  Average time: "));
  SERIAL_OUT.print(mathTime / mathTests);
  SERIAL_OUT.println(F_STR(" µs"));
  SERIAL_OUT.println();

  // Test 3: String operations
  SERIAL_OUT.println(F_STR("3. String RPC Test"));
  int strTests = 0;
  int strSuccess = 0;
  unsigned long strTime = micros();

  for (int i = 0; i < 10; i++) {
    String message = "Test_" + String(i);
    String response;
    if (Bridge.call("loopback", response, message).result(response)) {
      if (response == message) {
        strSuccess++;
      }
      strTests++;
    }
  }

  strTime = micros() - strTime;
  SERIAL_OUT.print(F_STR("  Tests: "));
  SERIAL_OUT.print(strSuccess);
  SERIAL_OUT.print(F_STR("/"));
  SERIAL_OUT.println(strTests);
  SERIAL_OUT.print(F_STR("  Average time: "));
  SERIAL_OUT.print(strTime / strTests);
  SERIAL_OUT.println(F_STR(" µs"));
  SERIAL_OUT.println();

  // Test 4: Async call test
  SERIAL_OUT.println(F_STR("4. Async RPC Call Test"));
  unsigned long asyncStart = micros();

  // Make multiple async calls
  RpcCall call1 = Bridge.call("add", 10, 20);
  RpcCall call2 = Bridge.call("add", 30, 40);
  RpcCall call3 = Bridge.call("add", 50, 60);

  // Now wait for results
  int result1, result2, result3;
  bool ok1 = call1.result(result1);
  bool ok2 = call2.result(result2);
  bool ok3 = call3.result(result3);

  unsigned long asyncTime = micros() - asyncStart;

  SERIAL_OUT.print(F_STR("  3 async calls completed in: "));
  SERIAL_OUT.print(asyncTime);
  SERIAL_OUT.println(F_STR(" µs"));
  if (ok1 && ok2 && ok3) {
    SERIAL_OUT.print(F_STR("  Results: "));
    SERIAL_OUT.print(result1);
    SERIAL_OUT.print(F_STR(", "));
    SERIAL_OUT.print(result2);
    SERIAL_OUT.print(F_STR(", "));
    SERIAL_OUT.println(result3);
  }
  SERIAL_OUT.println();

  SERIAL_OUT.println(F_STR("NOTE: These tests require corresponding RPC methods"));
  SERIAL_OUT.println(F_STR("      registered on the Linux side (echo, add, loopback)."));
  SERIAL_OUT.println(F_STR("      See Arduino_RouterBridge examples for Linux setup."));

#elif defined(HAS_RPCLITE)
  // Using Arduino_RPClite low-level API
  SERIAL_OUT.println(F_STR("Bridge Type: RPClite (low-level API)"));
  SERIAL_OUT.println();

  SerialTransport transport(Serial1);
  RPCClient client(transport);

  SERIAL_OUT.println(F_STR("1. RPC Call Latency Test"));
  const int PING_COUNT = 50;
  unsigned long totalLatency = 0;
  int successfulCalls = 0;

  for (int i = 0; i < PING_COUNT; i++) {
    unsigned long start = micros();

    String result;
    bool ok = client.call("echo", result, "ping");

    unsigned long elapsed = micros() - start;

    if (ok) {
      totalLatency += elapsed;
      successfulCalls++;
    }

    if (i % 10 == 0) {
      yield();
    }
  }

  if (successfulCalls > 0) {
    SERIAL_OUT.print(F_STR("  Successful calls: "));
    SERIAL_OUT.print(successfulCalls);
    SERIAL_OUT.print(F_STR("/"));
    SERIAL_OUT.println(PING_COUNT);
    SERIAL_OUT.print(F_STR("  Average latency: "));
    SERIAL_OUT.print(totalLatency / successfulCalls);
    SERIAL_OUT.println(F_STR(" µs"));
  }
  SERIAL_OUT.println();

  SERIAL_OUT.println(F_STR("NOTE: RPClite requires manual transport setup."));
  SERIAL_OUT.println(F_STR("      Ensure Serial1 is properly initialized."));
#endif

#else
  SERIAL_OUT.println(F_STR("Arduino RPC Bridge library not detected."));
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("To enable Bridge/RPC benchmarks:"));
  SERIAL_OUT.println(F_STR("  1. Install Arduino_RouterBridge or Arduino_RPClite"));
  SERIAL_OUT.println(F_STR("  2. Ensure Linux side has RPC server running"));
  SERIAL_OUT.println(F_STR("  3. Register test methods (echo, add, loopback)"));
  SERIAL_OUT.println(F_STR("  4. Re-compile and upload sketch"));
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("Library: github.com/arduino-libraries/Arduino_RouterBridge"));
  SERIAL_OUT.println(F_STR("Library: github.com/arduino-libraries/Arduino_RPClite"));
#endif

  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("Arduino Bridge benchmarks complete"));
}

#else  // !BOARD_STM32U5 || !HAS_DUAL_PROCESSOR

// Stub function for non-Uno Q boards
void benchmarkArduinoBridge() {
  // This function intentionally left empty for non-Uno Q boards
  // It won't be called due to compile-time guards in setup()
}

#endif  // BOARD_STM32U5 && HAS_DUAL_PROCESSOR

// ==================== MULTIDUINO-SPECIFIC BENCHMARKS ====================

#ifdef HAS_RTC
void benchmarkRTC() {
  printHeader("RTC BENCHMARK (DS1307)");

  // Initialize RTC
  if (!rtc.begin()) {
    SERIAL_OUT.println(F_STR("ERROR: RTC not found!"));
    SERIAL_OUT.println(F_STR("Check wiring: SDA->A4, SCL->A5"));
    SERIAL_OUT.println();
    return;
  }

  SERIAL_OUT.println(F_STR("RTC initialized successfully"));

  // Check if RTC is running
  if (!rtc.isrunning()) {
    SERIAL_OUT.println(F_STR("WARNING: RTC is not running!"));
    SERIAL_OUT.println(F_STR("Starting RTC and setting time..."));
    // Set to compile time as default
    rtc.adjust(DateTime(F_STR(__DATE__), F_STR(__TIME__)));
  }

  // Display current time
  DateTime now = rtc.now();
  SERIAL_OUT.print(F_STR("Current Time: "));
  SERIAL_OUT.print(now.year(), DEC);
  SERIAL_OUT.print('/');
  if (now.month() < 10) SERIAL_OUT.print('0');
  SERIAL_OUT.print(now.month(), DEC);
  SERIAL_OUT.print('/');
  if (now.day() < 10) SERIAL_OUT.print('0');
  SERIAL_OUT.print(now.day(), DEC);
  SERIAL_OUT.print(" ");
  if (now.hour() < 10) SERIAL_OUT.print('0');
  SERIAL_OUT.print(now.hour(), DEC);
  SERIAL_OUT.print(':');
  if (now.minute() < 10) SERIAL_OUT.print('0');
  SERIAL_OUT.print(now.minute(), DEC);
  SERIAL_OUT.print(':');
  if (now.second() < 10) SERIAL_OUT.print('0');
  SERIAL_OUT.println(now.second(), DEC);
  SERIAL_OUT.println();

  // Benchmark 1: RTC Read Speed
  SERIAL_OUT.println(F_STR("Test: RTC Read Speed"));
  volatile uint32_t readChecksum = 0;
  unsigned long startTime = micros();
  uint32_t reads = 0;

  unsigned long testDuration = 1000000UL;  // 1 second
  while (micros() - startTime < testDuration) {
    DateTime reading = rtc.now();
    readChecksum += reading.unixtime();
    reads++;
  }
  unsigned long elapsed = micros() - startTime;

  float readsPerMs = (reads * 1000.0f) / elapsed;
  SERIAL_OUT.print(F_STR("  Reads: "));
  SERIAL_OUT.print(reads);
  SERIAL_OUT.print(F_STR(" in "));
  SERIAL_OUT.print(elapsed / 1000.0f, 2);
  SERIAL_OUT.println(F_STR(" ms"));
  SERIAL_OUT.print(F_STR("  Speed: "));
  SERIAL_OUT.print(readsPerMs, 2);
  SERIAL_OUT.println(F_STR(" reads/ms"));
  SERIAL_OUT.print(F_STR("  Time per read: "));
  SERIAL_OUT.print((float)elapsed / reads, 2);
  SERIAL_OUT.println(F_STR(" μs"));
  SERIAL_OUT.print(F_STR("  Checksum: 0x"));
  SERIAL_OUT.println((unsigned long)readChecksum, HEX);
  SERIAL_OUT.println();

  // Benchmark 2: RTC Write Speed (Using adjust - time setting)
  SERIAL_OUT.println(F_STR("Test: RTC Write Speed (Time Adjust)"));
  startTime = micros();
  uint32_t writes = 0;

  testDuration = 1000000UL;  // 1 second
  DateTime testTime = DateTime(2025, 1, 1, 12, 0, 0);
  while (micros() - startTime < testDuration) {
    rtc.adjust(testTime);
    writes++;
  }
  elapsed = micros() - startTime;

  // Restore current time
  rtc.adjust(now);

  float writesPerMs = (writes * 1000.0f) / elapsed;
  SERIAL_OUT.print(F_STR("  Writes: "));
  SERIAL_OUT.print(writes);
  SERIAL_OUT.print(F_STR(" in "));
  SERIAL_OUT.print(elapsed / 1000.0f, 2);
  SERIAL_OUT.println(F_STR(" ms"));
  SERIAL_OUT.print(F_STR("  Speed: "));
  SERIAL_OUT.print(writesPerMs, 2);
  SERIAL_OUT.println(F_STR(" writes/ms"));
  SERIAL_OUT.print(F_STR("  Time per write: "));
  SERIAL_OUT.print((float)elapsed / writes, 2);
  SERIAL_OUT.println(F_STR(" μs"));
  SERIAL_OUT.println();

  // Benchmark 3: NVRAM Read/Write Speed (DS1307 has 56 bytes of NVRAM)
  SERIAL_OUT.println(F_STR("Test: NVRAM Read/Write (56 bytes)"));
  const uint8_t nvramSize = 56;
  uint8_t nvramData[nvramSize];

  // Write test
  for (uint8_t i = 0; i < nvramSize; i++) {
    nvramData[i] = i;
  }

  startTime = micros();
  uint32_t nvramWrites = 0;
  testDuration = 1000000UL;  // 1 second

  while (micros() - startTime < testDuration) {
    for (uint8_t addr = 0; addr < nvramSize; addr++) {
      rtc.writenvram(addr, nvramData[addr]);
    }
    nvramWrites++;
  }
  elapsed = micros() - startTime;

  uint32_t totalBytesWritten = nvramWrites * nvramSize;
  float nvramWriteSpeed = (totalBytesWritten * 1000.0f) / elapsed;

  SERIAL_OUT.print(F_STR("  NVRAM Writes: "));
  SERIAL_OUT.print(totalBytesWritten);
  SERIAL_OUT.print(F_STR(" bytes in "));
  SERIAL_OUT.print(elapsed / 1000.0f, 2);
  SERIAL_OUT.println(F_STR(" ms"));
  SERIAL_OUT.print(F_STR("  Speed: "));
  SERIAL_OUT.print(nvramWriteSpeed, 2);
  SERIAL_OUT.println(F_STR(" bytes/ms"));

  // Read test
  volatile uint32_t nvramChecksum = 0;
  startTime = micros();
  uint32_t nvramReads = 0;

  while (micros() - startTime < testDuration) {
    for (uint8_t addr = 0; addr < nvramSize; addr++) {
      nvramChecksum += rtc.readnvram(addr);
    }
    nvramReads++;
  }
  elapsed = micros() - startTime;

  uint32_t totalBytesRead = nvramReads * nvramSize;
  float nvramReadSpeed = (totalBytesRead * 1000.0f) / elapsed;

  SERIAL_OUT.print(F_STR("  NVRAM Reads: "));
  SERIAL_OUT.print(totalBytesRead);
  SERIAL_OUT.print(F_STR(" bytes in "));
  SERIAL_OUT.print(elapsed / 1000.0f, 2);
  SERIAL_OUT.println(F_STR(" ms"));
  SERIAL_OUT.print(F_STR("  Speed: "));
  SERIAL_OUT.print(nvramReadSpeed, 2);
  SERIAL_OUT.println(F_STR(" bytes/ms"));
  SERIAL_OUT.print(F_STR("  Checksum: 0x"));
  SERIAL_OUT.println((unsigned long)nvramChecksum, HEX);
  SERIAL_OUT.println();

  SERIAL_OUT.println(F_STR("RTC benchmarks complete"));
}
#endif  // HAS_RTC

// ==================== SYSTEM INFO ====================

void printSystemInfo() {
  printHeader("SYSTEM INFORMATION");

  SERIAL_OUT.print(F_STR("Board: "));
  SERIAL_OUT.println(BOARD_NAME);

#if defined(ESP32)
  SERIAL_OUT.print(F_STR("Chip Model: "));
  SERIAL_OUT.println(ESP.getChipModel());
  SERIAL_OUT.print(F_STR("Chip Revision: "));
  SERIAL_OUT.println(ESP.getChipRevision());
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(ESP.getCpuFreqMHz());
  SERIAL_OUT.println(F_STR(" MHz"));
  SERIAL_OUT.print(F_STR("Cores: "));
  SERIAL_OUT.println(ESP.getChipCores());
  SERIAL_OUT.print(F_STR("SDK Version: "));
  SERIAL_OUT.println(ESP.getSdkVersion());
#elif defined(ESP8266)
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(ESP.getCpuFreqMHz());
  SERIAL_OUT.println(F_STR(" MHz"));
  SERIAL_OUT.print(F_STR("Chip ID: "));
  SERIAL_OUT.println(ESP.getChipId());
  SERIAL_OUT.print(F_STR("SDK Version: "));
  SERIAL_OUT.println(ESP.getSdkVersion());
#elif defined(ARDUINO_ARCH_RP2040)
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(F_CPU / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));
#if defined(ARDUINO_NANO_RP2040_CONNECT)
  SERIAL_OUT.println(F_STR("Features: WiFi (Nina W102), BLE, IMU (LSM6DSOX), Mic"));
#elif defined(ARDUINO_RASPBERRY_PI_PICO_W)
  SERIAL_OUT.println(F_STR("Features: WiFi (CYW43439)"));
#endif
#elif defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA)
  SERIAL_OUT.print(F_STR("MCU: Renesas RA4M1 (ARM Cortex-M4)"));
  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(F_CPU / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));
#ifdef ARDUINO_UNOR4_WIFI
  SERIAL_OUT.println(F_STR("Features: WiFi (ESP32-S3), 12x8 LED Matrix"));
#else
  SERIAL_OUT.println(F_STR("Features: 12x8 LED Matrix"));
#endif
#elif defined(BOARD_SAMD)
  SERIAL_OUT.print(F_STR("MCU: SAMD (ARM Cortex-M0+)"));
  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(F_CPU / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));
#if defined(ARDUINO_SAMD_NANO_33_IOT)
  SERIAL_OUT.println(F_STR("Features: WiFi, BLE, IMU (LSM6DS3)"));
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
  SERIAL_OUT.println(F_STR("Features: WiFi (Nina W102), Crypto (ECC508)"));
#endif
#elif defined(BOARD_NRF52)
  SERIAL_OUT.print(F_STR("MCU: nRF52840 (ARM Cortex-M4F)"));
  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("CPU Frequency: 64 MHz"));
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("Features: BLE 5.0, IMU (LSM9DS1)"));
#elif defined(BOARD_STM32H7)
  SERIAL_OUT.print(F_STR("MCU: STM32H7 (ARM Cortex-M7)"));
  SERIAL_OUT.println();
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(F_CPU / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));
#ifdef HAS_DUAL_CORE
  SERIAL_OUT.println(F_STR("Cores: Dual Core (M7 + M4)"));
#endif
#elif defined(BOARD_TEENSY)
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
  SERIAL_OUT.print(F_CPU / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));
#if defined(__IMXRT1062__)
  SERIAL_OUT.println(F_STR("MCU: i.MX RT1062 (ARM Cortex-M7)"));
#endif
#elif defined(BOARD_STM32U5)
  SERIAL_OUT.println(F_STR("MCU: STM32U585 (ARM Cortex-M33)"));
  SERIAL_OUT.print(F_STR("MCU Frequency: "));

  // Try to get actual clock frequency
#if defined(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC)
  SERIAL_OUT.print(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000000);
#elif defined(F_CPU)
  SERIAL_OUT.print(F_CPU / 1000000);
#else
  SERIAL_OUT.print(F_STR("160"));  // STM32U585 default max frequency
#endif

  SERIAL_OUT.println(F_STR(" MHz"));
  SERIAL_OUT.println(F_STR("MCU Features: FPU, DSP, TrustZone"));
  SERIAL_OUT.println(F_STR("MCU RAM: 786 KB SRAM"));
  SERIAL_OUT.println(F_STR("MCU Flash: 2 MB"));
#ifdef USING_ZEPHYR
  SERIAL_OUT.println(F_STR("MCU RTOS: Zephyr"));
#endif
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("Linux MPU: Qualcomm QRB2210"));
  SERIAL_OUT.println(F_STR("MPU: Quad Cortex-A53 @ up to 2.0 GHz"));
  SERIAL_OUT.println(F_STR("MPU RAM: 2-4 GB"));
  SERIAL_OUT.println(F_STR("MPU Storage: 16 GB eMMC"));
  SERIAL_OUT.println(F_STR("MPU OS: Debian-based Linux"));
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("Communication: Arduino Bridge RPC (MCU<->Linux)"));
#ifdef HAS_ROUTER_BRIDGE
  SERIAL_OUT.println(F_STR("RPC Library: Arduino_RouterBridge (MessagePack)"));
#elif defined(HAS_RPCLITE)
  SERIAL_OUT.println(F_STR("RPC Library: Arduino_RPClite (MessagePack)"));
#else
  SERIAL_OUT.println(F_STR("RPC Library: Not detected"));
#endif
#else
  SERIAL_OUT.print(F_STR("CPU Frequency: "));
#if defined(F_CPU)
  SERIAL_OUT.print(F_CPU / 1000000);
  SERIAL_OUT.println(F_STR(" MHz"));
#else
  SERIAL_OUT.println(F_STR("Unknown"));
#endif
#endif

#if defined(ARDUINO_AVR_MULTIDUINO)
  SERIAL_OUT.println(F_STR("Features: RTC (DS1307)"));
#endif

  // RAM Info
  SERIAL_OUT.print(F_STR("Free RAM: "));
#if defined(ESP32)
  SERIAL_OUT.print(ESP.getFreeHeap() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
  SERIAL_OUT.print(F_STR("Total Heap: "));
  SERIAL_OUT.print(ESP.getHeapSize() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
  SERIAL_OUT.print(F_STR("Min Free Heap: "));
  SERIAL_OUT.print(ESP.getMinFreeHeap() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
#elif defined(ESP8266)
  SERIAL_OUT.print(ESP.getFreeHeap() / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
#elif defined(__AVR__)
  extern int __heap_start, *__brkval;
  int v;
  int freeRam = (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
  SERIAL_OUT.print(freeRam);
  SERIAL_OUT.println(F_STR(" bytes"));
// Show total RAM for common AVR boards
#if defined(__AVR_ATmega328P__)
  SERIAL_OUT.println(F_STR("Total RAM: 2 KB"));
#elif defined(__AVR_ATmega2560__)
  SERIAL_OUT.println(F_STR("Total RAM: 8 KB"));
#elif defined(__AVR_ATmega32U4__)
  SERIAL_OUT.println(F_STR("Total RAM: 2.5 KB"));
#endif
#elif defined(ARDUINO_SAM_DUE)
  extern char _end;
  extern "C" char *sbrk(int i);
  char *ramstart = (char *)0x20070000;
  char *ramend = (char *)0x20088000;
  int freeRam = ramend - sbrk(0);
  SERIAL_OUT.print(freeRam / 1024);
  SERIAL_OUT.println(F_STR(" KB"));
  SERIAL_OUT.println(F_STR("Total RAM: 96 KB"));
#elif defined(ARDUINO_ARCH_RP2040)
  // RP2040 has 264KB RAM
  SERIAL_OUT.println(F_STR("~264 KB (RP2040)"));
#elif defined(BOARD_NRF52)
  SERIAL_OUT.println(F_STR("~256 KB (nRF52840)"));
#elif defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_UNOR4_MINIMA)
  SERIAL_OUT.println(F_STR("32 KB (RA4M1)"));
#elif defined(BOARD_SRAM_KB)
  SERIAL_OUT.print(F_STR("Total RAM: "));
  SERIAL_OUT.print(BOARD_SRAM_KB);
  SERIAL_OUT.println(F_STR(" KB"));
#else
  SERIAL_OUT.println(F_STR("Unknown"));
#endif

  SERIAL_OUT.print(F_STR("Compile Date: "));
  SERIAL_OUT.print(__DATE__);
  SERIAL_OUT.print(F_STR(" "));
  SERIAL_OUT.println(__TIME__);
}

// ==================== MAIN FUNCTIONS ====================

void setup() {
#if defined(ARDUINO_UNO_Q)
  SERIAL_OUT.begin();  // Uno Q Monitor doesn't use baud rate
  delay(3000);  // Wait longer for Monitor connection
#else
  SERIAL_OUT.begin(SERIAL_BAUD);
  delay(2000);  // Wait for serial connection
#endif

  calibrateBenchmarkTime();

  SERIAL_OUT.println();
  SERIAL_OUT.println();
  printDivider();
  SERIAL_OUT.println(F_STR("  UNIVERSAL ARDUINO BENCHMARK SUITE"));
  printDivider();
  SERIAL_OUT.println();

  // System info
  printSystemInfo();

  // CPU benchmarks
  benchmarkIntegerOps();
  benchmarkFloatOps();
  benchmarkStringOps();
  benchmarkCPUStress();

  // Memory benchmarks
  benchmarkSRAM();
#if defined(EEPROM_h) || defined(ESP32) || defined(ESP8266)
  benchmarkEEPROM();
#endif
#ifdef HAS_PSRAM
  benchmarkPSRAM();
#endif

  // I/O benchmarks
  benchmarkDigitalIO();
  benchmarkAnalogIO();
  benchmarkSerial();

  // Board-specific
  benchmarkFlash();
#ifdef HAS_LED_MATRIX
  benchmarkLEDMatrix();
#endif
#ifdef HAS_WIFI
  benchmarkWiFi();
#endif
#ifdef HAS_BLE
  benchmarkBLE();
#endif

  // Advanced benchmarks
  benchmarkAdvancedMath();
  benchmarkTimingPrecision();
  benchmarkStackDepth();
#if defined(ARDUINO_ARCH_RP2040)
  benchmarkSHA1();
#endif
#if defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
  benchmarkMultiCore();
#endif
#if defined(ESP32)
  benchmarkESP32Crypto();
  benchmarkHardwareRNG();
#endif
#if defined(BOARD_STM32U5)
  benchmarkHardwareRNG();
#endif
#if defined(ARDUINO_UNOR4_WIFI)
  benchmarkSoftwareATSE();
#endif
#if defined(BOARD_STM32U5) && defined(HAS_DUAL_PROCESSOR)
  //benchmarkArduinoBridge();
#endif

  // Multiduino-specific benchmarks
#ifdef HAS_RTC
  benchmarkRTC();
#endif

  // Final summary
  printHeader("BENCHMARK COMPLETE!");
  SERIAL_OUT.println(F_STR("Results saved in Serial Monitor."));
  SERIAL_OUT.println(F_STR("You can copy/paste the output for analysis."));
  SERIAL_OUT.println();
  SERIAL_OUT.println(F_STR("To run again, press the RESET button or"));
  SERIAL_OUT.println(F_STR("re-upload the sketch."));
  printDivider();
}

void loop() {
  // Nothing to do - benchmark runs once in setup()
  delay(1000);
}

Can you present the benchmarks that you have already obtained, best in some sort of table for easy comparison.
If that test compiles for an ESP32-C6 I can deliver the results to you if I can copy these out of the serial monitor.

Arduino Uno R3:

========================================
  UNIVERSAL ARDUINO BENCHMARK SUITE
========================================


========================================
SYSTEM INFORMATION
========================================
Board: Arduino Uno
CPU Frequency: 16 MHz
Free RAM: 921 bytes
Total RAM: 2 KB
Compile Date: Jan 29 2026 20:03:02

========================================
CPU: INTEGER OPERATIONS
========================================
Checksum: 49995000
Checksum: 1243496233
Checksum: 100
Addition (10000 ops): 101724 μs (98.31 ops/ms)
Multiplication (200 ops): 6468 μs (30.92 ops/ms)
Division (200 ops): 8084 μs (24.74 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS
========================================
Checksum: 3141.60
Checksum: 1.11
Checksum: 1322.93
Checksum: 129.92
Float Addition (1000 ops): 9884 μs (101.17 ops/ms)
Float Multiply (1000 ops): 11036 μs (90.61 ops/ms)
Square Root (200 ops): 8756 μs (22.84 ops/ms)
Sin/Cos (100 ops): 27024 μs (3.70 ops/ms)

========================================
CPU: STRING OPERATIONS
========================================
Arduino String (heap stress) - Concatenation (3000 ops): 20368 μs (147.29 ops/ms)
Arduino String (heap stress) - Comparison (3000 ops): 28124 μs (106.67 ops/ms)
Arduino String (heap stress) - Int to String (1000 ops): 67236 μs (14.87 ops/ms)
snprintf (fixed buffer, 1000 ops): 70952 μs (14.09 ops/ms)

========================================
CPU: STRESS TEST with Temperature
========================================
Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 34400 iterations in 10018 ms
Performance: 3.43 iterations/ms

========================================
MEMORY: SRAM READ/WRITE
========================================
Read checksum: 326400
Random checksum: 261120
Sequential Write (7680 ops): 5000 μs (1536.00 ops/ms)
Sequential Read (2560 ops): 5244 μs (488.18 ops/ms)
Random Access (2048 ops): 5444 μs (median 376.19 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 256 byte buffers (2 KB RAM)
memcpy (51200 bytes): 23088 μs (2.22 MB/s)
memset (51200 bytes): 19856 μs (2.58 MB/s)
RAM Write Bandwidth: 3.45 MB/s
RAM Read Bandwidth: 1.98 MB/s

========================================
MEMORY: EEPROM
========================================
EEPROM Size: 1024 bytes
Hardware Write (64 bytes): 213700 μs (0.30 ops/ms)
Read (64 bytes): 224 μs (285.71 ops/ms)
Read checksum: 2016

========================================
I/O: DIGITAL PIN OPERATIONS
========================================
digitalWrite() (2000 ops): 9184 μs (median 217.77 ops/ms, 5 trials)
Direct Port (6000 ops): 6804 μs (median 881.83 ops/ms, 5 trials)
Speedup: 4.05x faster

========================================
I/O: ANALOG OPERATIONS
========================================
analogRead() (167 ops): 20064 μs (8.32 ops/ms)
ADC average: 592
analogWrite() (1800 ops): 20004 μs (89.98 ops/ms)

========================================
I/O: SERIAL COMMUNICATION
========================================
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 10696 μs (median 17.76 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 5344 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 64.85% (buffered, won't block)

========================================
STORAGE: Flash Information
========================================
Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions
========================================
Checksum: 254059.29
atan2() (100 ops): 20044 μs (4.99 ops/ms)
log() (100 ops): 15980 μs (6.26 ops/ms)
exp() (100 ops): 21832 μs (4.58 ops/ms)
pow() (100 ops): 34516 μs (2.90 ops/ms)
fmod() (1000 ops): 27688 μs (36.12 ops/ms)

========================================
TIMING: millis() and micros() Precision
========================================
millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 4 μs (detected after 2 reads)
Minimum step size (100 samples): 4 μs
Note: AVR micros() typically advances in 4 μs steps
micros() 1ms test: 1108 μs (±108 μs error)

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test
========================================
Testing shallow recursion (2 KB RAM)
Recursion test (20 deep): PASS
Successfully executed 20 nested function calls
Estimated stack usage: ~600 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
BENCHMARK COMPLETE!
========================================
Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.
========================================

Multiduino:

========================================
UNIVERSAL ARDUINO BENCHMARK SUITE

========================================
SYSTEM INFORMATION

Board: Multiduino
CPU Frequency: 16 MHz
Features: RTC (DS1307)
Free RAM: 679 bytes
Total RAM: 2 KB
Compile Date: Jan 29 2026 20:04:50

========================================
CPU: INTEGER OPERATIONS

Checksum: 49995000
Checksum: 1243496233
Checksum: 100
Addition (10000 ops): 101728 μs (98.30 ops/ms)
Multiplication (200 ops): 6468 μs (30.92 ops/ms)
Division (200 ops): 8084 μs (24.74 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS

Checksum: 3141.60
Checksum: 1.11
Checksum: 1322.93
Checksum: 129.92
Float Addition (1000 ops): 9884 μs (101.17 ops/ms)
Float Multiply (1000 ops): 11032 μs (90.65 ops/ms)
Square Root (200 ops): 8760 μs (22.83 ops/ms)
Sin/Cos (100 ops): 27020 μs (3.70 ops/ms)

========================================
CPU: STRING OPERATIONS

Arduino String (heap stress) - Concatenation (3000 ops): 20368 μs (147.29 ops/ms)
Arduino String (heap stress) - Comparison (3000 ops): 28124 μs (106.67 ops/ms)
Arduino String (heap stress) - Int to String (1000 ops): 67232 μs (14.87 ops/ms)
snprintf (fixed buffer, 1000 ops): 70952 μs (14.09 ops/ms)

========================================
CPU: STRESS TEST with Temperature

Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 34400 iterations in 10019 ms
Performance: 3.43 iterations/ms

========================================
MEMORY: SRAM READ/WRITE

Read checksum: 326400
Random checksum: 261120
Sequential Write (7680 ops): 5000 μs (1536.00 ops/ms)
Sequential Read (2560 ops): 5244 μs (488.18 ops/ms)
Random Access (2048 ops): 5444 μs (median 376.19 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 256 byte buffers (2 KB RAM)
memcpy (51200 bytes): 23088 μs (2.22 MB/s)
memset (51200 bytes): 19864 μs (2.58 MB/s)
RAM Write Bandwidth: 3.46 MB/s
RAM Read Bandwidth: 1.98 MB/s

========================================
MEMORY: EEPROM

EEPROM Size: 1024 bytes
Hardware Write (64 bytes): 214984 μs (0.30 ops/ms)
Read (64 bytes): 224 μs (285.71 ops/ms)
Read checksum: 2016

========================================
I/O: DIGITAL PIN OPERATIONS

digitalWrite() (2000 ops): 9184 μs (median 217.77 ops/ms, 5 trials)
Direct Port (6000 ops): 6804 μs (median 881.83 ops/ms, 5 trials)
Speedup: 4.05x faster

========================================
I/O: ANALOG OPERATIONS

analogRead() (167 ops): 20064 μs (8.32 ops/ms)
ADC average: 631
analogWrite() (1799 ops): 20000 μs (89.95 ops/ms)

========================================
I/O: SERIAL COMMUNICATION

01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 10692 μs (median 17.77 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 5360 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 64.83% (buffered, won't block)

========================================
STORAGE: Flash Information

Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions

Checksum: 254059.29
atan2() (100 ops): 20036 μs (4.99 ops/ms)
log() (100 ops): 15980 μs (6.26 ops/ms)
exp() (100 ops): 21832 μs (4.58 ops/ms)
pow() (100 ops): 34520 μs (2.90 ops/ms)
fmod() (1000 ops): 27688 μs (36.12 ops/ms)

========================================
TIMING: millis() and micros() Precision

millis() 1-second test: 999 ms (±1 ms error)
micros() resolution: 4 μs (detected after 1 reads)
Minimum step size (100 samples): 4 μs
Note: AVR micros() typically advances in 4 μs steps
micros() 1ms test: 1112 μs (±112 μs error)

Clock accuracy: 99.90%

========================================
MEMORY: Stack Depth Test

Testing shallow recursion (2 KB RAM)
Recursion test (20 deep): PASS
Successfully executed 20 nested function calls
Estimated stack usage: ~600 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
RTC BENCHMARK (DS1307)

RTC initialized successfully
Current Time: 2026/01/29 20:04:40

Test: RTC Read Speed
Reads: 915 in 1000.92 ms
Speed: 0.91 reads/ms
Time per read: 1093.90 μs
Checksum: 0x545C48F

Test: RTC Write Speed (Time Adjust)
Writes: 1013 in 1000.38 ms
Speed: 1.01 writes/ms
Time per write: 987.54 μs

Test: NVRAM Read/Write (56 bytes)
NVRAM Writes: 2912 bytes in 1017.51 ms
Speed: 2.86 bytes/ms
NVRAM Reads: 2184 bytes in 1010.11 ms
Speed: 2.16 bytes/ms
Checksum: 0xEA9C

RTC benchmarks complete

========================================
BENCHMARK COMPLETE!

Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.

Nano:



========================================
  UNIVERSAL ARDUINO BENCHMARK SUITE
========================================


========================================
SYSTEM INFORMATION
========================================
Board: Arduino Nano
CPU Frequency: 16 MHz
Free RAM: 919 bytes
Total RAM: 2 KB
Compile Date: Jan 29 2026 20:06:44

========================================
CPU: INTEGER OPERATIONS
========================================
Checksum: 49995000
Checksum: 1243496233
Checksum: 100
Addition (10000 ops): 101720 μs (98.31 ops/ms)
Multiplication (200 ops): 6468 μs (30.92 ops/ms)
Division (200 ops): 8084 μs (24.74 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS
========================================
Checksum: 3141.60
Checksum: 1.11
Checksum: 1322.93
Checksum: 129.92
Float Addition (1000 ops): 9884 μs (101.17 ops/ms)
Float Multiply (1000 ops): 11032 μs (90.65 ops/ms)
Square Root (200 ops): 8748 μs (22.86 ops/ms)
Sin/Cos (100 ops): 27024 μs (3.70 ops/ms)

========================================
CPU: STRING OPERATIONS
========================================
Arduino String (heap stress) - Concatenation (3000 ops): 20368 μs (147.29 ops/ms)
Arduino String (heap stress) - Comparison (3000 ops): 28124 μs (106.67 ops/ms)
Arduino String (heap stress) - Int to String (1000 ops): 67232 μs (14.87 ops/ms)
snprintf (fixed buffer, 1000 ops): 70956 μs (14.09 ops/ms)

========================================
CPU: STRESS TEST with Temperature
========================================
Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 34400 iterations in 10017 ms
Performance: 3.43 iterations/ms

========================================
MEMORY: SRAM READ/WRITE
========================================
Read checksum: 326400
Random checksum: 261120
Sequential Write (7936 ops): 5164 μs (1536.79 ops/ms)
Sequential Read (2560 ops): 5228 μs (489.67 ops/ms)
Random Access (2048 ops): 5444 μs (median 376.19 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 256 byte buffers (2 KB RAM)
memcpy (51200 bytes): 23096 μs (2.22 MB/s)
memset (51200 bytes): 19852 μs (2.58 MB/s)
RAM Write Bandwidth: 3.46 MB/s
RAM Read Bandwidth: 1.98 MB/s

========================================
MEMORY: EEPROM
========================================
EEPROM Size: 1024 bytes
Hardware Write (64 bytes): 200784 μs (0.32 ops/ms)
Read (64 bytes): 232 μs (275.86 ops/ms)
Read checksum: 2016

========================================
I/O: DIGITAL PIN OPERATIONS
========================================
digitalWrite() (2000 ops): 9184 μs (median 217.77 ops/ms, 5 trials)
Direct Port (6000 ops): 6804 μs (median 881.83 ops/ms, 5 trials)
Speedup: 4.05x faster

========================================
I/O: ANALOG OPERATIONS
========================================
analogRead() (167 ops): 20064 μs (8.32 ops/ms)
ADC average: 527
analogWrite() (1799 ops): 20004 μs (89.93 ops/ms)

========================================
I/O: SERIAL COMMUNICATION
========================================
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 10696 μs (median 17.76 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 5360 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 64.85% (buffered, won't block)

========================================
STORAGE: Flash Information
========================================
Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions
========================================
Checksum: 254059.29
atan2() (100 ops): 20044 μs (4.99 ops/ms)
log() (100 ops): 15972 μs (6.26 ops/ms)
exp() (100 ops): 21840 μs (4.58 ops/ms)
pow() (100 ops): 34508 μs (2.90 ops/ms)
fmod() (1000 ops): 27688 μs (36.12 ops/ms)

========================================
TIMING: millis() and micros() Precision
========================================
millis() 1-second test: 1001 ms (±1 ms error)
micros() resolution: 4 μs (detected after 1 reads)
Minimum step size (100 samples): 4 μs
Note: AVR micros() typically advances in 4 μs steps
micros() 1ms test: 1116 μs (±116 μs error)

Clock accuracy: 99.90%

========================================
MEMORY: Stack Depth Test
========================================
Testing shallow recursion (2 KB RAM)
Recursion test (20 deep): PASS
Successfully executed 20 nested function calls
Estimated stack usage: ~600 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
BENCHMARK COMPLETE!
========================================
Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.
========================================

Uno R4 Wifi:



========================================
  UNIVERSAL ARDUINO BENCHMARK SUITE
========================================


========================================
SYSTEM INFORMATION
========================================
Board: Arduino Uno R4 WiFi
MCU: Renesas RA4M1 (ARM Cortex-M4)
CPU Frequency: 48 MHz
Features: WiFi (ESP32-S3), 12x8 LED Matrix
Free RAM: 32 KB (RA4M1)
Compile Date: Jan 29 2026 20:07:38

========================================
CPU: INTEGER OPERATIONS
========================================
Checksum: 49995000
Checksum: 1695432965
Checksum: 100
Addition (10000 ops): 2931 μs (3411.80 ops/ms)
Multiplication (15900 ops): 5023 μs (3165.44 ops/ms)
Division (1900 ops): 5042 μs (376.83 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS
========================================
Checksum: 3141.60
Checksum: 1.11
Checksum: 27119.83
Checksum: 1169.32
Float Addition (1000 ops): 151 μs (6622.52 ops/ms)
Float Multiply (1000 ops): 172 μs (5813.95 ops/ms)
Square Root (4100 ops): 5064 μs (809.64 ops/ms)
Sin/Cos (900 ops): 5021 μs (179.25 ops/ms)

========================================
CPU: STRING OPERATIONS
========================================
Arduino String (heap stress) - Concatenation (15600 ops): 50050 μs (311.69 ops/ms)
Arduino String (heap stress) - Comparison (16000 ops): 52859 μs (302.69 ops/ms)
Arduino String (heap stress) - Int to String (4000 ops): 52512 μs (76.17 ops/ms)
snprintf (fixed buffer, 3000 ops): 56166 μs (53.41 ops/ms)

========================================
CPU: STRESS TEST with Temperature
========================================
Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 768800 iterations in 10000 ms
Performance: 76.88 iterations/ms

========================================
MEMORY: SRAM READ/WRITE
========================================
Read checksum: 3264000
Random checksum: 2676480
Sequential Write (37376 ops): 5028 μs (7433.57 ops/ms)
Sequential Read (25600 ops): 5038 μs (5081.38 ops/ms)
Random Access (20992 ops): 5008 μs (median 4191.69 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 1 KB buffers (32 KB RAM)
memcpy (102400 bytes): 17161 μs (5.97 MB/s)
memset (102400 bytes): 12871 μs (7.96 MB/s)
RAM Write Bandwidth: 27.26 MB/s
RAM Read Bandwidth: 21.24 MB/s

========================================
MEMORY: EEPROM
========================================
EEPROM Size: 8192 bytes
Hardware Write (64 bytes): 40614 μs (1.58 ops/ms)
Read (64 bytes): 1690 μs (37.87 ops/ms)
Read checksum: 2016

========================================
I/O: DIGITAL PIN OPERATIONS
========================================
digitalWrite() (2000 ops): 1592 μs (median 1256.28 ops/ms, 5 trials)

========================================
I/O: ANALOG OPERATIONS
========================================
analogRead() (2093 ops): 50004 μs (41.86 ops/ms)
ADC average: 192
analogWrite() (1800 ops): 50025 μs (35.98 ops/ms)

========================================
I/O: SERIAL COMMUNICATION
========================================
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 16432 μs (median 11.56 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 74 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 99.63% (buffered, won't block)

========================================
STORAGE: Flash Information
========================================
Flash info not available on this platform

========================================
DISPLAY: LED Matrix (Uno R4)
========================================
12x8 LED Matrix Available: YES
Running LED animation test...
Blink animation (20 cycles): 2000 ms
Pattern switching (100 frames): 621 μs (161.03 ops/ms)
Bitmap rendering (50 frames): 1887 μs (26.50 ops/ms)

========================================
WIRELESS: WiFi CAPABILITIES
========================================
WiFi Available: YES (ESP32-S3 via WiFiS3)
MAC Address: 50:59:6F:FA:12:F4
Scanning networks... 1 networks found
Strongest 3 networks:
  1: Telstra63E7E3 (-84 dBm)

========================================
ADVANCED MATH: Transcendental Functions
========================================
Checksum: 254059.42
atan2() (100 ops): 595 μs (168.07 ops/ms)
log() (100 ops): 2676 μs (37.37 ops/ms)
exp() (100 ops): 2743 μs (36.46 ops/ms)
pow() (100 ops): 5800 μs (17.24 ops/ms)
fmod() (1000 ops): 4583 μs (218.20 ops/ms)

========================================
TIMING: millis() and micros() Precision
========================================
millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 2 μs (detected after 1 reads)
Minimum step size (100 samples): 2 μs
micros() 1ms test: 1050 μs (±50 μs error)

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test
========================================
Testing moderate recursion (32 KB RAM)
Recursion test (100 deep): PASS
Successfully executed 100 nested function calls
Note: Actual stack usage varies by compiler and optimization.

========================================
CRYPTO: SoftwareATSE (Uno R4 WiFi)
========================================
Initializing SoftwareATSE...
SoftwareATSE initialized successfully!

--- Public Key Generation ---
SoftwareATSE: Public key generation (ms): 195
  Rate: 5.128 keys/sec

--- Secure Storage Operations ---
Config write (µs): 2
  (ms): 0.002
  Write speed: 128000000.00 bytes/sec

--- EC Signing ---
EC signing (avg ms/op): 193.711
  Rate: 5.16 ops/sec
  Successful operations: 10/10

--- Secure Random Number Generator ---
RNG checksum: 646383
Secure RNG throughput: 9124.43 bytes/sec
  Total bytes generated: 5120
  Time: 561.13 ms
  Successful reads: 20/20
Distribution test (first 1000 bytes):
  Bin 0: 241 (24.1%)
  Bin 1: 243 (24.3%)
  Bin 2: 262 (26.2%)
  Bin 3: 254 (25.4%)
  (Ideal: 25% each bin)

SoftwareATSE benchmarks complete

========================================
BENCHMARK COMPLETE!
========================================
Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.
========================================

Xiao RP2040:



========================================
  UNIVERSAL ARDUINO BENCHMARK SUITE
========================================


========================================
SYSTEM INFORMATION
========================================
Board: SEEED_XIAO_RP2040
CPU Frequency: 200 MHz
Free RAM: ~264 KB (RP2040)
Compile Date: Jan 29 2026 20:09:18

========================================
CPU: INTEGER OPERATIONS
========================================
Checksum: 49995000
Checksum: 2827298069
Checksum: 100
Addition (10000 ops): 779 μs (12836.97 ops/ms)
Multiplication (17900 ops): 5026 μs (3561.48 ops/ms)
Division (13000 ops): 5020 μs (2589.64 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS
========================================
Checksum: 3141.60
Checksum: 1.11
Checksum: 32411.47
Checksum: 909.47
Float Addition (1000 ops): 457 μs (2188.18 ops/ms)
Float Multiply (1000 ops): 379 μs (2638.52 ops/ms)
Square Root (4900 ops): 5098 μs (961.16 ops/ms)
Sin/Cos (700 ops): 5174 μs (135.29 ops/ms)

========================================
CPU: STRING OPERATIONS
========================================
Arduino String (heap stress) - Concatenation (5400 ops): 5022 μs (1075.27 ops/ms)
Arduino String (heap stress) - Comparison (8000 ops): 5467 μs (1463.33 ops/ms)
Arduino String (heap stress) - Int to String (1000 ops): 6816 μs (146.71 ops/ms)
snprintf (fixed buffer, 1000 ops): 8868 μs (112.76 ops/ms)

========================================
CPU: STRESS TEST with Temperature
========================================
Start Temperature: 28.07 °C
Running intensive computation for 10 seconds...
........................................
Stress test complete: 3541900 iterations in 10000 ms
Performance: 354.19 iterations/ms

Final Temperature: 29.95 °C
Total Temperature Gain: +1.87 °C
✓ Minimal temperature increase - good thermal performance

========================================
MEMORY: SRAM READ/WRITE
========================================
Read checksum: 11293440
Random checksum: 9628800
Sequential Write (96512 ops): 5007 μs (19275.41 ops/ms)
Sequential Read (88576 ops): 5009 μs (17683.37 ops/ms)
Random Access (75520 ops): 5015 μs (median 15058.82 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 4 KB buffers (264 KB RAM)
memcpy (409600 bytes): 1724 μs (237.59 MB/s)
memset (409600 bytes): 1074 μs (381.38 MB/s)
RAM Write Bandwidth: 99.08 MB/s
RAM Read Bandwidth: 79.70 MB/s

========================================
I/O: DIGITAL PIN OPERATIONS
========================================
digitalWrite() (2000 ops): 866 μs (median 2309.47 ops/ms, 5 trials)
Direct Register (248000 ops): 5018 μs (median 49422.08 ops/ms, 5 trials)
Speedup: 21.40x faster

========================================
I/O: ANALOG OPERATIONS
========================================
analogRead() (1199 ops): 5000 μs (239.80 ops/ms)
ADC average: 233
analogWrite() (2201 ops): 5001 μs (440.11 ops/ms)

========================================
I/O: SERIAL COMMUNICATION
========================================
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 941 μs (median 201.91 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 11 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 5.71% (buffered, won't block)

========================================
STORAGE: Flash Information
========================================
Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions
========================================
Checksum: 254059.42
atan2() (100 ops): 454 μs (220.26 ops/ms)
log() (100 ops): 472 μs (211.86 ops/ms)
exp() (100 ops): 398 μs (251.26 ops/ms)
pow() (100 ops): 1191 μs (83.96 ops/ms)
fmod() (1000 ops): 1938 μs (516.00 ops/ms)

========================================
TIMING: millis() and micros() Precision
========================================
millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 1 μs (detected after 1 reads)
Minimum step size (100 samples): 1 μs
micros() 1ms test: 1001 μs (±1 μs error)

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test
========================================
Testing deep recursion (264 KB RAM)
Recursion test (300 deep): PASS
Successfully executed 300 nested function calls
Estimated stack usage: ~12000 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
CRYPTO: SHA1
========================================
Example digests:
SHA1:a9993e364706816aba3e25717850c26c9cd0d89d
SHA1:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Checksum: 35400
SHA1 String (40 ops): 5849 μs (6.84 ops/ms)
SHA1 Buffer (200 ops): 5173 μs (38.66 ops/ms)

========================================
MULTI-CORE: Parallel Performance
========================================
RP2040 Dual-Core Test
Running dual-core workload for 1 second...
Core 0 iterations: 1784891
Core 1 iterations: 8058354
Total iterations: 9843245
Scaling efficiency: 1.22x

========================================
BENCHMARK COMPLETE!
========================================
Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.
========================================

ESP32 Dev Module:



========================================
  UNIVERSAL ARDUINO BENCHMARK SUITE
========================================


========================================
SYSTEM INFORMATION
========================================
Board: ESP32
Chip Model: ESP32-D0WD-V3
Chip Revision: 301
CPU Frequency: 240 MHz
Cores: 2
SDK Version: v5.5.2-249-gf56bea3d1f
Free RAM: 199 KB
Total Heap: 240 KB
Min Free Heap: 197 KB
Compile Date: Jan 29 2026 20:11:03

========================================
CPU: INTEGER OPERATIONS
========================================
Checksum: 49995000
Checksum: 2821416005
Checksum: 100
Addition (10000 ops): 1218 μs (8210.18 ops/ms)
Multiplication (30300 ops): 5004 μs (6055.16 ops/ms)
Division (9600 ops): 5013 μs (1915.02 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS
========================================
Checksum: 3141.60
Checksum: 1.11
Checksum: 70775.90
Checksum: 4287.52
Float Addition (1000 ops): 56 μs (17857.14 ops/ms)
Float Multiply (1000 ops): 56 μs (17857.14 ops/ms)
Square Root (10700 ops): 5038 μs (2123.86 ops/ms)
Sin/Cos (3300 ops): 5039 μs (654.89 ops/ms)

========================================
CPU: STRING OPERATIONS
========================================
Arduino String (heap stress) - Concatenation (4500 ops): 5089 μs (884.26 ops/ms)
Arduino String (heap stress) - Comparison (7000 ops): 5260 μs (1330.80 ops/ms)
Arduino String (heap stress) - Int to String (2000 ops): 7873 μs (254.03 ops/ms)
snprintf (fixed buffer, 1000 ops): 5237 μs (190.95 ops/ms)

========================================
CPU: STRESS TEST with Temperature
========================================
Start Temperature: 64.44 °C
Running intensive computation for 10 seconds...

Stress test complete: 3477800 iterations in 10000 ms
Performance: 347.78 iterations/ms

Final Temperature: 65.56 °C
Total Temperature Gain: +1.11 °C
✓ Minimal temperature increase - good thermal performance

========================================
MEMORY: SRAM READ/WRITE
========================================
Read checksum: 9041280
Random checksum: 9041280
Sequential Write (151040 ops): 5008 μs (30159.74 ops/ms)
Sequential Read (70912 ops): 5009 μs (14156.92 ops/ms)
Random Access (70912 ops): 5011 μs (median 14151.27 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 8 KB buffers (large heap)
memcpy (819200 bytes): 2155 μs (380.14 MB/s)
memset (819200 bytes): 1091 μs (750.87 MB/s)
RAM Write Bandwidth: 159.16 MB/s
RAM Read Bandwidth: 73.54 MB/s

========================================
MEMORY: EEPROM
========================================
EEPROM Size: 512 bytes
RAM Buffer Write (64 bytes): 15 μs (4266.67 ops/ms)
Flash Commit Test (10 commits):
  Min: 2580 μs (2.58 ms)
  Median: 2602 μs (2.60 ms)
  Max: 25975 μs (25.98 ms) ← Includes erase
Read (64 bytes): 13 μs (4923.08 ops/ms)
Read checksum: 16320

========================================
I/O: DIGITAL PIN OPERATIONS
========================================
digitalWrite() (2000 ops): 1101 μs (median 1816.53 ops/ms, 5 trials)
Direct Register (96000 ops): 5086 μs (median 18875.34 ops/ms, 5 trials)
Speedup: 10.39x faster

========================================
I/O: ANALOG OPERATIONS
========================================
analogRead() (108 ops): 5004 μs (21.58 ops/ms)
ADC average: 136
PWM setup: 295 μs (3.39 ops/ms)
PWM duty update (13 ops): 5097 μs (2.55 ops/ms)

========================================
I/O: SERIAL COMMUNICATION
========================================
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 11843 μs (median 16.04 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 4466 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 71.81% (buffered, won't block)

========================================
STORAGE: Flash Information
========================================
Flash Size: 4096 KB
Flash Speed: 80 MHz
Sketch Size: 1622 KB
Free Sketch Space: 3072 KB

========================================
WIRELESS: WiFi CAPABILITIES
========================================
WiFi Available: YES (Native)
MAC Address: 38:18:2B:83:3A:98
Scanning networks... 1 networks found
Strongest 3 networks:
  1: Telstra63E7E3 (-90 dBm)

========================================
WIRELESS: Bluetooth LE
========================================
BLE Available: YES
Initializing BLE...
Scanning for BLE devices (5 sec)... 1 devices found
Discovered devices:
  1: Unknown [5d:fa:a5:52:6a:32] RSSI: -51 dBm

========================================
ADVANCED MATH: Transcendental Functions
========================================
Checksum: 254059.42
atan2() (100 ops): 194 μs (515.46 ops/ms)
log() (100 ops): 131 μs (763.36 ops/ms)
exp() (100 ops): 174 μs (574.71 ops/ms)
pow() (100 ops): 1069 μs (93.55 ops/ms)
fmod() (1000 ops): 914 μs (1094.09 ops/ms)

========================================
TIMING: millis() and micros() Precision
========================================
millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 2 μs (detected after 2 reads)
Minimum step size (100 samples): 1 μs
micros() 1ms test: 1003 μs (±3 μs error)

ESP32 CPU Cycle Counter:
CPU Frequency: 240 MHz
Cycles elapsed: 240303
micros() elapsed: 1001 μs
Expected cycles: 240240
Timing jitter: 0.03%

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test
========================================
Testing deep recursion (large heap)
Recursion test (500 deep): PASS
Successfully executed 500 nested function calls
Estimated stack usage: ~20000 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
MULTI-CORE: Parallel Performance
========================================
ESP32 Dual-Core Test
Core 0 iterations: 5794438
Core 1 iterations: 5803583
Total iterations: 11598021
Core balance: 99.84%

========================================
CRYPTO: Hashing (ESP32)
========================================
Example digests:
MD5: 9699e36529556c9352c707c6efad30dc
SHA1: 1ff043261f4af33c1e4ce68ca2b2ce77a8bf4cf3
SHA256: d2102eb1ca93268fd3a1dc13b92cb9dc87ab169934952950e2c06e19dc9797a2
SHA512: 20e72a61af48834e18f1c94805d8d3b855188f21567fcc6a4da18d410beca7e9058e2f3c4adb1d35ca1c6f71c469d3b548febf090af55dc935c3b387a7206dec
SHA3-256: not available in this build
...running HEX encode
...running MD5
...running SHA1
...running SHA256
...running SHA512
...running PBKDF2-HMAC-SHA256
Checksum: 71902
HEX encode (20 ops): 9370 μs (2.13 ops/ms)
MD5 (310 ops): 5077 μs (61.06 ops/ms)
SHA1 (90 ops): 5068 μs (17.76 ops/ms)
SHA256 (90 ops): 5316 μs (16.93 ops/ms)
SHA512 (80 ops): 5417 μs (14.77 ops/ms)
PBKDF2-HMAC-SHA256 (1 ops): 53872 μs (0.02 ops/ms)
  Iterations per op: 500

========================================
CRYPTO: Hardware RNG
========================================
Using ESP32 hardware RNG
Checksum: 1891559710
Hardware RNG (1000 values): 544 μs (1838.24 values/ms)
Distribution (10000 samples):
  Bin 0: 2573 (25.7%)
  Bin 1: 2479 (24.8%)
  Bin 2: 2519 (25.2%)
  Bin 3: 2429 (24.3%)
(Ideal: 25% each bin)

========================================
BENCHMARK COMPLETE!
========================================
Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.
========================================

ESP32 Dev Module:



========================================
  UNIVERSAL ARDUINO BENCHMARK SUITE
========================================


========================================
SYSTEM INFORMATION
========================================
Board: ESP32
Chip Model: ESP32-D0WD-V3
Chip Revision: 301
CPU Frequency: 240 MHz
Cores: 2
SDK Version: v5.5.2-249-gf56bea3d1f
Free RAM: 199 KB
Total Heap: 240 KB
Min Free Heap: 197 KB
Compile Date: Jan 29 2026 20:11:03

========================================
CPU: INTEGER OPERATIONS
========================================
Checksum: 49995000
Checksum: 2821416005
Checksum: 100
Addition (10000 ops): 1218 μs (8210.18 ops/ms)
Multiplication (30300 ops): 5004 μs (6055.16 ops/ms)
Division (9600 ops): 5013 μs (1915.02 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS
========================================
Checksum: 3141.60
Checksum: 1.11
Checksum: 70775.90
Checksum: 4287.52
Float Addition (1000 ops): 56 μs (17857.14 ops/ms)
Float Multiply (1000 ops): 56 μs (17857.14 ops/ms)
Square Root (10700 ops): 5038 μs (2123.86 ops/ms)
Sin/Cos (3300 ops): 5039 μs (654.89 ops/ms)

========================================
CPU: STRING OPERATIONS
========================================
Arduino String (heap stress) - Concatenation (4500 ops): 5089 μs (884.26 ops/ms)
Arduino String (heap stress) - Comparison (7000 ops): 5260 μs (1330.80 ops/ms)
Arduino String (heap stress) - Int to String (2000 ops): 7873 μs (254.03 ops/ms)
snprintf (fixed buffer, 1000 ops): 5237 μs (190.95 ops/ms)

========================================
CPU: STRESS TEST with Temperature
========================================
Start Temperature: 64.44 °C
Running intensive computation for 10 seconds...

Stress test complete: 3477800 iterations in 10000 ms
Performance: 347.78 iterations/ms

Final Temperature: 65.56 °C
Total Temperature Gain: +1.11 °C
✓ Minimal temperature increase - good thermal performance

========================================
MEMORY: SRAM READ/WRITE
========================================
Read checksum: 9041280
Random checksum: 9041280
Sequential Write (151040 ops): 5008 μs (30159.74 ops/ms)
Sequential Read (70912 ops): 5009 μs (14156.92 ops/ms)
Random Access (70912 ops): 5011 μs (median 14151.27 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 8 KB buffers (large heap)
memcpy (819200 bytes): 2155 μs (380.14 MB/s)
memset (819200 bytes): 1091 μs (750.87 MB/s)
RAM Write Bandwidth: 159.16 MB/s
RAM Read Bandwidth: 73.54 MB/s

========================================
MEMORY: EEPROM
========================================
EEPROM Size: 512 bytes
RAM Buffer Write (64 bytes): 15 μs (4266.67 ops/ms)
Flash Commit Test (10 commits):
  Min: 2580 μs (2.58 ms)
  Median: 2602 μs (2.60 ms)
  Max: 25975 μs (25.98 ms) ← Includes erase
Read (64 bytes): 13 μs (4923.08 ops/ms)
Read checksum: 16320

========================================
I/O: DIGITAL PIN OPERATIONS
========================================
digitalWrite() (2000 ops): 1101 μs (median 1816.53 ops/ms, 5 trials)
Direct Register (96000 ops): 5086 μs (median 18875.34 ops/ms, 5 trials)
Speedup: 10.39x faster

========================================
I/O: ANALOG OPERATIONS
========================================
analogRead() (108 ops): 5004 μs (21.58 ops/ms)
ADC average: 136
PWM setup: 295 μs (3.39 ops/ms)
PWM duty update (13 ops): 5097 μs (2.55 ops/ms)

========================================
I/O: SERIAL COMMUNICATION
========================================
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 11843 μs (median 16.04 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 4466 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 71.81% (buffered, won't block)

========================================
STORAGE: Flash Information
========================================
Flash Size: 4096 KB
Flash Speed: 80 MHz
Sketch Size: 1622 KB
Free Sketch Space: 3072 KB

========================================
WIRELESS: WiFi CAPABILITIES
========================================
WiFi Available: YES (Native)
MAC Address: 38:18:2B:83:3A:98
Scanning networks... 1 networks found
Strongest 3 networks:
  1: Telstra63E7E3 (-90 dBm)

========================================
WIRELESS: Bluetooth LE
========================================
BLE Available: YES
Initializing BLE...
Scanning for BLE devices (5 sec)... 1 devices found
Discovered devices:
  1: Unknown [5d:fa:a5:52:6a:32] RSSI: -51 dBm

========================================
ADVANCED MATH: Transcendental Functions
========================================
Checksum: 254059.42
atan2() (100 ops): 194 μs (515.46 ops/ms)
log() (100 ops): 131 μs (763.36 ops/ms)
exp() (100 ops): 174 μs (574.71 ops/ms)
pow() (100 ops): 1069 μs (93.55 ops/ms)
fmod() (1000 ops): 914 μs (1094.09 ops/ms)

========================================
TIMING: millis() and micros() Precision
========================================
millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 2 μs (detected after 2 reads)
Minimum step size (100 samples): 1 μs
micros() 1ms test: 1003 μs (±3 μs error)

ESP32 CPU Cycle Counter:
CPU Frequency: 240 MHz
Cycles elapsed: 240303
micros() elapsed: 1001 μs
Expected cycles: 240240
Timing jitter: 0.03%

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test
========================================
Testing deep recursion (large heap)
Recursion test (500 deep): PASS
Successfully executed 500 nested function calls
Estimated stack usage: ~20000 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
MULTI-CORE: Parallel Performance
========================================
ESP32 Dual-Core Test
Core 0 iterations: 5794438
Core 1 iterations: 5803583
Total iterations: 11598021
Core balance: 99.84%

========================================
CRYPTO: Hashing (ESP32)
========================================
Example digests:
MD5: 9699e36529556c9352c707c6efad30dc
SHA1: 1ff043261f4af33c1e4ce68ca2b2ce77a8bf4cf3
SHA256: d2102eb1ca93268fd3a1dc13b92cb9dc87ab169934952950e2c06e19dc9797a2
SHA512: 20e72a61af48834e18f1c94805d8d3b855188f21567fcc6a4da18d410beca7e9058e2f3c4adb1d35ca1c6f71c469d3b548febf090af55dc935c3b387a7206dec
SHA3-256: not available in this build
...running HEX encode
...running MD5
...running SHA1
...running SHA256
...running SHA512
...running PBKDF2-HMAC-SHA256
Checksum: 71902
HEX encode (20 ops): 9370 μs (2.13 ops/ms)
MD5 (310 ops): 5077 μs (61.06 ops/ms)
SHA1 (90 ops): 5068 μs (17.76 ops/ms)
SHA256 (90 ops): 5316 μs (16.93 ops/ms)
SHA512 (80 ops): 5417 μs (14.77 ops/ms)
PBKDF2-HMAC-SHA256 (1 ops): 53872 μs (0.02 ops/ms)
  Iterations per op: 500

========================================
CRYPTO: Hardware RNG
========================================
Using ESP32 hardware RNG
Checksum: 1891559710
Hardware RNG (1000 values): 544 μs (1838.24 values/ms)
Distribution (10000 samples):
  Bin 0: 2573 (25.7%)
  Bin 1: 2479 (24.8%)
  Bin 2: 2519 (25.2%)
  Bin 3: 2429 (24.3%)
(Ideal: 25% each bin)

========================================
BENCHMARK COMPLETE!
========================================
Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.
========================================

Uno Q:

=== UNO Q DETECTED ===
Monitor initialized

========================================
UNIVERSAL ARDUINO BENCHMARK SUITE

========================================
SYSTEM INFORMATION

Board: Arduino Uno Q (MCU)
MCU: STM32U585 (ARM Cortex-M33)
MCU Frequency: 160 MHz
MCU Features: FPU, DSP, TrustZone
MCU RAM: 786 KB SRAM
MCU Flash: 2 MB
MCU RTOS: Zephyr

Linux MPU: Qualcomm QRB2210
MPU: Quad Cortex-A53 @ up to 2.0 GHz
MPU RAM: 2-4 GB
MPU Storage: 16 GB eMMC
MPU OS: Debian-based Linux

Communication: Arduino Bridge RPC (MCU<->Linux)
RPC Library: Arduino_RouterBridge (MessagePack)
Free RAM: Total RAM: 786 KB
Compile Date: Jan 29 2026 18:32:28

========================================
CPU: INTEGER OPERATIONS

Checksum: 49995000
Checksum: 2060603005
Checksum: 100
Addition (10000 ops): 814 μs (12285.01 ops/ms)
Multiplication (41300 ops): 5000 μs (8260.00 ops/ms)
Division (6800 ops): 5022 μs (1354.04 ops/ms)

--- DSP-Enhanced Integer Tests (Cortex-M33) ---
64-bit Multiply (32350 ops): 6467.41 ops/ms
64-bit Divide (6500 ops): 1291.22 ops/ms
MAC Operations (1000 ops): 108 μs (9259.26 ops/ms)
MAC Checksum: 1040516
Saturating Add (1000 ops): 96 μs (10416.67 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS

Checksum: 3141.60
Checksum: 1.11
Float Addition (1000 ops): 46 μs (21739.13 ops/ms)
Float Multiply (1000 ops): 46 μs (21739.13 ops/ms)
Sqrt/Sin/Cos: Skipped (Uno Q - no libm)

========================================
CPU: STRING OPERATIONS

Arduino String (heap stress) - Concatenation (62000 ops): 50052 μs (1238.71 ops/ms)
Arduino String (heap stress) - Comparison (52000 ops): 50235 μs (1035.13 ops/ms)
Arduino String (heap stress) - Int to String (7000 ops): 56488 μs (123.92 ops/ms)
snprintf (fixed buffer, 10000 ops): 51365 μs (194.69 ops/ms)

========================================
CPU: STRESS TEST with Temperature

Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 44726100 iterations in 10000 ms
Performance: 4472.61 iterations/ms

========================================
MEMORY: SRAM READ/WRITE

Read checksum: 9367680
Random checksum: 10281600
Sequential Write (100864 ops): 5009 μs (20136.55 ops/ms)
Sequential Read (73472 ops): 5015 μs (14650.45 ops/ms)
Random Access (80640 ops): 5005 μs (median 16111.89 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 8 KB buffers (786 KB SRAM)
memcpy (819200 bytes): 25638 μs (31.95 MB/s)
memset (819200 bytes): 30757 μs (26.63 MB/s)
RAM Write Bandwidth: 91.39 MB/s
RAM Read Bandwidth: 79.98 MB/s

========================================
I/O: DIGITAL PIN OPERATIONS

digitalWrite() (2000 ops): 558 μs (median 3584.23 ops/ms, 5 trials)

========================================
I/O: ANALOG OPERATIONS

analogRead() (1455 ops): 50007 μs (29.10 ops/ms)
ADC average: 290

========================================
I/O: SERIAL COMMUNICATION

01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 493358 μs (median 0.39 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 1 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 2991.32% (CPU-bound)

========================================
STORAGE: Flash Information

Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions

Uno Q: libm not available (sin/cos/log/exp/pow/atan2)
Skipping advanced math benchmark

========================================
TIMING: millis() and micros() Precision

millis() 1-second test: 1001 ms (±1 ms error)
micros() resolution: 2 μs (detected after 1 reads)
Minimum step size (100 samples): 1 μs
micros() 1ms test: 1100 μs (±100 μs error)

Clock accuracy: 99.90%

========================================
MEMORY: Stack Depth Test

Testing deep recursion (786 KB SRAM)
Recursion test (500 deep): PASS
Successfully executed 500 nested function calls
Estimated stack usage: ~20000 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
CRYPTO: Hardware RNG

Using STM32U585 hardware RNG (Zephyr)
Checksum: 915988530
Hardware RNG (1000 values): 121843 μs (8.21 values/ms)
Distribution (10000 samples):
Bin 0: 2509 (25.1%)
Bin 1: 2431 (24.3%)
Bin 2: 2496 (25.0%)
Bin 3: 2564 (25.6%)
(Ideal: 25% each bin)

========================================
BENCHMARK COMPLETE!

Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.

I am working on a table, though so far I have posted the direct serial monitor outputs

Wov, it's interesting!

I have some 3rd party arduino boards for testing... as WinnerMicro W800 or W806. I would try to benchmark them and show the results here.

It looks like there are some bits missing when I compile for an ESP32-C6:
#include "BenchmarkHelpers.h"
Here it stopped at the first error.

Crap. Sorry:

#ifndef BENCHMARK_HELPERS_H
#define BENCHMARK_HELPERS_H

// Benchmark helper functions compatible with older C++ standards
// Works with Arduino Uno (AVR), Uno Q (Zephyr/STM32U585), and other boards

#include <Arduino.h>

struct MinDurationResult {
  uint32_t ops;
  unsigned long elapsedUs;
};

template<typename Func>
MinDurationResult runForAtLeastUs(unsigned long minUs, Func fn) {
  MinDurationResult result = {};
  unsigned long start = micros();
  unsigned long elapsed = 0;
  do {
    result.ops += fn();
#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)
    yield();
#endif
    elapsed = micros() - start;
  } while (elapsed < minUs);
  result.elapsedUs = elapsed;
  return result;
}

struct TimedLoopResult {
  unsigned long elapsedMicros;
  uint32_t iterations;
  uint32_t totalOps;
  float opsPerMs;
};

// Helper function for void return type
template<typename Func>
void runFuncVoid(Func& func, bool& shouldBreak) {
  func();
  shouldBreak = false;
}

// Helper function for non-void return type
template<typename Func>
void runFuncNonVoid(Func& func, bool& shouldBreak) {
  shouldBreak = !func();
}

// Simple type trait replacement for older C++
template<typename Func>
TimedLoopResult runTimedLoop(uint32_t minDurationMs, uint32_t opsPerIteration, Func func) {
  TimedLoopResult result = {};
  unsigned long start = micros();
  unsigned long elapsed = 0;
  do {
    // Just call the function - works for both void and non-void returns
    func();
    result.iterations++;
    result.totalOps += opsPerIteration;
#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)
    yield();
#endif
    elapsed = micros() - start;
  } while (elapsed < (minDurationMs * 1000UL));
  result.elapsedMicros = elapsed;
  result.opsPerMs = (result.totalOps * 1000.0f) / result.elapsedMicros;
  return result;
}

#endif

You may find some libraries need installing. If you can’t find them in library manager, shoot a message across…

No problems here, put the Benchmarkhelper in the code folder, compiled no problem.

Tom.... :smiley: :+1: :coffee: :australia:

Let me know what you run it on. It is a fun project, each “special” board with different features has me creating new ifdefs and writing code to benchmark those features!

OK. I've now got this for the ESP32-C6
I can't spend too much time debugging but I can certainly try some things that you suggest.

Compiling sketch...
"C:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp-rv32\\2507/bin/riscv32-esp-elf-g++" -MMD -c "@C:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.5-8410210c-v2\\esp32c6/flags/cpp_flags" -Wall -Wextra -Os -Werror=return-type -DF_CPU=160000000L -DARDUINO=10607 -DARDUINO_ESP32C6_DEV -DARDUINO_ARCH_ESP32 "-DARDUINO_BOARD=\"ESP32C6_DEV\"" "-DARDUINO_VARIANT=\"esp32c6\"" -DARDUINO_PARTITION_default "-DARDUINO_HOST_OS=\"windows\"" "-DARDUINO_FQBN=\"esp32:esp32:esp32c6:UploadSpeed=256000,CDCOnBoot=cdc,CPUFreq=160,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=none,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default\"" -DESP32=ESP32 -DCORE_DEBUG_LEVEL=0 -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 "@C:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.5-8410210c-v2\\esp32c6/flags/defines" "-IC:\\Users\\6v6gt\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\\sketch_jan29a" -iprefix "C:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.5-8410210c-v2\\esp32c6/include/" "@C:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.5-8410210c-v2\\esp32c6/flags/includes" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.5-8410210c-v2\\esp32c6/qio_qspi/include" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.3.4\\cores\\esp32" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.3.4\\variants\\esp32c6" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.3.4\\libraries\\WiFi\\src" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.3.4\\libraries\\Network\\src" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.3.4\\libraries\\EEPROM\\src" "-IC:\\Users\\6v6gt\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.3.4\\libraries\\BLE\\src" "@C:\\Users\\6v6gt\\AppData\\Local\\arduino\\sketches\\185A6D58925566AB51DCAF14F9E3209C/build_opt.h" "@C:\\Users\\6v6gt\\AppData\\Local\\arduino\\sketches\\185A6D58925566AB51DCAF14F9E3209C/file_opts" "C:\\Users\\6v6gt\\AppData\\Local\\arduino\\sketches\\185A6D58925566AB51DCAF14F9E3209C\\sketch\\sketch_jan29a.ino.cpp" -o "C:\\Users\\6v6gt\\AppData\\Local\\arduino\\sketches\\185A6D58925566AB51DCAF14F9E3209C\\sketch\\sketch_jan29a.ino.cpp.o"
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino: In lambda function:
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:1378:33: error: no match for 'operator=' (operand types are 'volatile gpio_out_w1ts_reg_t' and 'unsigned int')
 1378 |           GPIO.out_w1ts = 1u << testPin;
      |                                 ^~~~~~~
In file included from C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:56:
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:51:3: note: candidate: 'constexpr gpio_out_w1ts_reg_t& gpio_out_w1ts_reg_t::operator=(const gpio_out_w1ts_reg_t&)'
   51 | } gpio_out_w1ts_reg_t;
      |   ^~~~~~~~~~~~~~~~~~~
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:51:3: note:   no known conversion for argument 1 from 'unsigned int' to 'const gpio_out_w1ts_reg_t&'
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:51:3: note: candidate: 'constexpr gpio_out_w1ts_reg_t& gpio_out_w1ts_reg_t::operator=(gpio_out_w1ts_reg_t&&)'
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:51:3: note:   no known conversion for argument 1 from 'unsigned int' to 'gpio_out_w1ts_reg_t&&'
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:1379:33: error: no match for 'operator=' (operand types are 'volatile gpio_out_w1tc_reg_t' and 'unsigned int')
 1379 |           GPIO.out_w1tc = 1u << testPin;
      |                                 ^~~~~~~
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:64:3: note: candidate: 'constexpr gpio_out_w1tc_reg_t& gpio_out_w1tc_reg_t::operator=(const gpio_out_w1tc_reg_t&)'
   64 | } gpio_out_w1tc_reg_t;
      |   ^~~~~~~~~~~~~~~~~~~
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:64:3: note:   no known conversion for argument 1 from 'unsigned int' to 'const gpio_out_w1tc_reg_t&'
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:64:3: note: candidate: 'constexpr gpio_out_w1tc_reg_t& gpio_out_w1tc_reg_t::operator=(gpio_out_w1tc_reg_t&&)'
C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\tools\esp32-arduino-libs\idf-release_v5.5-8410210c-v2\esp32c6/include/soc/esp32c6/register/soc/gpio_struct.h:64:3: note:   no known conversion for argument 1 from 'unsigned int' to 'gpio_out_w1tc_reg_t&&'
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:1381:26: error: 'volatile union gpio_out1_w1ts_reg_t' has no member named 'data'
 1381 |           GPIO.out1_w1ts.data = 1u << (testPin - 32);
      |                          ^~~~
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:1382:26: error: 'volatile union gpio_out1_w1tc_reg_t' has no member named 'data'
 1382 |           GPIO.out1_w1tc.data = 1u << (testPin - 32);
      |                          ^~~~
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino: In function 'int testRecursion(int)':
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:2600:3: warning: '++' expression of 'volatile'-qualified type is deprecated [-Wvolatile]
 2600 |   recursionCounter++;
      |   ^~~~~~~~~~~~~~~~
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino: In function 'void core0Task(void*)':
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:2693:7: warning: '++' expression of 'volatile'-qualified type is deprecated [-Wvolatile]
 2693 |       core0Count++;
      |       ^~~~~~~~~~
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino: In function 'void core1Task(void*)':
C:\Users\6v6gt\AppData\Local\Temp\.arduinoIDE-unsaved2026029-17728-11ujzz.3h3aum\sketch_jan29a\sketch_jan29a.ino:2704:7: warning: '++' expression of 'volatile'-qualified type is deprecated [-Wvolatile]
 2704 |       core1Count++;
      |       ^~~~~~~~~~
Using library WiFi at version 3.3.4 in folder: C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.4\libraries\WiFi 
Using library Networking at version 3.3.4 in folder: C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.4\libraries\Network 
Using library EEPROM at version 3.3.4 in folder: C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.4\libraries\EEPROM 
Using library BLE at version 3.3.4 in folder: C:\Users\6v6gt\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.4\libraries\BLE 
exit status 1

Compilation error: no match for 'operator=' (operand types are 'volatile gpio_out_w1ts_reg_t' and 'unsigned int')

Legend! I’ll debug and push the new code to github.

Looks like a register issue…

This might be easier than reposting the code here?

trying downloading the code and reuploading.

If it tells you it exceeds available space, make sure you have HugeApp selected in board settings…

Hi, @outbackhut
Just ran it on a clone nano.

========================================
UNIVERSAL ARDUINO BENCHMARK SUITE

========================================
SYSTEM INFORMATION

Board: Arduino Nano
CPU Frequency: 16 MHz
Free RAM: 919 bytes
Total RAM: 2 KB
Compile Date: Jan 29 2026 21:29:07

========================================
CPU: INTEGER OPERATIONS

Checksum: 49995000
Checksum: 1243496233
Checksum: 100
Addition (10000 ops): 101720 μs (98.31 ops/ms)
Multiplication (200 ops): 6468 μs (30.92 ops/ms)
Division (200 ops): 8084 μs (24.74 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS

Checksum: 3141.60
Checksum: 1.11
Checksum: 1322.93
Checksum: 129.92
Float Addition (1000 ops): 9884 μs (101.17 ops/ms)
Float Multiply (1000 ops): 11032 μs (90.65 ops/ms)
Square Root (200 ops): 8748 μs (22.86 ops/ms)
Sin/Cos (100 ops): 27024 μs (3.70 ops/ms)

========================================
CPU: STRING OPERATIONS

Arduino String (heap stress) - Concatenation (3000 ops): 20368 μs (147.29 ops/ms)
Arduino String (heap stress) - Comparison (3000 ops): 28124 μs (106.67 ops/ms)
Arduino String (heap stress) - Int to String (1000 ops): 67232 μs (14.87 ops/ms)
snprintf (fixed buffer, 1000 ops): 70956 μs (14.09 ops/ms)

========================================
CPU: STRESS TEST with Temperature

Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 34400 iterations in 10017 ms
Performance: 3.43 iterations/ms

========================================
MEMORY: SRAM READ/WRITE

Read checksum: 326400
Random checksum: 261120
Sequential Write (7936 ops): 5164 μs (1536.79 ops/ms)
Sequential Read (2560 ops): 5228 μs (489.67 ops/ms)
Random Access (2048 ops): 5444 μs (median 376.19 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 256 byte buffers (2 KB RAM)
memcpy (51200 bytes): 23096 μs (2.22 MB/s)
memset (51200 bytes): 19852 μs (2.58 MB/s)
RAM Write Bandwidth: 3.46 MB/s
RAM Read Bandwidth: 1.98 MB/s

========================================
MEMORY: EEPROM

EEPROM Size: 1024 bytes
Hardware Write (64 bytes): 212080 μs (0.30 ops/ms)
Read (64 bytes): 232 μs (275.86 ops/ms)
Read checksum: 2016

========================================
I/O: DIGITAL PIN OPERATIONS

digitalWrite() (2000 ops): 9184 μs (median 217.77 ops/ms, 5 trials)
Direct Port (6000 ops): 6804 μs (median 881.83 ops/ms, 5 trials)
Speedup: 4.05x faster

========================================
I/O: ANALOG OPERATIONS

analogRead() (167 ops): 20064 μs (8.32 ops/ms)
ADC average: 368
analogWrite() (1799 ops): 20004 μs (89.93 ops/ms)

========================================
I/O: SERIAL COMMUNICATION

01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 10696 μs (median 17.76 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 5344 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 64.85% (buffered, won't block)

========================================
STORAGE: Flash Information

Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions

Checksum: 254059.29
atan2() (100 ops): 20040 μs (4.99 ops/ms)
log() (100 ops): 15976 μs (6.26 ops/ms)
exp() (100 ops): 21836 μs (4.58 ops/ms)
pow() (100 ops): 34512 μs (2.90 ops/ms)
fmod() (1000 ops): 27692 μs (36.11 ops/ms)

========================================
TIMING: millis() and micros() Precision

millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 4 μs (detected after 1 reads)
Minimum step size (100 samples): 4 μs
Note: AVR micros() typically advances in 4 μs steps
micros() 1ms test: 1112 μs (±112 μs error)

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test

Testing shallow recursion (2 KB RAM)
Recursion test (20 deep): PASS
Successfully executed 20 nested function calls
Estimated stack usage: ~600 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
BENCHMARK COMPLETE!

Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.

Tom.... :smiley: :+1: :coffee: :australia:

Hi, @outbackhut
A second clone Nano

========================================
UNIVERSAL ARDUINO BENCHMARK SUITE

========================================
SYSTEM INFORMATION

Board: Arduino Nano
CPU Frequency: 16 MHz
Free RAM: 919 bytes
Total RAM: 2 KB
Compile Date: Jan 29 2026 21:34:52

========================================
CPU: INTEGER OPERATIONS

Checksum: 49995000
Checksum: 1243496233
Checksum: 100
Addition (10000 ops): 101720 μs (98.31 ops/ms)
Multiplication (200 ops): 6468 μs (30.92 ops/ms)
Division (200 ops): 8084 μs (24.74 ops/ms)

========================================
CPU: FLOATING POINT OPERATIONS

Checksum: 3141.60
Checksum: 1.11
Checksum: 1322.93
Checksum: 129.92
Float Addition (1000 ops): 9884 μs (101.17 ops/ms)
Float Multiply (1000 ops): 11032 μs (90.65 ops/ms)
Square Root (200 ops): 8748 μs (22.86 ops/ms)
Sin/Cos (100 ops): 27024 μs (3.70 ops/ms)

========================================
CPU: STRING OPERATIONS

Arduino String (heap stress) - Concatenation (3000 ops): 20368 μs (147.29 ops/ms)
Arduino String (heap stress) - Comparison (3000 ops): 28124 μs (106.67 ops/ms)
Arduino String (heap stress) - Int to String (1000 ops): 67232 μs (14.87 ops/ms)
snprintf (fixed buffer, 1000 ops): 70956 μs (14.09 ops/ms)

========================================
CPU: STRESS TEST with Temperature

Temperature sensor not available on this board
Running stress test without temperature monitoring...

Running intensive computation for 10 seconds...

Stress test complete: 34400 iterations in 10017 ms
Performance: 3.43 iterations/ms

========================================
MEMORY: SRAM READ/WRITE

Read checksum: 326400
Random checksum: 261120
Sequential Write (7936 ops): 5164 μs (1536.79 ops/ms)
Sequential Read (2560 ops): 5228 μs (489.67 ops/ms)
Random Access (2048 ops): 5444 μs (median 376.19 ops/ms, 5 trials)

--- Memory Bandwidth Tests ---
Using 256 byte buffers (2 KB RAM)
memcpy (51200 bytes): 23096 μs (2.22 MB/s)
memset (51200 bytes): 19852 μs (2.58 MB/s)
RAM Write Bandwidth: 3.46 MB/s
RAM Read Bandwidth: 1.98 MB/s

========================================
MEMORY: EEPROM

EEPROM Size: 1024 bytes
Hardware Write (64 bytes): 213268 μs (0.30 ops/ms)
Read (64 bytes): 232 μs (275.86 ops/ms)
Read checksum: 2016

========================================
I/O: DIGITAL PIN OPERATIONS

digitalWrite() (2000 ops): 9184 μs (median 217.77 ops/ms, 5 trials)
Direct Port (6000 ops): 6800 μs (median 882.35 ops/ms, 5 trials)
Speedup: 4.05x faster

========================================
I/O: ANALOG OPERATIONS

analogRead() (167 ops): 20080 μs (8.32 ops/ms)
ADC average: 525
analogWrite() (1799 ops): 20008 μs (89.91 ops/ms)

========================================
I/O: SERIAL COMMUNICATION

01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899012345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989901234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
Serial Enqueue (190 bytes): 10696 μs (median 17.76 bytes/ms CPU, 5 trials)
flush() time (implementation-dependent): 5332 μs
Theoretical Wire Time: 16493 μs (16.49 ms)
Wire Throughput: 11.52 bytes/ms (11520 bytes/sec theoretical)
Enqueue/Wire Ratio: 64.85% (buffered, won't block)

========================================
STORAGE: Flash Information

Flash info not available on this platform

========================================
ADVANCED MATH: Transcendental Functions

Checksum: 254059.29
atan2() (100 ops): 20044 μs (4.99 ops/ms)
log() (100 ops): 15972 μs (6.26 ops/ms)
exp() (100 ops): 21840 μs (4.58 ops/ms)
pow() (100 ops): 34508 μs (2.90 ops/ms)
fmod() (1000 ops): 27688 μs (36.12 ops/ms)

========================================
TIMING: millis() and micros() Precision

millis() 1-second test: 1000 ms (±0 ms error)
micros() resolution: 4 μs (detected after 1 reads)
Minimum step size (100 samples): 4 μs
Note: AVR micros() typically advances in 4 μs steps
micros() 1ms test: 1108 μs (±108 μs error)

Clock accuracy: 100.00%

========================================
MEMORY: Stack Depth Test

Testing shallow recursion (2 KB RAM)
Recursion test (20 deep): PASS
Successfully executed 20 nested function calls
Estimated stack usage: ~600 bytes
Note: Actual stack usage varies by compiler and optimization.

========================================
BENCHMARK COMPLETE!

Results saved in Serial Monitor.
You can copy/paste the output for analysis.

To run again, press the RESET button or
re-upload the sketch.

Tom.... :smiley: :+1: :coffee: :australia:

You’ll notice they are effectively identical:

  1. EEPROM write (64B): 212080 µs vs 213268 µs (about +0.56%)
  2. Direct Port (6000 ops): 6804 µs vs 6800 µs (basically identical)
  3. analogRead (167 ops): 20064 µs vs 20080 µs (tiny)
  4. ADC average: 368 vs 525 (this is due to the pins floating. Connect via a 10k resistor to gnd if you care, though I haven’t bothered yet)
  5. Serial flush(): 5344 µs vs 5332 µs (tiny)
  6. atan2 (100 ops): 20040 µs vs 20044 µs
  7. log (100 ops): 15976 µs vs 15972 µs
  8. exp (100 ops): 21836 µs vs 21840 µs
  9. pow (100 ops): 34512 µs vs 34508 µs
  10. fmod (1000 ops): 27692 µs vs 27688 µs
  11. micros() 1ms test: 1112 µs vs 1108 µs

Incidentally you’ll notice they are all basically within the 4µs resolution here

so it’s basically a rounding thing

I have never heard of these, vast chance is a lot of work will be needed. I’m checking compile out now.

Hi, @outbackhut
I think they are from the same supplier, at work we did a bulk by for a project, all I had to do was burn the bootloader, the old one was on them.

Tom.... :smiley: :+1: :coffee: :australia:

OK. I got the latest code from Github. Yes, it has got quite big:

ESP32-C6

Sketch uses 1368526 bytes (43%) of program storage space. Maximum is 3145728 bytes.
Global variables use 47688 bytes (14%) of dynamic memory, leaving 279992 bytes for local variables. Maximum is 327680 bytes.

I got a few compiler warnings. If you get a completely clean compilation with this board selected, then I'll look further.

But, it crashed on running. Since it failed in the "Multi-core" part, which of course the ESP32-C6 does not have, I guess it will be an easy fix.



12:47:15.010 -> Note: Actual stack usage varies by compiler and optimization.
12:47:15.010 -> 
12:47:15.010 -> ========================================
12:47:15.010 -> MULTI-CORE: Parallel Performance
12:47:15.010 -> ========================================
12:47:15.010 -> ESP32 Dual-Core Test
12:47:15.316 -> 
12:47:15.316 -> assert failed: xTaskCreatePinnedToCore freertos_tasks_c_additions.h:163 (( ( ( ( BaseType_t ) xCoreID ) >= 0 && ( ( BaseType_t ) xCoreID ) < 1 ) ? ( ( BaseType_t ) 1 ) : ( ( BaseType_t ) 0 ) ) == ( (
12:47:15.316 -> Core  0 register dump:
12:47:15.316 -> MEPC    : 0x4080e56e  RA      : 0x4080e532  SP      : 0x4087f1c0  GP      : 0x4081b924  
12:47:15.316 -> TP      : 0x4087f3b0  T0      : 0x37363534  T1      : 0x7271706f  T2      : 0x33323130  
. . . 
. . .