FanControl plugin that adds fan monitoring and direct fan control for MSI laptops — the missing piece for machines whose fans are normally only adjustable through MSI Center / Creator Center (requested here).
Verified hardware: EC firmware family 14B3EMS1 — MSI PS42 Modern 8MO/8RA,
Modern 14 A10M/A10RB. Other MSI laptops with the standard EC layout can opt in
via the config file (see below).
- Install FanControl (the standard .NET build, V271+).
- Make sure the PawnIO driver is installed — FanControl itself offers to install it, or grab the installer from pawnio.eu.
- Drop
FanControl.MsiEc.dllinto FanControl'sPluginsfolder and restart FanControl.
That's it. You get:
- CPU Fan (MSI EC) control — ready for a curve or the calibration assistant,
- CPU (MSI EC) temperature and CPU Fan (MSI EC) RPM sensors (polled
slowly; disable them with
"ecSensors": "off"), plus GPU ones on dual-fan models.
Controls accept 0–100 %.
The plugin's job is writing fan speed; for reading temperature there is a
better source. Point your fan curve at a LibreHardwareMonitor CPU
temperature (FanControl ships with it — "CPU Package", "Core Average", …).
Those come from the CPU's own MSRs, a completely different bus, so they update
instantly and cost zero EC traffic. That single change removes the most
frequent EC access; the default "ecSensors": "slow" then costs only 4 bytes
per 30 s and keeps the RPM readout.
If you want literally zero steady-state EC traffic, set "ecSensors": "off" —
but first remove every reference to the plugin's sensors from FanControl
(curve temperature source, control pairing, tray icons). FanControl validates
saved sensor references on startup and refuses to refresh when they disappear.
- The plugin reads the EC firmware version first (register
0xA0) and disables itself on anything not in the verified list — it never writes to an unknown EC. - Writes go only to the documented fan registers (curve tables + fan mode), every byte is read back and verified.
- Thermal failsafe: the two hottest bands of the EC's own curve table are never written below their floors (≥ ~80 °C: min 80 % duty; top band: always 100 %). Even if the OS or FanControl freezes while a quiet duty is set, an overheating CPU/GPU still gets full airflow — this logic lives in the EC, not in software.
- The factory fan curve and mode are captured at startup and restored when you disable the control, close FanControl, or the plugin unloads.
- Worst case (a frozen EC — never observed): power the laptop off and hold the power button ~30 s; the EC resets with factory behavior.
- EC access uses the signed, HVCI-compatible PawnIO
driver with the official
LpcACPIECmodule (port I/O restricted to the ACPI EC ports0x62/0x66), so it works with Windows Memory Integrity (HVCI) enabled. Transactions are serialized through the system-wideAccess_ECmutex shared with other monitoring tools. - ACPI-driver coexistence (v1.2+): the Windows kernel EC driver shares the same ports and cannot be locked out, so the plugin never consumes a pending EC response that may belong to the kernel (that desyncs battery/thermal reporting), skips its cycle instead of interfering, keeps traffic minimal (sensor poll every 5 s, duty writes within ±2 % coalesced, mode re-check once a minute) and backs off exponentially when the EC misbehaves.
- EC health watchdog (v1.3): every write anomaly, timeout or implausible reading counts as evidence of bus contention; two within 10 minutes suspend all EC writes for 15 minutes (the fan keeps its last duty, the EC-side thermal failsafe stays active). Implausible sensor samples are discarded so garbage never reaches your fan curves.
- Sleep/resume aware (v1.3): resume is when the kernel talks to the EC the most, so after any suspend/hang gap the plugin stays off the bus for 45 s, then gently re-asserts control. All boost-register writes are absolute values from a known-good startup snapshot — never read-modify-write — and boost toggles at most once a minute with a wide 10 % hysteresis.
- Boot- and resume-aware startup (v1.5): FanControl re-creates plugin
objects (the plugin lives in
FanControl.Service, which reloads them e.g. when the UI reconnects after resume), so a fresh instance used to repeat the whole startup read burst — right after a resume, the worst possible moment. The "stay off the EC bus" deadline, the verified firmware string and the GPU detection result are now process-wide: a re-created instance re-identifies the machine without a single EC read, and the factory snapshot waits out the first minute after boot and 45 s after resume before it is taken. - Minimal contact (v1.4): requested duty is quantized (default 5 %) and
rate-limited (default one write per 10 s), only the table bytes that actually
changed are written, the fan-mode register is re-checked every 5 minutes
instead of every minute, Cooler Boost is off by default, and with
"ecSensors": "off"a steady fan speed means zero EC transactions.
| Situation | EC bytes |
|---|---|
| Startup (firmware check + factory snapshot) | ~20 reads, once |
Steady state, ecSensors: "off" |
none |
Steady state, ecSensors: "slow" |
4 reads / 30 s |
| Fan speed change | ≤5 writes + 1 read, at most once per 10 s |
| Fan-mode re-check while controlling | 1 read / 5 min |
Create FanControl.MsiEc.json next to the dll (see
FanControl.MsiEc.json.example):
{
// Opt-in for EC firmwares not in the built-in verified list.
// Check yours first (e.g. HWiNFO → Embedded Controller, or MSI's EC update
// package name). Only do this if you know your model uses the standard
// MSI EC layout (most 2018+ consumer/creator models do).
"additionalFirmwarePrefixes": [],
// "auto" (default): GPU fan sensors appear if the EC reports GPU activity
// at startup. "on"/"off" to force.
"gpuFan": "auto",
// Engage MSI Cooler Boost when a control is asked for at least this duty %
// (1..100, 0 = disable). Default 100: full-speed requests act instantly.
"coolerBoostAtDuty": 100
}The MSI EC ramps the actual PWM toward the requested duty at only ~1 %/s
(measured: 3000→5900 RPM takes ~56 s through the curve-table path) — firmware
behavior, same under MSI Center, not adjustable through documented registers.
The plugin compensates for the case that matters: when FanControl requests
coolerBoostAtDuty % or more, it flips MSI's Cooler Boost bit, which
bypasses the ramp entirely (3000→6200 RPM in ~2 s, slightly above the normal
100 % speed). Below the threshold (with 5 % hysteresis) boost is released and
the fan follows the normal slow ramp down.
If your firmware isn't listed, the plugin shows exactly what to put in this file — and please open an issue with your model + firmware string so it can be added to the verified list.
Register map (standard MSI layout, confirmed live on 14B3EMS1.102):
| Register | Meaning |
|---|---|
0xA0..0xAB |
EC firmware version string |
0x68 / 0x80 |
CPU / GPU temperature, °C |
0x71 / 0x89 |
current fan duty, % |
0xCC/0xCD, 0xCA/0xCB |
fan tachometer, RPM = 478000 / raw (big-endian) |
0x72..0x78, 0x8A..0x90 |
fan curve duty tables (7 temperature bands) |
0xF4 |
fan mode: 0x0D auto, 0x8D advanced |
Control works like MSI Center's advanced mode: the plugin switches the EC to advanced fan mode and writes a flat duty table, so the value FanControl asks for applies at any temperature (except the failsafe bands above).
dotnet build src/FanControl.MsiEc/FanControl.MsiEc.csproj -c Release -p:FanControlDir=<path to FanControl>
- Встановіть FanControl і драйвер PawnIO (FanControl сам запропонує).
- Покладіть
FanControl.MsiEc.dllу папкуPluginsFanControl і перезапустіть програму. - З'являться датчики температури/обертів та керування вентилятором — далі звичайні криві FanControl.
Plugin code: MIT (see LICENSE). The embedded LpcACPIEC.bin PawnIO module
is LGPL-2.1-or-later, © namazso — source:
PawnIO.Modules (see
THIRD-PARTY-NOTICES.md).