
Pl60c dmx mini
tsmiltonAgents/pl60c-dmx-wakeup
A small ESP32-S3 board that drives the wired DMX512 input of a Neewer PL60C panel light so the light can be ramped up slowly in the morning (sunrise alarm). Rev A, 2026-09-02.

A programmable force-feedback knob for your computer. Custom motor-driver PCB, closed-loop haptic firmware, a native Windows companion app and a parametric 3D-printed enclosure, all designed in house.
Smartknob driver is an open-source printed circuit board by aryanthomare, from the aryanthomare/SmartKnob repository on GitHub. It is a 4-layer board of 54 × 54 mm with 69 parts on 75 nets, routed with 891 tracks and 130 vias.
It is built around the ESP32-S3-MINI-1-N8, DRV8316CRRGFR and TPS54202DDCR, with the AP2112K-3.3TRG1, USBLC6-2SC6 and B5819W among its other parts. Its parts include 25 capacitors, 20 resistors, 5 ICs, 5 diodes and 5 connectors. It belongs with the ESP32 boards of this library.
A programmable force-feedback knob for your computer. Custom motor-driver PCB, closed-loop haptic firmware,
a native Windows companion app and a parametric 3D-printed enclosure, all designed in house.
A brushless gimbal motor sits under the knob. By driving it with the right torque at every angle, the firmware makes the same physical knob feel like a stepped volume dial, a smooth scroll wheel or a switch with hard end stops, and changes that feel on the fly as you switch tasks on the PC. The knob talks to a small Windows tray app over USB or Bluetooth LE, and works on its own as a media volume knob when the app isn't running.
flowchart LR
subgraph Knob["Knob (ESP32-S3 firmware)"]
ENC["AS5600 encoder<br/>12-bit, I²C"] --> CTRL["Control loop ~4.7 kHz<br/>FOC torque + haptic engine"]
CTRL --> DRV["DRV8316 3-phase driver<br/>→ gimbal BLDC motor"]
CTRL <--> PROTO["Line protocol<br/>HELLO · CFG · VAL · PING"]
CTRL --> HID["HID volume keys<br/>(standalone)"]
end
PROTO <-- "USB CDC serial" --> APP
PROTO <-- "BLE Nordic UART" --> APP
HID -- "USB HID / HID-over-GATT" --> WIN["Windows"]
subgraph PC["Windows PC"]
APP["SmartKnob.exe<br/>tray app"] --> CA["Core Audio<br/>system + per-app volume"]
APP --> SI["SendInput<br/>scroll · zoom · arrows"]
endThe haptics always run on the knob, so the feel never waits on the PC. The app only sends a haptic config (range, degrees per step, detent strength, wall stiffness) when the mode changes, and receives value changes back.
A 54 × 54 mm, four-layer board designed in KiCad. The motor's axis sits at the board centre, the AS5600 encoder board stacks above it on M3 standoffs, and the motor mounts on top of that.
| Block | Part | Notes |
|---|---|---|
| MCU | ESP32-S3-MINI-1-N8 | Native USB (no USB-UART bridge), BLE 5, 8 MB flash |
| Motor driver | TI DRV8316CR | 3-phase, integrated FETs, SPI config, 3× PWM mode, current-sense outputs |
| Encoder | AS5600 breakout | 12-bit magnetic angle over I²C, on its own board under the motor |
| Motor | 34.5 mm gimbal BLDC | 7 pole pairs (measured during bring-up) |
| 12 V input | DC barrel jack | P-MOSFET reverse-polarity block, 15 V gate clamp, SMAJ16A TVS |
| 5 V | TI TPS54202 buck | 12 V → 5.08 V, diode-ORed with USB VBUS |
| 3.3 V | AP2112K LDO | MCU, encoder and breakout header |
| USB-C | HRO TYPE-C-31-M-12 | 500 mA polyfuse, USBLC6 ESD protection |
| Misc | JST-PH motor and encoder connectors, 2×5 breakout header, BOOT/RESET buttons, VM voltage sense |
flowchart LR
J1["12 V barrel"] --> Q1["Reverse-polarity<br/>P-MOSFET + TVS"] --> VM["+12 V (VM)"]
VM --> DRV["DRV8316<br/>motor supply"]
VM --> BUCK["TPS54202 buck<br/>→ 5.08 V"] --> D4["Schottky"] --> V5["+5 V"]
USB["USB-C VBUS"] --> F1["Polyfuse"] --> D3["Schottky"] --> V5
V5 --> LDO["AP2112K"] --> V33["+3.3 V<br/>MCU · encoder"]
VM --> SENSE["÷11 divider → GPIO7<br/>(VM sense)"]The two 5 V sources are diode-ORed, so the logic runs from either USB or the barrel jack. Motor power only comes from the barrel jack, so on USB alone the knob still reads the encoder and talks to the PC, and the firmware turns haptics off until 12 V is present.
Layer stack. Signals on the outer layers, a solid ground plane on inner 1 under everything, and inner 2 split between the 12 V motor supply and 3.3 V. The DRV8316's thermal pad drops straight into the ground plane through a via array, and the ESP32 antenna overhangs a copper keep-out.

