Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

taVNS-ESP32 — a DIY transcutaneous auricular vagus nerve stimulator

DOI

A working prototype of a charge-balanced, transformer-isolated taVNS stimulator built around an ESP32-S3, six discrete MOSFETs and a small audio transformer. Everything is here: schematic, as-built wiring map, firmware, a browser-based control panel, the bench bring-up procedure, and an honest engineering log of what broke and why.

Warning

This is not a medical device. It puts current through the skin of a human ear. It has no regulatory approval, no clinical validation, and no redundant protection. Read SAFETY.md before you build or power anything — especially the mains-isolation and charge-balance rules, which are the two that actually keep you safe. Anyone who builds this accepts full responsibility for the result.

Schematic

What it does

Transcutaneous auricular vagus nerve stimulation (taVNS) delivers small biphasic current pulses to the cymba conchae of the outer ear, which is innervated by the auricular branch of the vagus nerve. The usual research parameters are 25 Hz, 100–500 µs pulses, current titrated to a clear-but-comfortable tingle, 30 minutes per session.

This device produces those pulses. It does not claim to treat anything — see docs/stimulation-protocol.md for the parameter rationale and a deliberately unenthusiastic summary of the evidence.

Design in one paragraph

An H-bridge switches the low-voltage primary of a 1:4 audio transformer; the ear hangs off the floating secondary. That single decision solves most of the hard problems at once: all high-voltage nodes sit on a winding with no switches on it, so gate drive stays trivial (Vgs never exceeds the rail); the transformer cannot pass DC, so charge balance is structural rather than a firmware promise; and the same transformer is the galvanic barrier between the ear and everything else. A series capacitor on the secondary is the second, independent DC block, and a 10 kΩ series resistor caps the ear current at roughly 4.8 mA even into a dead short.

power bank 5 V ─┬─► ESP32-S3 (timing, UI, telemetry)
                └─► XL6019 boost ─► Vprim 12–18 V
                                     │
              GPIO4..7 ──────► H-bridge Q1..Q4 (+ Q5/Q6 level shifters)
                                     │  OUTA / OUTB
                                     ▼
                              T1 primary  ≈600 Ω
                              ─────║─────           ← galvanic isolation barrier
                              T1 secondary ≈10 kΩ
                                     │
                        R_lim 10k ─► Cb 4.7 µF ─► ear electrode A
                                                   ~ ear tissue ~
                        ───────────── Rb 1 MΩ ──► ear electrode B

The firmware runs the bridge as a phase machine on esp_timer: a positive phase where one high-side switch is PWM-chopped and the opposite low-side switch is held on, a dead time, the mirror-image negative phase, another dead time, then idle until the period is up. Amplitude is the PWM duty of the chopped switch. Only one switch is ever chopped at a time and its low-side neighbour is off, so PWM-off current freewheels through a body diode and shoot-through inside a phase is structurally impossible. Details and the measured proof are in docs/firmware.md.

Status

Working prototype. Built, powered, measured, and used on a human ear.

Area State
Power stage (H-bridge on perfboard) Built, continuity-checked, run under 12–18 V, clean
Bridge logic Verified with a logic analyser: 0 µs shoot-through, diagonals match
Isolated output stage Built; drives a dummy load and a real ear
Firmware v2.2 (ESP32-S3) Flashed and in use
Firmware v2.3 (optional GC9A01 display) Compiles, not yet flashed
ESP32-C3 port Compiles, never run on hardware
Control panel (browser) Working
Current sense (ADS1115) Not connected — the umbilical carries no I²C. Charge figures are arithmetic, not measurement
Electrode attachment Ear clips with ECG gel; the weakest part of the whole system

Working point in actual use: 100 % amplitude, 500 µs, 25 Hz, Vprim 18 V.

Known limitation — the 250 µs target is not reachable yet. The nerve responds to charge (current × pulse width), so halving the width means doubling the current. The firmware's width command reports the exact shortfall from the device itself: ×2.0 for 250 µs and ×3.3 for 150 µs. That is arithmetic about the output impedance, not a fault. The single unmeasured quantity in that chain is the ear/electrode impedance; measuring it is the next step, and the fix is likely better electrode contact rather than a circuit change. See docs/troubleshooting.md.

