Files
ESP32-Code-for-the-Half-Bri…/README.md
T
2026-10-10 01:35:14 +00:00

24 KiB
Raw Blame History

ESP32 Complementary Half-Bridge Controller

Hardware-timed complementary PWM, manual control, and automated frequency sweeps from a local web page.

This project runs on a classic ESP32-DevKitC (ESP32-WROOM-class board) using the Arduino-ESP32 3.x core. It generates two complementary logic signals for a dual-channel gate driver, controls the gate driver's disable input, and serves a browser-based control panel over Wi-Fi. The ESP32 first tries a normal Wi-Fi router and, if it cannot join one at startup, falls back to its own Wi-Fi access point.

Caution

High-voltage hardware: This firmware was developed for an IGBT half-bridge / Paul-trap driver. The PWM outputs have no programmed deadtime. Complementary ESP32 pins do not guarantee non-overlap at the IGBTs: propagation-delay mismatch, turn-off time, and IGBT tail current can cause shoot-through. Do not energize the HV DC bus until you have checked both gate-emitter waveforms and the power-stage switching at a safe test voltage. The gate-driver DIS input is not a means of isolating or discharging the HV bus. Provide an independent hardware interlock/emergency shutdown and appropriate discharge arrangements.

1. Features

  • Two synchronized, complementary PWM outputs generated by one internal LEDC hardware channel (not two independently started timers).
  • Adjustable frequency 100–200,000 Hz and CH1 duty cycle 1–99%; CH2 is the inverted output.
  • Automatic search for the highest supported LEDC duty-resolution setting, from 14 bits down to 1 bit. Failed trial settings are reported as normal progress instead of misleading driver-error spam.
  • Gate-driver disable on GPIO19. Default state after boot: disabled until an explicit Enable command.
  • Web-based manual controls and frequency sweeps (start, finish, step, on-time, and separate HV-off preparation time).
  • Non-blocking sweep engine: timing runs on the ESP32, not in the browser; it continues if the browser disconnects.
  • A large green/amber/red status panel showing the selected frequency, sweep step, and time remaining. The browser checks a small /status response only while an automatic transition is expected.
  • Router-first Wi-Fi with mDNS (http://hvboard.local/) and standalone AP fallback (http://192.168.1.1/). The two modes are alternatives, not simultaneous AP+STA operation.
  • USB Serial Monitor commands for manual operation and debugging.

2. Hardware and pinout

ESP32 DevKitC pin Purpose Connect to
GPIO23 CH1: normal LEDC PWM Upper IGBT gate-driver logic input (via the intended input circuitry)
GPIO22 CH2: inverted LEDC PWM Lower IGBT gate-driver logic input (via the intended input circuitry)
GPIO19 Gate-driver disable; HIGH = disabled, LOW = enabled UCC21550 DIS control input as wired in this design
GND Logic reference Gate-driver input-side ground, as required by the interface design
USB Programming and serial debugging Computer with a data-capable USB cable

Do not physically connect GPIO23 to GPIO22. Both GPIOs are assigned internally to LEDC channel 0; GPIO22 is inverted by the ESP32 output logic. Keep the two gate-driver input connections separate.

The DIS polarity above is the convention used by this sketch; verify it against your actual UCC21550 wiring and datasheet. The sketch drives GPIO19 HIGH as early as setup() can control it, but the pin may be floating during reset/boot before firmware starts. Design a suitable hardware-defined safe disable state (for example, an appropriately chosen pull-up on the logic input) rather than relying on firmware alone.

This version is for a classic ESP32, not the previous ESP32-CAM pinout or a four-IGBT NPC stage. GPIO16/17 were used in earlier iterations; GPIO23/22/19 are the current pins. On some ESP32 modules GPIO16/17 are reserved for PSRAM, which is another reason not to assume earlier pinouts apply here.

3. Software requirements

Item Use
IDE Arduino IDE 2.x
Board package esp32 by Espressif Systems, 3.x series
Board selection Tools → Board → ESP32 Arduino → ESP32 Dev Module, or the matching ESP32 DevKitC profile if listed
Upload port The USB serial/COM port for your connected DevKitC
Serial Monitor baud 115200
Serial Monitor line ending Newline or Both NL & CR

Use the current stable 3.x release of Espressif's Arduino board package. The sketch was developed with the 3.x LEDC API; Arduino-ESP32 2.x is not compatible without porting the LEDC calls. As with any hardware-control firmware, record the precise working board-package version in your lab/repository notes after a successful upload; that exact patch version is not specified in this project.

Install ESP32 board support

  1. Install Arduino IDE.

  2. Open File → Preferences (or Arduino IDE → Settings on macOS).

  3. In Additional Boards Manager URLs, add the Espressif stable URL:

    https://espressif.github.io/arduino-esp32/package_esp32_index.json
    
  4. Open Boards Manager, search for esp32 by Espressif Systems, and install a 3.x version.

  5. Select ESP32 Dev Module (or the exact matching classic DevKitC board), then select its USB serial port.

Do not select an ESP32-S3, C3, ESP8266, or ESP32-CAM board profile for a classic ESP32-DevKitC.

Libraries: no separate installations required

The sketch includes:

#include <Arduino.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WebServer.h>
#include "esp_log.h"

Arduino, WiFi, ESPmDNS, WebServer, and the underlying ESP-IDF logging headers are provided by the Espressif Arduino-ESP32 board package. Do not install unrelated third-party libraries with the same names; they may cause ambiguous includes or incompatibilities. No RMT, MCPWM, timer-interrupt, display, JSON, or external web-server library is needed. The HTML/CSS/JavaScript page is embedded directly in the sketch.

Common API trap: Do not copy LEDC examples based on the old ledcSetup() / ledcAttachPin() APIs. This code uses ledcAttachChannel(), ledcOutputInvert(), ledcWriteChannel(), and ledcChangeFrequency() from the 3.x API.

4. Find and open the sketch

The intended sketch filename is:

ESP32_LEDC_2CH_200kHz_sweep_router_mdns_fallback.ino

In Arduino IDE, use File → Open to select this .ino. If Arduino asks to create a folder with the same basename, accept. Alternatively, arrange the repository as:

ESP32_LEDC_2CH_200kHz_sweep_router_mdns_fallback/
├── ESP32_LEDC_2CH_200kHz_sweep_router_mdns_fallback.ino
└── README.md

If your repository uses a different sketch filename, use that filename consistently; the Arduino sketch folder should normally match its .ino basename.

5. Configure Wi-Fi before uploading

Near the top of the .ino:

const char *ROUTER_SSID = "YOUR_ROUTER_WIFI_NAME";
const char *ROUTER_PASSWORD = "YOUR_ROUTER_WIFI_PASSWORD";
const char *MDNS_HOSTNAME = "hvboard";
const uint32_t ROUTER_CONNECT_TIMEOUT_MS = 12000;

const char *AP_SSID = "2-Channel HV board";
const char *AP_PASSWORD = "12345678";

Option A — existing router: Replace the two YOUR_ROUTER_... placeholders with the normal Wi-Fi credentials of a 2.4 GHz network. You do not need router administrator access. On startup, the board attempts to join for up to 12 seconds. If successful, open http://hvboard.local/ from a computer/phone on the same local network. If .local does not work, type wifi in Serial Monitor and use the Local IP printed there.

Option B — standalone: Leave the router credential placeholders unchanged. The ESP32 creates its own network:

  • Wi-Fi name: 2-Channel HV board
  • Wi-Fi password: 12345678 (change it before shared use)
  • Control page: http://192.168.1.1/

A browser/device may warn that this Wi-Fi has no internet; choose to stay connected. Type the URL with http://, not https://.

How fallback works: If joining the router fails during startup, the sketch switches from WIFI_STA to WIFI_AP. It does not run a permanent AP alongside a working router connection. The fallback decision is made during boot: if the router later drops out while STA mode is active, the existing sketch does not automatically change to AP without restarting/resetting the board. hvboard.local is a local-network name, not a public internet URL. Guest/client isolation, multicast filtering, VPNs, and client mDNS support can prevent name resolution or local access.

Warning

Security: The webpage deliberately has no second username/password prompt. Anyone who can reach the ESP32 over the network can access Enable/Disable and sweep endpoints. Do not put this HV controller on a shared/untrusted campus or public Wi-Fi network without adding authentication and network restrictions. The default fallback AP password is only an example, not production-grade protection.

6. Upload and first safe test

  1. Disconnect the HV DC bus and prevent the gate-driver/power stage from switching dangerous voltage. Start with the ESP32 and logic signals only.
  2. Connect the DevKitC over a data-capable USB cable. Select the board and port in Arduino IDE.
  3. Click Verify to compile, then Upload.
  4. If upload hangs at Connecting..., try a different USB data cable/port; on some DevKitC boards, hold BOOT during the initial connection and release after the upload begins. Avoid anything connected to the USB UART pins (GPIO1/TX, GPIO3/RX) during flashing.
  5. Open Serial Monitor, select 115200 baud and Newline.
  6. Confirm that LEDC initializes, Wi-Fi starts in STA or fallback AP mode, and the startup state reports Gate-driver output: DISABLED.
  7. With the HV supply still disconnected, measure GPIO23, GPIO22, and GPIO19 with an oscilloscope. GPIO23/22 are complementary logic signals, and GPIO19 is HIGH while the driver is disabled. Check the actual gate-driver outputs and gate-emitter voltages separately before any powered switching test.
  8. Connect to the selected network and open the control page. Try Enable and Disable at safe logic/low-voltage conditions before proceeding.

AUTO_START_AFTER_BOOT = false is intentional. The messages:

Automatic startup is disabled.
Gate-driver output: DISABLED

mean GPIO19 is held HIGH after startup. They are not errors. Press Enable on the page or enter enable in Serial Monitor to begin the configured blanking interval and then set GPIO19 LOW.

7. Manual control

Default values:

Setting Default / permitted values
Frequency 1,500 Hz initially; 100–200,000 Hz allowed
CH1 duty 50% initially; 1–99% allowed
CH2 duty Complementary to CH1 (nominally 100% − CH1 duty)
Initial/manual blanking 2,000 ms initially
Automatic startup Off
Gate-driver DIS GPIO19 HIGH = disabled, LOW = enabled

On the webpage, Apply settings sets manual frequency/duty/blanking. Enable waits the configured blanking time and then enables the gate driver; Disable / Stop sweep disables the driver immediately in the main loop. Changing manual settings while running disables the driver, updates LEDC, then resumes after blanking. Manual controls also take precedence over and cancel an active sweep.

Three different timings:

  • parameterBlankMs = 2000 — manual Enable/Apply blanking and initial blanking before the first sweep step.
  • STARTUP_BLANK_MS = 2000 — only relevant if AUTO_START_AFTER_BOOT is changed to true (not recommended for HV testing).
  • delay(500) near Serial.begin(115200) — a short serial/startup settling pause, not the HV blanking interval. GPIO19 is already configured to HIGH before that pause.

LEDC behavior: PWM continues to run at GPIO23/22 even while GPIO19 holds the gate driver disabled. A red “driver disabled” status does not mean the ESP32 pins are static, nor does it mean the HV supply is discharged. The “actual LEDC frequency” is a peripheral configuration/readback value, not an oscilloscope measurement.

8. Web frequency sweep

The Frequency sweep section accepts:

Field Meaning
Start frequency (Hz) First frequency
Finish frequency (Hz) Final frequency
Frequency step (Hz) Positive step size; direction is automatic (up or down)
HV ON at each frequency (seconds) Time the driver is enabled at that frequency, 0.1–3,600 s
HV OFF preparation interval (seconds) Time between adjacent steps when GPIO19 is HIGH, 0.1–3,600 s

Frequency inputs must be integer Hz. Sweep start/finish must be 100–200,000 Hz; step must be 1–200,000 Hz. The finish frequency is visited even if the last step is shorter. The preparation interval is separate from parameterBlankMs.

Example — start 1000, finish 3000, step 1000, ON 3 s, prep 5 s, initial blank 2 s:

Start sweep         GPIO19 HIGH   2 s (initial blank)
1,000 Hz            GPIO19 LOW    3 s (driver enabled)
Prepare / spray     GPIO19 HIGH   5 s (driver disabled)
2,000 Hz            GPIO19 LOW    3 s
Prepare / spray     GPIO19 HIGH   5 s
3,000 Hz            GPIO19 LOW    3 s
Sweep complete      GPIO19 HIGH   driver disabled

During each preparation interval, the code disables the gate driver first, configures the next LEDC frequency, and waits with the driver off. It does not apply the initial blanking interval again between steps. The duty cycle remains at the current manual setting throughout the sweep. The sweep runs with millis() scheduling rather than blocking delay() calls, so the web server and serial controls remain responsive.

The page shows a large colour-coded driver status box:

  • Green: driver enabled; shows the active frequency and current sweep step.
  • Amber/orange: initial blanking or preparation; shows the upcoming frequency/time remaining.
  • Red: driver disabled, sweep finished, stopped, or error.

The page uses small asynchronous /status requests roughly every 750 ms while blanking/sweeping and stops periodic polling once a stable manual state is reached. The ESP32 owns the actual sweep timing; closing the browser does not cancel the sweep.

Stop: Press Stop sweep / Disable driver or Disable / Stop sweep, or send sweepstop/disable through Serial Monitor. A sweep completes with GPIO19 HIGH. No automatic repeat is implemented.

9. Serial commands

Open Serial Monitor → 115200 baud → Newline and enter one command per line:

Command What it does
help Print available commands
status Show driver, frequency, duty, resolution, and sweep phase
wifi Show whether STA/router or AP fallback is active and how to access the page
set 1500 50 Set frequency to 1,500 Hz and CH1 duty to 50%
f 3000 Set frequency to 3,000 Hz
d 45 Set CH1 duty to 45% (CH2 complementary)
45% Alternative CH1 duty command
blank 2000 Set manual/initial blanking to 2,000 ms
enable Begin blanking, then enable the gate driver
disable Disable gate driver and stop an active sweep
sweepstop Stop the sweep and disable the driver

Starting a sweep is implemented on the webpage (/sweep/start), not as a Serial Monitor sweepstart command in this version. Serial status and sweepstop work during a web-started sweep.

10. Troubleshooting: previously encountered errors

A. Compilation error: cannot convert 'ledc_clk_src_t' to 'ledc_clk_cfg_t'

Cause: An earlier version tried to call:

ledcSetClockSource(LEDC_APB_CLK);

On the affected Arduino-ESP32 core, that argument is not the type expected by ledcSetClockSource().

Fix: Do not re-add that call. The current sketch uses the Arduino core's default LEDC clock and probes which frequency/resolution combinations are accepted. Removing the line was the compatibility fix; changing USB drivers will not resolve this compiler error.

B. LEDC setup error: LEDC could not represent this frequency ... at 1,500 Hz

An earlier sketch treated a zero immediately returned by ledcReadFreq(CH1_PIN) as a failed setup even after ledcAttachChannel() had succeeded. The current sketch recognizes successful attachment and uses the requested frequency as a fallback reporting value if the initial readback is zero.

If this error returns: Use the latest sketch, select a classic ESP32 board, check the Arduino-ESP32 core is 3.x, and inspect which API call actually fails. Do not assume 8-bit duty resolution is too high: the code starts at 14 bits and tries down to 1 bit.

C. Repeated logs such as requested frequency 150000 and duty resolution 14 can not be achieved

These were expected trial failures, not an overall failure. The firmware probes 14, 13, 12, ... bits and selects the highest resolution supported at the requested frequency. The current version suppresses the expected ESP-IDF ledc log messages during each trial and instead prints human-readable progress, ending with the selected resolution and configured frequency. This is normal: higher frequencies leave fewer PWM duty steps.

If every candidate fails, the sketch reports a genuine error. As an example, 200 kHz may require fewer resolution bits than 1.5 kHz. The reported exact resolution depends on the clock/core configuration.

D. ledcSetup / ledcAttachPin not declared; old RMT/timer examples do not compile

This project uses hardware LEDC, not the old timer-ISR waveform generator, four independent RMT transmitters, or MCPWM. The Arduino-ESP32 2.x → 3.x migration changed peripheral APIs. Do not merge older snippets into this firmware without porting them. Use one shared LEDC channel and per-pin inversion for these two outputs.

E. Upload fails: Failed to connect to ESP32, Timed out waiting for packet header, or no COM port

  • Choose the correct ESP32 Dev Module and Tools → Port.
  • Use a USB data cable; try another USB port (prefer direct computer connection over a hub).
  • Install your board's USB-to-UART driver only if the interface isn't recognized (commonly CP210x or CH340, depending on board revision/clone).
  • Close the Serial Monitor or other program holding the port while uploading.
  • If needed, hold the BOOT button while upload begins; release it after the connection starts. Some boards may require EN/Reset.
  • Check stable ESP32 power, remove connections from UART/boot-related pins, and disconnect the HV system for debugging.

F. Serial Monitor is blank or commands are ignored

Use 115200 baud and Newline (or Both NL & CR). The firmware collects input until \n; with No line ending, commands may appear to do nothing. Press EN/Reset once to see startup logs if Serial Monitor opened after boot. The early delay(500) is not related to the blanking time.

G. hvboard.local does not open

  • Check wifi in Serial Monitor: is the board actually in STA mode? If it fell back to AP, use http://192.168.1.1/ after joining its Wi-Fi.
  • In STA mode, phone/computer and ESP32 must be able to reach each other on the same LAN. Guest isolation and multicast blocking can prevent this.
  • Make sure you used http://hvboard.local/, not https://....
  • Try the Local IP printed by wifi; it bypasses mDNS name lookup.
  • mDNS support varies by device/OS; Windows configurations sometimes require additional discovery support (e.g., Bonjour), while macOS/iOS normally support mDNS.
  • Ensure the existing router provides 2.4 GHz Wi-Fi for a classic ESP32; use the correct SSID/password.
  • The router/AP choice happens at boot. Reset the ESP32 if you want it to retry joining a now-available router.

H. The webpage is slow or doesn't update after blanking

Use the AJAX version in this repository, not an older form/redirect sketch. The browser posts control commands without reloading the full page and calls the lightweight GET /status endpoint only while blanking/sweeping. If a page seems stale after installing new firmware, perform one hard refresh or close/reopen the tab. LEDs/Wi-Fi do not schedule sweep timing; that runs locally on the ESP32.

I. Webpage shows ENABLED, but no HV waveform is visible

Verify GPIO19 and the actual gate-driver output stages. ENABLED is the firmware's GPIO19 command state, not independent hardware feedback. LEDC logic signals can still toggle at GPIO23/22 even while DIS is HIGH. Verify driver input-side logic supply, grounding, isolated gate supplies, and the gate-emitter voltage with suitable instruments. Do not infer the HV output from the webpage status alone.

J. PWM looks complementary on ESP32 pins but overlaps at IGBTs

A shared LEDC channel removes software phase drift, but this firmware contains no intentional deadtime. IGBT delays and turn-off tails can make both devices conductive simultaneously. Stop HV testing until appropriate non-overlap/deadtime and hardware protection have been verified. Raising frequency toward the 200 kHz software limit does not establish that the UCC21550/IGBT power stage is safe at that switching rate.

11. Implementation notes and scope

  • LEDC is a hardware peripheral inside the ESP32, not an external chip or additional library.
  • One LEDC channel supplies both outputs; CH2 is inverted with ledcOutputInvert(CH2_PIN, true).
  • There is no configurable deadtime, no shoot-through interlock, no independent HV-voltage/current feedback, and no hardware fault/brake input implemented by this sketch.
  • Frequency and duty are quantized to actual LEDC timer/duty settings; high-frequency duty percentages may not be represented exactly.
  • The web server is basic HTTP on port 80 (not HTTPS), with no separate webpage login.
  • Sweep delays are software-timed using millis() and serviced from loop(); the PWM edges themselves come from LEDC hardware. UI updates and Wi-Fi activity do not require an interrupt per PWM edge.
  • Router-first + AP fallback is retained intentionally. It does not keep two Wi-Fi networks operating at once.
  • The firmware is provided as experimental control code, not a certified high-voltage safety controller.

12. Official references


Before connecting HV: Confirm correct module, pinout, polarity of DIS, logic power/ground, measured complementary waveforms, safe gate-driver operation, and a working independent emergency power-off path.