The design notes on each sheet record the datasheet decisions: feedback divider values, which DRV8316 pins may not float, strapping pins to avoid, ADC1-only analog inputs because ADC2 is unusable with the radio on, and so on.
Power

Motor driver

MCU

Connectors

Full PDF: hardware/smartknob_driver/smartknob_driver_schematic.pdf
Fabrication. hardware/smartknob_driver/fab has Gerbers, drill files and a
JLCPCB assembly BOM and placement file with LCSC part numbers, so the board can be ordered fully assembled.
volume_knob/src/main.cpp · Arduino on ESP32-S3 via PlatformIO
Motor control. At power-up the firmware calibrates itself: it aligns the rotor with a fixed voltage vector to find the encoder direction and the electrical zero, then applies a test push to learn the torque sign. After that it runs voltage-mode field-oriented control: every loop it reads the encoder over 400 kHz I²C, computes the electrical angle, and puts the requested torque on the q-axis through 20 kHz PWM. The loop runs at about 4.7 kHz. Drive voltage is capped per supply (3 V on 12 V, 1.2 V when VM is low), and a DRV8316 fault or loss of motor power drops the knob into plain-encoder mode instead of driving blind.
Haptic engine. The knob tracks an integer value in [lo, hi] with one value every step degrees. Around each
value a capped spring pulls the knob to the detent centre, and past either end a stiffer spring wall pushes it back,
with damping on both. Hysteresis on the step boundary stops the value chattering.
Two ways to run.
Protocol. Plain text lines, identical over USB serial and Bluetooth:
| Direction | Message | Meaning |
|---|---|---|
| PC → knob | HELLO | Handshake, answered with INFO name=SmartKnob fw=2 hap=<0/1> |
| PC → knob | CFG lo= hi= val= step= det= wall= | Range, current value, degrees per step, detent volts, wall stiffness |
| PC → knob | VAL v= | Move the value without moving the knob (volume changed elsewhere) |
| PC → knob | PING vol= | Keep-alive (3 s timeout) plus the PC's real volume, answered with PONG hap= vm= |
| knob → PC | VAL v= | The user turned the knob |
Connectivity. USB enumerates as a composite device (HID consumer control + CDC serial) with its own product ID. Over Bluetooth LE the knob exposes two services on one connection: HID-over-GATT for the standalone volume keys and the Nordic UART Service for the protocol. Every message the firmware prints goes to both transports.
desktop/smartknob.cpp · C++17, Win32, GDI+, C++/WinRT
![]() | ![]() |
![]() Volume popup shown while turning | |
A tray app with a floating panel for picking the mode and click strength, and a volume popup that appears while you turn the knob.
IAudioEndpointVolume), and listens for
changes made elsewhere so the knob's haptic position stays in sync. It tags its own writes so it can ignore them.SetWinEventHook) and adjusts every audio session of that process.SendInput, each
with its own detent feel.Liquid Glass material, in software. The panel and popup follow Apple's Liquid Glass guidelines without any GPU framework:
Footprint: one 280 KB statically linked executable, no runtime to install, about 7 MB of memory, 0 % CPU idle.
Settings live in %APPDATA%\SmartKnob\settings.ini.
enclosure/smartknob_enclosure.fs · Onshape FeatureScript
The whole enclosure is a single code-defined Onshape feature, so changing a standoff height or the knob fit is one constant and a rebuild.
The whole stack was designed in house and brought up one layer at a time.
encoder_test scans the I²C bus and streams raw angle,
magnet status and AGC to confirm the magnet height.motor_test brings up the DRV8316 over SPI and checks supply and
faults. It steps through the phases while watching the rotor, sweeps electrical revolutions to measure the pole
pairs (7), and spins the motor open-loop in both directions before any closed-loop code runs.Problems found on real hardware
setup() when CDC-on-boot is enabled, that meant turning CDC-on-boot off and owning
the serial object.Firmware (PlatformIO):
cd volume_knob
pio run -t upload # first flash goes through the chip's USB-Serial/JTAG port (COM3 in platformio.ini)Once the firmware is running, the board shows up as 303A:4B4E (HID + serial) and the flashing port disappears. To
reflash, choose Disconnect for firmware update in the app's tray menu, then open the knob's COM port at 1200 baud
to reboot into the bootloader. Holding BOOT while plugging in also works.
Desktop app (Visual Studio with the C++ workload):
desktop\build.bat
desktop\SmartKnob.exeSmartKnob.exe --snapshot <dir> renders the panel and popup over the current screen to PNGs and exits. The UI images
in this README were made that way.
Bluetooth: pair "SmartKnob" once in Windows Settings → Bluetooth. Windows caches the knob's services, so after changing them in firmware, remove the device and pair again.
hardware/smartknob_driver/ KiCad project: schematic, 4-layer PCB, custom symbols/footprints, fab outputs
volume_knob/ Main firmware: FOC, haptic engine, USB + BLE protocol, HID
encoder_test/ Bring-up: AS5600 over I²C
motor_test/ Bring-up: DRV8316 + open-loop motor tests
desktop/ Windows companion app (single C++ file + build script)
enclosure/ Onshape FeatureScript enclosure + board STEP export
docs/images/ README images (renders, schematic sheets, app snapshots)| Qty | Value | Footprint | References |
|---|---|---|---|
| 5 | 10k | Resistor_SMD:R_0402_1005Metric | R1, R12, R14, R20, R21 |
| 4 | 100nF | Capacitor_SMD:C_0402_1005Metric | C4, C10, C28, C42 |
| 4 | 100nF 50V | Capacitor_SMD:C_0603_1608Metric | C3, C20, C21, C22 |
| 4 | M3 | MountingHole:MountingHole_3.2mm_M3 | H1, H2, H3, H4 |
| 3 | 22pF C0G | Capacitor_SMD:C_0402_1005Metric | C43, C44, C45 |
| 3 | 22uF 25V | Capacitor_SMD:C_0805_2012Metric | C5, C6, C26 |
| 3 | 330R | Resistor_SMD:R_0402_1005Metric | R22, R23, R24 |
| 3 | 5.1k | Resistor_SMD:R_0402_1005Metric | R11, R30, R31 |
| 2 | 100k 1% | Resistor_SMD:R_0402_1005Metric | R2, R4 |
| 2 | 10uF | Capacitor_SMD:C_0603_1608Metric | C9, C41 |
| 2 | 10uF 50V | Capacitor_SMD:C_1206_3216Metric | C2, C23 |
| 2 | 1uF | Capacitor_SMD:C_0402_1005Metric | C8, C40 |
| 2 | 1uF 50V | Capacitor_SMD:C_0603_1608Metric | C24, C27 |
| 2 | 4.7k DNP | Resistor_SMD:R_0402_1005Metric | R32, R33 |
| 2 | B5819W | Diode_SMD:D_SOD-123 | D3, D4 |
| 1 | 100k | Resistor_SMD:R_0402_1005Metric | R13 |
| 1 | 100uF 35V | Capacitor_SMD:CP_Elec_6.3x7.7 | C1 |
| 1 | 10k 1% | Resistor_SMD:R_0402_1005Metric | R5 |
| 1 | 13.3k 1% | Resistor_SMD:R_0402_1005Metric | R3 |
| 1 | 15uH | Inductor_SMD:L_Sunlord_SWPA5040S | L1 |
| 1 | 1k | Resistor_SMD:R_0402_1005Metric | R6 |
| 1 | 22R | Resistor_SMD:R_0603_1608Metric | R10 |
| 1 | 47nF 50V | Capacitor_SMD:C_0603_1608Metric | C25 |
| 1 | 500mA PTC | Fuse:Fuse_0805_2012Metric | F1 |
| 1 | 75pF C0G | Capacitor_SMD:C_0402_1005Metric | C7 |
| 1 | AP2112K-3.3TRG1 | Package_TO_SOT_SMD:SOT-23-5 | U2 |
| 1 | BOOT | Button_Switch_SMD:SW_Push_1P1T_XKB_TS-1187A | SW2 |
| 1 | BREAKOUT 2x5 | Connector_PinHeader_2.54mm:PinHeader_2x05_P2.54mm_Vertical | J5 |
| 1 | BZT52C15 | Diode_SMD:D_SOD-123 | D1 |
| 1 | DC-005C-20A (5.5x2.1) | smartknob:BarrelJack_Hroparts_DC-005C-20A_Horizontal | J1 |
| 1 | DMP3099L-7 | Package_TO_SOT_SMD:SOT-23 | Q1 |
| 1 | DRV8316CRRGFR | smartknob:TI_RGF0040E_VQFN-40-1EP_5x7mm_P0.5mm_EP3.7x5.7mm_ThermalVias | U3 |
| 1 | ENCODER (S4B-PH-K-S) | Connector_JST:JST_PH_S4B-PH-K_1x04_P2.00mm_Horizontal | J3 |
| 1 | ESP32-S3-MINI-1-N8 | RF_Module:ESP32-S2-MINI-1 | U4 |
| 1 | MOTOR (S3B-PH-K-S) | Connector_JST:JST_PH_S3B-PH-K_1x03_P2.00mm_Horizontal | J4 |
| 1 | RESET | Button_Switch_SMD:SW_Push_1P1T_XKB_TS-1187A | SW1 |
| 1 | Red (PWR) | LED_SMD:LED_0603_1608Metric | D5 |
| 1 | SMAJ16A | Diode_SMD:D_SMA | D2 |
| 1 | TPS54202DDCR | Package_TO_SOT_SMD:SOT-23-6 | U1 |
| 1 | TYPE-C-31-M-12 | Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12 | J2 |
| 1 | USBLC6-2SC6 | Package_TO_SOT_SMD:SOT-23-6 | U5 |
It measures 54 × 54 mm and has 4 copper layers, 1.6 mm thick.
69 parts, built around the ESP32-S3-MINI-1-N8, DRV8316CRRGFR, TPS54202DDCR and AP2112K-3.3TRG1. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
From the aryanthomare/SmartKnob repository on GitHub, at the commit this page was made from: the board is hardware/smartknob_driver/smartknob_driver.kicad_pcb and its schematic hardware/smartknob_driver/connectors.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Its repository states no licence, so its author keeps all rights: ask aryanthomare before reusing the design.

tsmiltonAgents/pl60c-dmx-wakeup
A small ESP32-S3 board that drives the wired DMX512 input of a Neewer PL60C panel light so the light can be ramped up slowly in the morning (sunrise alarm). Rev A, 2026-09-02.

nikolaus018/dji-fcc-esp32
ESP32-S3 firmware that switches a DJI N1 remote to FCC mode over USB (replaces the Android app)

mburger89/SMK_Keyboard_DevKit
59-key hot-swap mechanical keyboard PCB carrier for a socketed ESP32-C6-DevKitC-1 dev board — KiCad project generated/routed by Python scripts


RotemCarr/snowboard-fc
Snowboard flight controller hardware and software stacks - using the Zephyr framework


