Skip to the content
2 layersEngine monitor V1, the printed circuit board in 3D

nRF52840 engine meter

Copper layers
2
Thickness
1.6 mm
Parts
44
Nets
49
Pads
141
Tracks, vias
0, 0
Routed
Not yet
KiCad
KiCad 10.0 (file 20260206)
Created
14 Sep 2026
Updated
25 Oct 2026

Overview

Engine monitor V1 is an open-source printed circuit board by andrewsargent2311-web, from the andrewsargent2311-web/Engine_meter repository on GitHub, published under the GPL-3.0 licence. It is a 2-layer board with 44 parts on 49 nets.

It is built around the MAX31856, LMV331TP and BAT54W. Its parts include 15 resistors, 14 capacitors, 8 diodes, 4 ICs and 2 crystals. It belongs with the nRF52 and nRF5x boards of this library.

Main components

3

README

README.md

Engine Meter (RPMuffin)

A small, battery-powered engine monitor for a paramotor. It measures RPM, CHT and EGT, and sends them over Bluetooth LE as NMEA-style sentences to Gaggle or the paraglide_vario_ESP32 flight computer. It also reports its own battery percentage.

It was designed and tested on a Moster 185 (single-cylinder two-stroke), but it should work on any engine with a spark-ignition lead and a thermocouple-instrumented head or exhaust.

MCUnice!nano (nRF52840)
RPMInductive pickup (2 wraps on the HT lead) → LMV331 comparator → interrupt
TemperatureUp to 2 × MAX31856 thermocouple amplifiers (CHT + EGT), K-type as shipped. The EGT channel is optional (see below)
RadioBLE, Nordic UART Service, advertises as ParaEngineMeter
Update rate5 Hz
Power1000 mAh single-cell LiPo, JST-PH 2.0 mm, charged over USB-C
PCB2 layers, 1.6 mm, about 50.6 × 75.1 mm
Case3D printed (PLA), about 58.5 × 123.5 × 27 mm including mounting tabs

Assembled unit


Repository layout

PathContents
Engine_meter/PlatformIO firmware project (open this folder in VS Code)
Engine_meter/src/main.cpp (RPM, thermocouples, BLE) and AuxSensors.cpp/.h (battery gauge)
Engine_meter/boards/Custom nicenano board definition and pin variant for PlatformIO
Engine_monitor_V1/KiCad 10 project: schematic and PCB
Engine_monitor_V1/Gerber files/Fabrication outputs: Gerbers, drill files, JLCPCB BOM, JLCPCB CPL, and Engine_monitor_V1_order.zip
3D print files/Case and lid as STL, plus ready-sliced G-code for a Prusa MK3S
Photos/Photos of the bare PCB and the finished unit

1. Parts list

Parts on the PCB (SMD, 0805 unless noted)

These are the parts in Engine_monitor_V1_BOM_JLCPCB.xlsx, and they can be assembled by JLCPCB.

QtyValueDesignatorsNotes
410 nF 50 V X7RC1, C3, C9, C10Thermocouple input filtering
7100 nF 50 V X7RC2, C4, C5, C8, C11, C12, C14Decoupling; C8 filters the comparator reference
210 µF 25 V X5RC6, C133.3 V bulk decoupling
4100 Ω 1 %R1, R2, R11, R12Thermocouple input series resistors
510 kΩ 1 %R4, R5, R7, R8, R9R4/R5 chip-select pull-ups, R7/R8 comparator reference divider, R9 comparator output pull-up
1150 kΩ 1 %R10RPM input series resistor. See the note below
11 MΩ 1 %R13Comparator hysteresis (positive feedback)
1220 kΩ 1 %R14RPM input divider to GND
21N5819HW-7-F Schottky, SOD-123D9, D10RPM input clamps (to 3.3 V and to GND)
1LMV331IDBVR, SOT-23-5U2Single comparator
2MAX31856MUD+, TSSOP-14U3, U4U3 = CHT, U4 = EGT. U4 is optional, see the note below

R10 value: the production design uses 150 kΩ. It was originally 22 kΩ, which was too sensitive to pick up noise on the ignition lead, so it was increased. Use 150 kΩ.

