Skip to content

System Overview

Purpose & Design Philosophy

The Xengineering Alternator Regulator controls alternator field output using ESP32-based PWM control with multi-source sensor inputs. The system provides battery monitoring, web-based configuration, and adaptive learning algorithms for thermal management.

Core Design Principles

  • Safety: Multiple protection layers prevent alternator, battery, and electrical system damage
  • Learning Mode: Adaptive alternator control based on temperature feedback and overheat history
  • Real-time Interface: Web-based monitoring and control accessible from any device
  • Reliability: Watchdog protection, error handling, and automatic recovery systems
  • Open Source: Full transparency for modification and community development

System Architecture

Hardware Foundation

ESP32-S3 (16MB Flash) ← Main Controller
├── ADS1115 ← 4-channel analog input (battery V, alt current, RPM, temp)
├── INA228 ← High-precision battery monitor with hardware overvoltage protection
├── OneWire ← DS18B20 temperature sensors
├── Field MOSFET Driver ← PWM control of alternator field
├── Digital I/O ← Ignition, alarms, switches, BMS signals
├── Communication Interfaces ← NMEA2K, NMEA0183, Victron VE.Direct
└── WiFi ← Web interface and OTA updates

Software Architecture

The firmware is organized around a main control loop with specialized subsystems:

Core Control Loop (loop()): - Runs every ~50ms with watchdog protection - Sensor data acquisition - Field control calculations
- Safety monitoring - Web data transmission

Key Subsystems: - Sensor Management: Multi-source data with validation and fallback - Field Control: Normal mode vs Learning mode algorithms - Battery Monitoring: SOC tracking with Peukert correction - Web Interface: Real-time data streaming to browser clients - Safety Systems: Multiple protection layers and alarm conditions

Main Loop Structure

Setup Phase (setup())

The initialization sequence establishes all system components:

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

  // System initialization
  initializeNVS();                    // Non-volatile storage for persistent data
  loadNVSData();                      // Restore previous session data
  ensureLittleFS();                   // File system for settings and web files
  InitSystemSettings();               // Load all configuration from files

  // Hardware initialization  
  if (hardwarePresent == 1) {
    initializeHardware();             // Sensors, communication interfaces
  }

  // Network and security
  loadPasswordHash();                 // Web interface authentication
  setupWiFi();                        // Network connectivity

  // Safety systems
  esp_task_wdt_init(&wdt_config);     // 15-second watchdog protection
  esp_task_wdt_add(NULL);

  Serial.println("=== SETUP COMPLETE ===");
}

Key Setup Functions: - initializeNVS(): Persistent data storage initialization - initializeHardware(): Sensor and communication interfaces
- setupWiFi(): Network configuration and connection - InitSystemSettings(): Load settings from LittleFS files

Main Loop Operation (loop())

The main control loop executes every 50-100ms with strict timing control:

void loop() {
  esp_task_wdt_reset();              // Feed 15-second watchdog
  starttime = esp_timer_get_time();  // Performance timing

  // Core sensor reading
  ReadAnalogInputs();                // ADS1115 state machine
  if (VeData == 1) ReadVEData();     // Victron VE.Direct
  if (NMEA2KData == 1) NMEA2000.ParseMessages();

  // Battery and engine monitoring
  UpdateEngineRuntime(elapsedMillis);
  UpdateBatterySOC(elapsedMillis);

  // Field control (main function)
  if (LearningMode == 1) {
    AdjustFieldLearnMode();          // Adaptive control algorithm
  } else {
    AdjustField();                   // Standard control algorithm  
  }

  // Safety and health monitoring
  CheckAlarms();                     // Temperature, voltage, current limits
  calculateThermalStress();          // Alternator lifetime modeling
  updateSystemHealthMetrics();       // CPU, memory, stack monitoring

  // User interface and data logging
  SendWifiData();                    // Real-time web interface updates
  UpdateDisplay();                   // Local OLED display

  // Periodic maintenance
  checkAndRestart();                 // Scheduled system restart (2 hours)

  // Performance monitoring
  endtime = esp_timer_get_time();
  LoopTime = (endtime - starttime);
  if (LoopTime > MaxLoopTime) MaxLoopTime = LoopTime;
}

Loop Timing: - Target: 50-100ms per iteration - Watchdog timeout: 15 seconds - Performance monitoring: Track maximum loop time - Automatic restart: Every 2 hours for maintenance

Data Flow Architecture

Sensor Data Pipeline

Hardware Sensors → ESP32 GPIO/I2C → Data Validation → Global Variables → Web Interface
     ↓                ↓                    ↓               ↓              ↓
ADS1115/INA228 → ReadAnalogInputs() → Sanity Checks → MeasuredAmps → SendWifiData()
OneWire Temp   → TempTask()         → Range Limits  → AlternatorTemperatureF
NMEA2K/VE.Direct → Parse Functions → Protocol Valid → VictronVoltage

Control Flow

Sensor Inputs → Target Calculation → Field Control → PWM Output → Alternator Response
     ↓              ↓                    ↓              ↓              ↓
Battery V,I → uTargetAmps (Hi/Low/RPM) → dutyCycle → setDutyPercent() → Field Current
Temperature → Safety Overrides        → Constraints → MOSFET Driver → Heat Generation

Data Freshness System

The system tracks sensor data age to detect failed sensors:

// Data timestamp tracking
enum DataIndex {
  IDX_ALTERNATOR_TEMP = 0,
  IDX_BATTERY_V,
  IDX_MEASURED_AMPS,
  // ... 17 total indices
};
unsigned long dataTimestamps[MAX_DATA_INDICES];

// Mark data fresh when successfully read
#define MARK_FRESH(index) dataTimestamps[index] = millis()

// Check if data is stale (>10 seconds old)
#define IS_STALE(index) (millis() - dataTimestamps[index] > DATA_TIMEOUT)

Benefits: - Web interface shows red indicators for stale data - Prevents control decisions based on old sensor readings - Enables automatic sensor fallback strategies

Memory Management

Partition Scheme (16MB ESP32-S3)

nvs         : 20KB   - Non-volatile storage (persistent variables)
otadata     : 8KB    - OTA boot selection
factory     : 4MB    - Factory firmware (GPIO15 recovery)
ota_0       : 4MB    - Production firmware (OTA updates)
factory_fs  : 2MB    - Factory web files
prod_fs     : 2MB    - Production web files (OTA updated)
userdata    : 3.9MB  - Data logs and configuration
coredump    : 64KB   - Debug crash dumps

Runtime Memory Management

  • Heap monitoring: Continuous tracking with console warnings
  • Stack monitoring: FreeRTOS task stack usage analysis
  • Fragmentation tracking: Heap fragmentation percentage
  • Console message queue: Fixed-size circular buffer (10 messages)

Memory Safety: - Watchdog protection prevents hung tasks - Stack overflow detection for critical tasks - Automatic restart if heap falls below 20KB - Fixed-size buffers to prevent dynamic allocation issues

Safety Systems

Hardware Protection

  • INA228 overvoltage protection: Hardware-level field shutdown at BulkVoltage + 0.1V
  • Emergency field collapse: Immediate MOSFET disable on voltage spikes
  • Watchdog timer: 15-second timeout with automatic restart

Software Protection Layers

// Multiple safety checks in field control
if (currentBatteryVoltage > (ChargingVoltageTarget + 0.2)) {
  digitalWrite(4, 0);           // Emergency field shutdown
  dutyCycle = MinDuty;
  fieldCollapseTime = millis(); // 10-second lockout
  return;
}

// Temperature protection
if (TempToUse > TemperatureLimitF) {
  dutyCycle -= 2 * dutyStep;    // Aggressive reduction
}

// Current limits
if (Bcur > MaximumAllowedBatteryAmps) {
  dutyCycle -= dutyStep;        // Battery protection
}

Alarm Conditions

  • High alternator temperature
  • Battery voltage too high/low
  • Excessive alternator or battery current
  • Sensor failures (stale data detection)
  • System health issues (low memory, stack overflow)

Configuration Management

Settings Storage

  • LittleFS files: Human-readable text files for each setting
  • NVS storage: Binary data for runtime variables and statistics
  • Persistent variables: Battery SOC, energy totals, thermal damage accumulation
  • Session variables: Reset on each boot (current maximums, loop times)

Default Value System

// Example: Target current setting
if (!LittleFS.exists("/TargetAmps.txt")) {
  writeFile(LittleFS, "/TargetAmps.txt", String(TargetAmps).c_str());
} else {
  TargetAmps = readFile(LittleFS, "/TargetAmps.txt").toInt();
}

Benefits: - Settings survive firmware updates - Easy troubleshooting (readable files) - Factory reset capability - Individual setting modification without recompilation

Performance Characteristics

Timing Requirements

  • Main loop: 50-100ms typical, 5000ms maximum (watchdog limit)
  • Sensor reading: ADS1115 ~20ms per channel, INA228 ~5ms
  • Field adjustment: Every 50ms (configurable)
  • Web updates: Every 50ms (real-time data), 2-3 seconds (status data)

Resource Usage

  • Flash memory: ~1.4MB firmware (4MB available)
  • RAM usage: ~200KB typical (320KB available)
  • CPU utilization: ~15-25% average
  • Network bandwidth: ~2KB/second for real-time web interface

Scalability Limits

  • Maximum sensor channels: 4 analog (ADS1115), expandable via I2C
  • Web clients: 5-10 simultaneous connections tested
  • Data logging: 180 days local storage in userdata partition
  • Settings: 100+ individual parameters in LittleFS files

Development Environment

Required Tools

  • Arduino IDE 2.x with ESP32 board package
  • Custom partition scheme: partitions.csv in sketch folder
  • Libraries: 20+ external libraries for sensors and communication
  • Build configuration: ESP32-S3, 16MB flash, 240MHz CPU

Build Process

# Board configuration
FQBN="esp32:esp32:esp32s3:FlashSize=16M,PartitionScheme=custom"

# Compilation
arduino-cli compile --fqbn $FQBN --output-dir ./build .

# OTA package creation
tar --format=ustar -cf firmware.tar -C build firmware.bin data/

This system overview provides the foundation for understanding the detailed subsystem documentation that follows.