Repository layout

Path What's in it
SAFETY.md Read first. Engineering rules, contraindications, the isolation test
hardware/schematic.svg As-built schematic (regenerate with tools/gen_schematic.py)
hardware/bom.md Bill of materials with substitution notes
hardware/photos/ Build photos
docs/circuit.md Why this topology, every component value, gate drive analysis
docs/board-map.md As-built perfboard map: designator ↔ hole ↔ measured pin role
docs/build.md Build order and the staged bring-up protocol
docs/firmware.md Firmware architecture, serial command reference, flashing
docs/control-panel.md Browser control panel: power knobs, threshold search, standalone mode
docs/troubleshooting.md Symptom → measurement → diagnosis, with reference numbers
docs/stimulation-protocol.md Stimulation parameters and what the evidence does and does not support
docs/engineering-log.md What actually broke, in order, and what each failure taught
firmware/ taVNS_fw (ESP32-S3, in use) and taVNS_fw_C3 (port, untested)
panel/ panel.py — dependency-light control panel served in a browser
tools/ Schematic generator

Quick start

Roughly a weekend of work if you can solder and own a multimeter.

  1. Read SAFETY.md. The isolation and charge-balance rules are not optional.
  2. Gather partshardware/bom.md. Nothing exotic: an ESP32-S3 board, an XL6019 boost module, 6 small-signal MOSFETs, a 600 Ω:10 kΩ audio transformer, a handful of resistors, two film capacitors, ear clip electrodes and conductive gel.
  3. Build the power stage following docs/build.md and docs/board-map.md. Determine every MOSFET pin role by diode-testing the part on the board; SOT-23 adapter pinouts vary and assuming the order has already destroyed one build here.
  4. Flash the firmwaredocs/firmware.md. Arduino-ESP32 core ≥ 3.0.
  5. Bring it up on the bench, into a 4.7–10 kΩ dummy load, never into an ear. Confirm bridge timing, then confirm net DC ≈ 0 across the output with a multimeter.
  6. Confirm T1 primary↔secondary isolation reads open (megohms). This is the barrier the whole safety argument rests on.
  7. Only then: electrodes on your own ear, amplitude from zero, upward slowly.
# control panel (creates its own venv on first run, needs only pyserial)
cd panel && ./run.sh     # then open the URL it prints

Design decisions worth stealing

  • Put the step-up transformer between the switches and the patient, not a high-voltage H-bridge in front of them. A discrete HV bridge needs floating gate drive and risks Vgs breakdown; this topology needs neither.
  • Make dead time a function of the PWM carrier, not a constant. The LEDC peripheral only applies duty = 0 at a carrier-period boundary, so a high-side switch can stay on for up to one full carrier period after being told to stop. Dead time is computed as carrier period + 15 µs and cannot be set lower — an operator cannot create shoot-through by changing the carrier frequency.
  • Check driver return codes. A silent ledcAttach failure at 40 kHz once left the bridge outputting nothing while the UI showed a perfectly healthy amplitude. Cost: one night.
  • One ground star, and treat it as a mechanical problem. The single wire from the boost converter's OUT− to the star came loose twice in two days; both times the symptom was "the processor is dead". It is now a screw terminal, not solder.

Citation

Archived on Zenodo under a concept DOI that always resolves to the newest version: 10.5281/zenodo.21628511. Machine-readable metadata lives in CITATION.cff.

Boliasov, N. (2026). taVNS-ESP32: a charge-balanced, transformer-isolated DIY transcutaneous auricular vagus nerve stimulator. Zenodo. https://doi.org/10.5281/zenodo.21628511

License

Code (firmware, panel, tools) — MIT, see LICENSE. Documentation, schematic and photos — CC BY-SA 4.0.

About

DIY charge-balanced, transformer-isolated taVNS stimulator on ESP32-S3 — schematic, firmware, control panel and docs

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages