
IphoneFM panel
louisflakes/IphoneFM
KiCad project for IphoneFM Rev A. Built step by step from ../../design/rev-a/kicad-build-procedure.md; checked with ../../tools/kicadcheck.py.

Cheap dual-band L1+L5 RTK GNSS module. LC29H rover, discrete 50 ohm front end, USB-C + castellated. Schematic generated from Python and verified by a 146-check gate.
Rtk gps module is an open-source printed circuit board by Lucas-Poulos, from the Lucas-Poulos/rtk-gps-module repository on GitHub, published under the CERN-OHL-P-2.0 licence. It is a 4-layer board of 40.6 × 40.6 mm with 67 parts on 54 nets, routed with 8 tracks and 12 vias.
It is built around the LC29HDAMD, CH340N and AP2112K-3.3TRG1, with the CL21A106KAYNNNE, 0402CG101J500NT and 0402CG330J500NT among its other parts. Its parts include 24 resistors, 19 capacitors, 7 diodes, 4 connectors and 3 ICs. It belongs with the radio and wireless boards of this library.
A cheap, solder-down RTK GNSS module that gets you centimetre-level position. Dual-band L1 + L5, castellated edges, and a USB-C port so it also works on its own with nothing but a cable.
Status: schematic complete and verified. PCB layout is the next phase.
┌──── u.FL ────┐
│ active │ 50 Ω CPWG, 0.38 mm
│ dual-band ├──► ESD ─► bias tee ─► DC block ─► π ─► SAW ─┐
│ antenna │ 0.25pF 68 nH 100 pF 0R L1+L5 │
└──────────────┘ ▲ ▼
│ ┌───────────────┐
ANT_ON ─┴─ PMOS switch │ LC29H (DA) │
│ dual-band │
USB-C ─► ESD ─► BAT54C OR ─► AP2112K 3V3 ────────────┤ RTK rover │
│ ▲ │ │
│ 5V_IN (carrier) │ UART1 1PPS │
└─► CH340N ──────────────────────────── UART ──────┤ │
1k/10k divider └───────┬───────┘
│
24 castellated pads, 1.27 mm ──────┘Feed it RTCM3 corrections over the UART — from an NTRIP client on a phone, a Raspberry Pi or a PC — and it resolves carrier phase to 1–2 cm horizontal, versus the 2–3 m you get from ordinary GPS.
Corrections come from the host, so there is no radio on the board: nothing to license, nothing to certify, and one less thing to pay for.
| Receiver | Quectel LC29H (DA), dual-band RTK rover |
| Bands | L1 / E1 / B1 / G1 and L5 / E5a / B2a |
| Constellations | GPS, GLONASS, Galileo, BeiDou, QZSS, SBAS |
| RTK accuracy | ~1–2 cm CEP, open sky |
| RTK fix rate | 1 Hz — the DA does not go faster, see below |
| Position rate, no RTK | up to 10 Hz |
| Corrections in | RTCM3 over UART1 — MSM4 or MSM7, plus 1005/1006 |
| Timing out | 1PPS, rising-edge synchronised |
| Supply | 5 V from USB-C or 5 V from the carrier board |
| Logic | 3.3 V (plus a 1.8 V debug domain, see below) |
| Interface | USB-C (CH340N) and 24 castellated pads on 1.27 mm |
| Parts cost | $27.10 per board at qty 1 |
The receiver is 88 % of the bill. Everything else together is $1.56. Nothing but the receiver is worth cost-optimising.
Quectel's LC29H (BA,CA,DA,EA) DR&RTK Application Note is unambiguous:
LC29H (DA) only supports RTK (update rate: 1 Hz). LC29H (EA) only supports RTK (update rate: 1–10 Hz, 10 Hz by default).
The 10 Hz figure quoted for these modules is the ordinary position rate. With RTK engaged, the DA produces one fix per second. If you need faster, the only variant that does it is the EA, which costs roughly 25 % more than the DA and is a different board cost, not a firmware setting.
This also means the AA variant gives up nothing on rate. Its raw observations are capped at 1 Hz, which is exactly what the DA fixes at — so "the AA is slower" is not a real objection to moving the RTK engine onto the host.
The board has no radio, so RTCM3 arrives over UART1 from whatever the host can reach. In the United States most states run a free CORS network.
In Massachusetts that is MaCORS, MassDOT's 22-station SpiderNet
network covering all 14 counties, free after registration at
macors.massdot.state.ma.us. It serves RTCM 3.1 and RTCM 3.2 MSM4.
That is directly compatible — no translation layer. The DA accepts:
| Message | |
|---|---|
| 1005 / 1006 | Stationary RTK Reference Station ARP |
| 1074 / 1077 | GPS MSM4 / MSM7 |
| 1084 / 1087 | GLONASS MSM4 / MSM7 |
| 1094 / 1097 | Galileo MSM4 / MSM7 |
| 1114 / 1117 | QZSS MSM4 / MSM7 |
| 1124 / 1127 | BeiDou MSM4 / MSM7 |
If the network offers a VRS mount point it synthesises a virtual base at
your position, so the usual "stay within ~1 km of the base" rule stops
applying — the effective baseline is short wherever you are inside the
network. Outside network coverage that rule returns, and the answer is
your own base: LC29HBS is the base-station variant and shares this
footprint, so a second board off the same fab run becomes one.
RTK resolves carrier phase, and carrier phase is ruined by reflections. A signal bounced off a glass facade arrives with corrupted phase, which costs you the fix — or worse, buys a confident but wrong one.
Test open-sky first and separate the two questions: does the board work and does it work where I need it. Debugging the former in an urban canyon wastes days.
There is no way to make an RTK receiver from discrete components — carrier phase needs a correlator ASIC. So the receiver and its SAW filter are ICs and everything around them is built from single transistors and passives rather than bought as a block:
ANT_ON, with a 10 Ω resistor limiting a shorted antenna to
~330 mA.VBCKP_EXT, so the ephemeris cache survives and the module
hot-starts in ~1 s instead of cold-starting in ~30 s.RXD1 is specified
VIHmax 3.08 V and a 3.3 V host would exceed it.Fully derived rather than asserted — see docs/impedance.md. Short version:
L302/L303 are
part of the impedance, not optional.tools/calc_impedance.py, and make check fails
if the project's RF netclass drifts away from it.24 castellated pads on 1.27 mm — drops onto 0.1 in perfboard.
Left edge (J501)
| Pad | Name | Notes |
|---|---|---|
| 1 | GND | |
| 2 | 5V_IN | ORed with USB VBUS |
| 3 | 3V3 | LDO output |
| 4 | VBCKP_EXT | optional backup cell / supercap |
| 5 | GND | |
| 6 | TXD1 | receiver → host, NMEA / PQTM |
| 7 | RXD1 | host → receiver, RTCM3 in |
| 8 | 1PPS | rising edge |
| 9 | RESET_N | active low, pulled up on-board |
| 10 | WAKEUP | needs ≥ 3.0 V to wake |
| 11 | VDD_EXT | 2.8 V out, 100 mA max |
| 12 | GND |
Right edge (J502)
| Pad | Name | Notes |
|---|---|---|
| 1 | GND | |
| 2 | ANT_ON | antenna switch control |
| 3 | I2C_SDA | via DNP link |
| 4 | I2C_SCL | via DNP link |
| 5 | TXD2 | 1.8 V domain, via DNP link |
| 6 | RXD2 | 1.8 V domain, via DNP link |
| 7 | D_SEL1 | 1.8 V domain, via DNP link |
| 8 | D_SEL2 | 1.8 V domain, via DNP link |
| 9 | GND | |
| 10–11 | — | spare |
| 12 | GND |
Pads 5–8 on the right edge are not 3.3 V tolerant. VIHmax is 2.1 V. Each reaches the edge only through an unfitted link, so a default board cannot present them to a 3.3 V host by accident.
D_SEL1 = D_SEL2 = 0 selects UART1 and is the on-chip default via 75 kΩ
pulldowns, so the fitted board needs no strapping parts at all.
design/ THE PROJECT. Open it in KiCad, edit it, save it.
lib/ the two symbols and three footprints stock KiCad lacks
tools/ helpers that READ design/ -- none of them write to it
check.py ERC + netlist + sourcing + impedance
gen_bom.py BOM, read from the schematic
calc_impedance.py the 50 Ω derivation
fetch_datasheets.py pulls the vendor PDFs (not committed)
bootstrap/ the generators that built v1 -- NOT authoritative
Makefile run `make` to list every target
.githooks/ optional pre-commit hook, ERC errors only
manufacturing/ BOM.md, BOM-dnp.md, bom_jlcpcb.csv
docs/ editing.md, impedance.md, schematic.pdf
datasheets/ README + fetch script; the PDFs are not ours to redistribute
analysis/ ERC report and netlist (gitignored, regenerated on demand)design/ is a normal KiCad project. Edit it directly. Nothing
regenerates it, and nothing in tools/ writes to it.
make open # open in KiCad -- edit and save freely
make check # ERC + netlist + sourcing + impedance, all read-only
make bom # rebuild manufacturing/ after a parts change
make # list every targetRead docs/editing.md before changing the RF path
or anything on the LC29H — there are four traps on this board that KiCad
will not warn you about (a 3.08 V limit on RXD1, a 1.8 V pin domain,
two supply pins that are outputs, and three pins that must float).
make check reads design/ and never writes to it. It exports a fresh
netlist and a fresh ERC report and asserts against those:
kicad-cli
writes no report at all when the schematic fails to parse. Verified by
injecting a deliberate fault and confirming ERC caught it on the right
sub-sheet./regex/ patterns are accepted by the file format
and match nothing — KiCad uses wildcards, and local nets carry their
sheet path.)VDD_EXT never tied to 3V3.Cxxxxx.tools/calc_impedance.py derives, and still land within 5 % of 50 Ω.The BOM is in manufacturing/BOM.md, with
bom_jlcpcb.csv ready for JLCPCB assembly and
BOM-dnp.md listing the unfitted options.
Prices and stock were read from LCSC on 2026-09-28 and frozen for
traceability — re-check before ordering. LC29H stock in particular was
thin (22 pcs). LC29HBS (C21385845) is the RTK base station variant and
LC29HAA (C22403415) has no RTK engine; both share the footprint, so
check you are buying the one you mean.
You also need an active dual-band L1+L5 antenna with NF < 1.5 dB, gain < 17 dB, and its SAW ahead of its LNA.
Hardware under CERN-OHL-P v2; the scripts under the same terms. Permissive — do what you like, no reciprocity required.
| Qty | Value | Footprint | References |
|---|---|---|---|
| 9 | 0R | Resistor_SMD:R_0402_1005Metric | R206, R207, R208, R209, R210, R211, R301, R305, R401 |
| 9 | 100nF | Capacitor_SMD:C_0402_1005Metric | C102, C104, C106, C202, C204, C205, C305, C401, C402 |
| 6 | 10k | Resistor_SMD:R_0402_1005Metric | R201, R204, R212, R303, R304, R501 |
| 3 | 10uF | Capacitor_SMD:C_0805_2012Metric | C101, C103, C201 |
| 3 | 1k | Resistor_SMD:R_0402_1005Metric | R103, R205, R502 |
| 3 | Fiducial_1mm_Mask2mm | Fiducial:Fiducial_1mm_Mask2mm | FID1, FID2, FID3 |
| 2 | 100pF | Capacitor_SMD:C_0402_1005Metric | C301, C304 |
| 2 | 33pF | Capacitor_SMD:C_0402_1005Metric | C107, C203 |
| 2 | 5.1k | Resistor_SMD:R_0402_1005Metric | R101, R102 |
| 2 | 5.1nH | Inductor_SMD:L_0402_1005Metric | L302, L303 |
| 2 | BAT54C | Package_TO_SOT_SMD:SOT-23 | D102, D104 |
| 2 | DNP | Capacitor_SMD:C_0402_1005Metric | C302, C303 |
| 2 | MMBT3904 | Package_TO_SOT_SMD:SOT-23 | Q302, Q501 |
| 1 | 100k | Resistor_SMD:R_0402_1005Metric | R202 |
| 1 | 10R | Resistor_SMD:R_0402_1005Metric | R302 |
| 1 | 22R | Resistor_SMD:R_0402_1005Metric | R213 |
| 1 | 4.7k | Resistor_SMD:R_0402_1005Metric | R203 |
| 1 | 4.7uF | Capacitor_SMD:C_0603_1608Metric | C105 |
| 1 | 68nH | Inductor_SMD:L_0402_1005Metric | L301 |
| 1 | AO3401A | Package_TO_SOT_SMD:SOT-23 | Q301 |
| 1 | AP2112K-3.3 | Package_TO_SOT_SMD:SOT-23-5 | U101 |
| 1 | B8389 | rtk-gps-module:SAW_RF360_SMD1411-5P_1.4x1.1mm | FL301 |
| 1 | CH340N | Package_SO:SOIC-8_3.9x4.9mm_P1.27mm | U401 |
| 1 | GREEN 1PPS | LED_SMD:LED_0603_1608Metric | D501 |
| 1 | LC29HDAMD | rtk-gps-module:Quectel_LC29H_LCC-24_12.2x16.0mm | U201 |
| 1 | LEFT EDGE | rtk-gps-module:Castellated_1x12_P1.27mm | J501 |
| 1 | RED | LED_SMD:LED_0603_1608Metric | D105 |
| 1 | RF1256-000 | Diode_SMD:D_0603_1608Metric | D301 |
| 1 | RIGHT EDGE | rtk-gps-module:Castellated_1x12_P1.27mm | J502 |
| 1 | SD05 | Diode_SMD:D_SOD-323 | D103 |
| 1 | USB-C 16P | Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12 | J101 |
| 1 | USBLC6-2SC6 | Package_TO_SOT_SMD:SOT-23-6 | D101 |
| 1 | u.FL | Connector_Coaxial:U.FL_Hirose_U.FL-R-SMT-1_Vertical | J301 |
It measures 40.6 × 40.6 mm and has 4 copper layers, 1.6 mm thick.
67 parts, built around the LC29HDAMD, CH340N, AP2112K-3.3TRG1 and CL21A106KAYNNNE. 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 Lucas-Poulos/rtk-gps-module repository on GitHub, at the commit this page was made from: the board is design/rtk-gps-module.kicad_pcb and its schematic design/01_power.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Its repository publishes it under the CERN-OHL-P-2.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).

louisflakes/IphoneFM
KiCad project for IphoneFM Rev A. Built step by step from ../../design/rev-a/kicad-build-procedure.md; checked with ../../tools/kicadcheck.py.



hydazz/iasis
An optional Raspberry Pi Compute Module 5 carrier for Iasis. It plugs into the main board's HubPD population and carries Ethernet, NVMe storage, an accessory USB-C port and a service USB-C port.

mx3353672833-debug/moto-gps-waveshare
MOTO GPS · Waveshare ESP32-S3 1.75C 圆屏导航 + iPhone App | Author: Maler X | Noncommercial, attribution required | Experimental


ConnorRigby/GD32-Devboard
Simple GD32F405 Development board with CAN, SD Card, Lora, BLE and GPS

marcoallegretti/Teresina-Rack
The goal is an open, self-fabricatable Daisy Patch SM-compatible Eurorack submodule: the same carrier interface and libDaisy application compatibility through a small Teresina firmware variant.