EGT is optional: fitting an EGT probe usually means drilling and threading a hole in the exhaust, which can weaken it. Many builds therefore leave the EGT channel off (U4, the X2 terminal and that channel's input filter parts). Newer exhausts often ship with a threaded EGT port, in which case fit it. The firmware auto-detects whether U4 is present at power-up (see Optional thermocouple channels below), so the same firmware works either way.

D9/D10 in the JLCPCB BOM are marked "consigned" (you supply them). Either supply 1N5819HW-7-F parts yourself, or pick an in-stock SOD-123 Schottky at order time.

Parts you add by hand (through-hole / modules)

RefPartPurpose
U1nice!nano (v2 or compatible, nRF52840), 2 × 12-pin headers or castellated solderMCU, BLE radio, LiPo charger
BT1JST-PH 2.0 mm 2-pin horizontal header (S2B-PH-K)Battery connector
J22-pin screw terminal, 3.81 mm pitch (Phoenix MC 1,5/2-G-3.81 footprint)Power switch (in series with the battery)
X12-pin screw terminal, 3.5 mm pitchCHT thermocouple input
X22-pin screw terminal, 3.5 mm pitchEGT thermocouple input
J11-pin 2.54 mm header (or a wire soldered straight in)RPM pickup input

Other items

  • Battery: 1000 mAh single-cell LiPo with a 2 mm JST-PH connector (ideally with a built-in protection circuit).
  • Power switch: any small SPST switch rated for a few hundred mA, wired to J2.
  • Thermocouples: two K-type probes, one for CHT (for example a spark-plug washer or bolt-on type) and one for EGT (exhaust probe). Use proper thermocouple wire or a compensated extension.
  • RPM pickup wire: a short length of insulated hookup wire.
  • Fasteners: 4 small self-tapping screws for the lid (see section 5), plus zip ties or straps for mounting.
  • USB-C cable for programming and charging.

2. Order and build the PCB

  1. Go to JLCPCB and upload Engine_monitor_V1/Gerber files/Engine_monitor_V1_order.zip.
  2. Settings: 2 layers, 1.6 mm thickness. The board is about 50.6 × 75.1 mm.
  3. Bare board: order the PCB only and hand-solder everything.
  4. Assembled: tick PCB Assembly, then upload Engine_monitor_V1_BOM_JLCPCB.xlsx and Engine_monitor_V1_CPL_JLCPCB.csv. The BOM has no LCSC part numbers, so match each line to a stocked part in the JLCPCB parts picker (see the part table above). Only the SMD parts on the top side are assembled. You add the nice!nano, terminals, header and JST connector yourself.

Bare PCB

Hand-soldering order (if building from a bare board)

The two MAX31856 chips are TSSOP-14, so the SMD parts are best done with flux, a fine tip and a magnifier.

  1. U2, U3, U4 (the ICs). Check pin 1 orientation against the silkscreen.
  2. The 0805 resistors and capacitors, then the two diodes D9/D10 (check the stripe against the silkscreen).
  3. Terminal blocks X1, X2, J2 and the JST connector BT1.
  4. J1.
  5. Finally the nice!nano. Either solder header pins or solder it directly. Keep the USB-C end of the board towards the board edge as shown in the silkscreen.

3. How the hardware works

Pin map

The firmware uses software (bit-banged) SPI, so the two MAX31856s share one bus with separate chip-selects.

Signalnice!nano GPIOFirmware pin number
MAX31856 SDO → MCU (MISO)P1.0032
MAX31856 SDI ← MCU (MOSI)P1.1345
SCKP1.1547
CS for CHT (U3)P0.1111
CS for EGT (U4)P1.0436
RPM comparator outputP1.1143

Pin numbers follow the Adafruit nRF52 core convention: P0.xx → xx, P1.xx → 32 + xx.

RPM input

  • The pickup wire goes to J1. It passes through R10 (150 kΩ) into a divider with R14 (220 kΩ), giving roughly 0.6 × the input voltage. D10 clamps to GND and D9 clamps to 3.3 V to protect the comparator.
  • U2 (LMV331) compares that signal with a 1.65 V reference made by R7/R8 and filtered by C8. As a rough guide, the pickup needs to swing above about 2.8 V at J1 to trigger.
  • R13 (1 MΩ) feeds the output back to the input for hysteresis. R9 (10 kΩ) pulls the open-collector output up to 3.3 V.
  • The nRF52840 counts the rising edges on an interrupt.

Thermocouple input

Each channel copies the Adafruit MAX31856 breakout design: 100 Ω series resistors on the thermocouple inputs, 10 nF / 100 nF filtering, and a 10 kΩ pull-up on each chip-select. X1 = CHT (U3) and X2 = EGT (U4).

Polarity matters. If a reading falls when you warm the probe, swap the two wires. The firmware sets type K for both channels, but the MAX31856 supports B, E, J, K, N, R, S and T. To change it, edit the two setThermocoupleType(...) lines in setup() in Engine_meter/src/main.cpp.

Power

  • The battery connects to BT1. BT1 pin 1 is battery + and pin 2 is GND.
  • BT1 + goes to J2 (the switch), and the other side of the switch goes to the nice!nano's battery-in pin (pin 26, marked BATIN/RAW on the board). So the battery is only connected to the nice!nano while the switch is on. Charge with the switch on.
  • Charging happens through the nice!nano's USB-C port. It charges at roughly 100 mA, so a flat 1000 mAh pack takes about 10 hours.
  • The nice!nano's regulator provides the 3.3 V rail for the comparator and both MAX31856s.

⚠️ Check battery polarity before the first power-up. JST-PH LiPo packs from different suppliers are wired in different orders, and a reversed pack can destroy the nice!nano. Use a multimeter on the pack connector, and compare it with BT1 (pin 1 = +, pin 2 = GND) on the PCB. If it is reversed, re-pin the connector on the battery lead.


4. Firmware

The firmware is a PlatformIO project in Engine_meter/.

Build and upload

  1. Install VS Code and the PlatformIO IDE extension.
  2. File → Open Folder… and choose the Engine_meter folder (not the repo root).
  3. PlatformIO downloads the nordicnrf52 platform and the libraries (Adafruit MAX31856, BusIO and TinyUSB) on first build.
  4. Build, then upload with the nice!nano plugged in over USB-C. PlatformIO will try to reset it into the bootloader automatically. If the upload hangs, double-tap the reset button and upload again. The bootloader appears as its own COM port (VID_239A&PID_00B3), and the upload must target that port.
  5. For debug output, open the running firmware's serial port at 115200 baud. It prints a line every 200 ms (only while a serial monitor is attached) with RPM, raw RPM, pulse and reject counts, EGT, CHT and battery %.

The nicenano board definition in boards/ comes from ICantMakeThings/Nicenano-NRF52-Supermini-PlatformIO-Support via bertrik/nicenano-example.

Optional thermocouple channels

At boot the firmware probes each MAX31856 by writing and reading back its thermocouple-type register. A missing chip cannot echo the values back, so that channel is marked not fitted and is reported as unavailable (99) in the $EMS sentence. The serial log at start-up shows [BOOT] CHT MAX31856: found, EGT MAX31856: not fitted, and the per-line output shows EGT=n/a.

Set CHT_PRESENCE / EGT_PRESENCE in main.cpp to TC_AUTO (default), TC_ABSENT (never read it) or TC_PRESENT (always read it, so a dead chip shows [FAULT] instead of vanishing). A chip that is fitted but has no probe attached is not "not fitted": it is detected, and reports a fault (open circuit) until a probe is connected.

Settings you may want to change (Engine_meter/src/main.cpp)

SettingDefaultMeaning
PULSES_PER_REV1.0Spark pulses per crank revolution. Correct for a single-cylinder two-stroke such as the Moster 185. If the reading is double or half what you expect, change this
RPM_TIMEOUT_MS1500No pulse for this long → RPM reports 0
RPM_WINDOW_MS5000RPM averaging window
RPM_FAST_ATTACK / RPM_FAST_WINDOW_MS / RPM_FAST_THRESHOLD1 / 1000 / 0.10Use a 1 s window when it differs from the 5 s average by more than 10 %
RPM_ROUND_TO / RPM_HYST10 / 7.0Displayed RPM is rounded to 10 RPM with 7 RPM hysteresis
RPM_MIN_LOCKOUT_US5000Ignores edges closer together than this (ringing rejection). It adapts to 40 % of the last period above about 600 RPM
CHT_PRESENCE / EGT_PRESENCETC_AUTOTC_AUTO, TC_PRESENT or TC_ABSENT. See Optional thermocouple channels
TC_FAULT_HOLD_COUNT3A temperature is only reported unavailable after this many consecutive bad reads. Until then the last good value is re-sent, hiding single glitches from ignition noise
TC_WARMUP_MS500Readings are ignored this long after power-up while the first conversion completes
WATCHDOG_TIMEOUT_MS8000The MCU resets itself if the main loop stalls this long. 0 disables the watchdog
PEMBAT_INTERVAL_MS1000How often the battery sentence is sent
SEND_PEMBAT1Set to 0 to stop sending the proprietary battery sentence
RPM_DEBUG_EDGES0Set to 1 to print raw edge intervals when diagnosing pickup noise

BLE output

The device advertises as ParaEngineMeter and exposes the Nordic UART Service. Each message is an ASCII sentence with an XOR checksum and CRLF line ending.

text
$EMS,<pressure>,<fuelFlow>,<fuelRemaining>,<fuelUsed>,<ambientTemp>,<CHT>,<EGT>,<waterTemp>,<RPM>*HH
$PEMBAT,<percent>*HH
  • Unused EMS fields are filled with 999999 (pressure), 9999 (fuel fields) or 99 (temperatures).
  • CHT and EGT are in °C × 100, clamped to −300..1500 °C. A value of 99 means unavailable (sensor fault, no probe, or that channel's chip is not fitted).
  • RPM is sent × 100. 0 is a valid stopped-engine reading.
  • $PEMBAT is battery percentage, 0–100, estimated from the nRF52840's internal supply-voltage ADC and a single-cell LiPo curve. It is approximate. It reads high while charging and sags under load.

Example: RPM 3100, CHT 180.0 °C, EGT 550.0 °C:

text
$EMS,999999,9999,9999,9999,99,18000,55000,99,310000*7C

Gaggle: add the meter under Profile → Equipment → Bluetooth Devices. Gaggle must receive a real supported reading within about 35 seconds.

paraglide_vario_ESP32: select ParaEngineMeter in the vario's Bluetooth scan list.


5. 3D printed case

The case and lid are in 3D print files/.

FilePrint time (Prusa MK3S, 0.15 mm, PLA)
Engine meter case.stl5 h 18 min
Engine meter lid.stl1 h 44 min

Ready-sliced G-code for a Prusa MK3S is included. For another printer, slice the STLs yourself, 0.15 mm layers in PLA or similar (PETG is a better choice for a hot, sunny harness).

  • The PCB sits in the case and the battery sits in the lid, as in the photo above.
  • The lid is held on by 4 small self-tapping screws into the corner holes (the lid has pilot holes at about 2 mm).
  • The mounting tabs on each side have slots (about 2.5 × 4.5 mm) for zip ties or straps.
  • The case was designed in Onshape.

Closed case


6. Wiring it to the engine

RPM pickup

  1. Take a length of insulated wire. Solder one end to J1.
  2. Wrap the other end 2 turns around the ignition (HT) lead, close to the spark plug cap. Do not connect it to anything else. The signal is picked up by coupling alone.
  3. Secure the wrap with heat-shrink or tape, and keep the lead clear of the exhaust and moving parts.

If RPM is wrong: no reading means add a turn, and spurious readings mean remove a turn or move the wrap further from the plug. The rejects counter in the serial output shows how many noise edges are being filtered. The reading is also wrong if PULSES_PER_REV doesn't match your engine.

Thermocouples

  • CHT probe → X1, EGT probe → X2.
  • Keep thermocouple wires away from the ignition lead and coil.

Power

Connect a switch to J2, plug the battery into BT1 (after checking polarity), and charge through the nice!nano's USB-C port.


7. First power-up checklist

  1. Check the 3.3 V rail on the board with a meter before fitting the nice!nano (if you soldered it in a socket).
  2. Plug the battery in, switch on, and confirm the nice!nano powers up.
  3. Connect USB, open the serial monitor at 115200 baud, and confirm you see [BOOT] Engine meter ready, advertising as ParaEngineMeter.
  4. With nothing connected, fitted thermocouple channels will show a fault, and an unfitted EGT channel shows n/a. With a probe attached you should see room temperature. Warm the probe and check that the reading rises.
  5. Check the BAT= value is sensible for the pack voltage.
  6. With the engine running, check the RPM against a known reference such as a handheld tachometer.
  7. Connect from Gaggle or the vario (or a generic BLE app such as nRF Connect) and confirm $EMS sentences arrive.

License

This project is open source under the GNU General Public License v3.0. See LICENSE for the full text. It covers the firmware, PCB design files, case models and documentation in this repository. You are free to build, modify and share it, and if you distribute a modified version you must release your changes under the same license.

Third-party files keep their own licenses and notices (see Credits below).

Credits

  • Thermocouple front end based on the Adafruit MAX31856 breakout.
  • nice!nano board support from ICantMakeThings and bertrik (linked above).
  • Firmware uses the Adafruit nRF52 Arduino core (Bluefruit) and the Adafruit MAX31856 library.

Parts

44
QtyValueFootprintReferences
60.1uFAdafruit MAX31856:0805-NOC2, C4, C5, C11, C12, C14
610KAdafruit MAX31856:0805-NOR3, R4, R5, R13, R14, R15
61N4148Adafruit MAX31856:SOD-323D1, D2, D3, D4, D7, D8
4100Adafruit MAX31856:0805-NOR1, R2, R11, R12
310kResistor_SMD:R_0805_2012MetricR7, R8, R9
20.01uFAdafruit MAX31856:0805-NOC3, C9
20.01uFAdafruit MAX31856:0805_10MGAPC1, C10
210uCapacitor_SMD:C_0805_2012MetricC6, C13
23.5mm termAdafruit MAX31856:TERMBLOCK_1X2-3.5MMX1, X2
2BAT54WDiode_SMD:D_SOD-123D5, D6
2MAX31856Adafruit MAX31856:TSSOP14U3, U4
1100nFCapacitor_SMD:C_0805_2012MetricC8
110nFCapacitor_SMD:C_0805_2012MetricC7
11MResistor_SMD:R_0805_2012MetricR10
122kResistor_SMD:R_0805_2012MetricR6
1LMV331Package_TO_SOT_SMD:SOT-23-5U2
1RPM_PICKUPConnector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_VerticalJ1
1nice_nanonice-nano-kicad-master:nice_nanoU1

More from andrewsargent2311-web/Engine_meter

1
  • 2 layers50.6 × 75.1 mmEngine monitor V1, the printed circuit board in 3D

    Engine monitor V1

    andrewsargent2311-web/Engine_meter

    nRF52840 engine meter

    36 parts1GPL-3.0

Similar boards

  • 4 layers170 × 74.5 mmSupply power, the printed circuit board in 3D

    Supply power

    GarryBGoode/VibeSupply

    USB PD based powersupply developed on vibes (claude)

    253 parts
  • 4 layers65 × 37.5 mmCLAS Combo Breakout BKUP, the printed circuit board in 3D

    CLAS Combo Breakout BKUP

    takuhoTech/CelestNavi-Combo

    Ready-to-use GNSS+CLAS receiver with integrated loop antenna

    71 parts9MIT
  • 4 layers45 × 24 mmAltimeter, the printed circuit board in 3D

    Altimeter

    rckTom/alturia-pcb

    altimeter for rocket recovery and flight status recording

    100 parts7
  • 2 layers354 × 295.1 mmSV PWM card R01, the printed circuit board in 3D

    SV PWM card R01

    mariusenglund/three-phase-inverter

    Materials for enhancing the DC-to-AC converter that was designed as part of our bachelor's thesis in the spring of 2023.

    257 parts2GPL-3.0
  • 4 layers51.5 × 21 mmPico-2v, the printed circuit board in 3D

    Pico-2v

    lucasbaizer/pico-2v

    RP2354A development board with switchable voltage, QSPI breakout, and more

    53 parts1
  • 4 layers230 × 152 mmSENTINEL TRM, the printed circuit board in 3D

    SENTINEL TRM

    ajisrawi/sentinel-uhf-radar

    Reference design of a two-face UHF early-warning phased-array radar: system sizing, MoM antenna simulation, seven KiCad PCB projects, Blender site model

    144 parts
  • 6 layers120.5 × 72.9 mmDriver Inductor, the printed circuit board in 3D

    Driver Inductor

    Alexandr-Filatov/Inductor-80kWt

    99 parts
  • 4 layers83.2 × 78.1 mmShield offset, the printed circuit board in 3D

    Shield offset

    apmarshall3/general-purpose-robotics-shield

    125 parts

Questions

What parts does the Engine monitor V1 use?

44 parts, built around the MAX31856, LMV331TP and BAT54W. 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.

Where can I download the Engine monitor V1 KiCad files?

From the andrewsargent2311-web/Engine_meter repository on GitHub, at the commit this page was made from: the board is Engine_monitor_V1/_restore_backup_2026-09-02T17-29-26-343/Engine_monitor_V1.kicad_pcb and its schematic Engine_monitor_V1/Engine_monitor_V1.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Engine monitor V1 design in my own project?

Its repository publishes it under the GPL-3.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).