|
ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
|
This example reads a u-blox GNSS module (the popular GT-U7, or a NEO-6/7/8/M8) and prints your position, satellite count, and the receiver's firmware version to the Serial Monitor. It shows the two languages a u-blox receiver speaks on the same UART - human-readable NMEA sentences and compact UBX binary frames - and how the library reads both and talks back in UBX.
Every u-blox GPS streams two things at once over its serial pin:
$GPGGA,123519,4807.038,N,... that any GPS emits. Easy to read, a bit wasteful.B5 62 <class> <id> <length> <payload> <checksum>. Compact, and the only way to configure the receiver or get the all-in-one NAV-PVT fix (position + velocity + time in a single frame).They are interleaved byte-by-byte on the same wire. This sketch's demultiplexer (pc_ubx_stream_feed) untangles them: it hands complete, checksum-checked UBX frames to the UBX decoder and every other byte to a normal NMEA line reader.
The sketch does both directions:
UBX-MON-VER poll) and turns on the binary position fix (UBX-CFG-MSG enabling UBX-NAV-PVT).The module talks over a UART (two data wires, crossed over):
| GPS pin | ESP32 pin | Why |
|---|---|---|
VCC | 3V3 | power |
GND | GND | ground |
TX | GPIO 16 | GPS talks -> ESP32 listens (RX) |
RX | GPIO 17 | ESP32 talks -> GPS listens (TX) |
PPS | GPIO 4 | 1 pulse/second (optional; timing use) |
The data wires cross: GPS TX -> ESP32 RX (GPIO 16), GPS RX -> ESP32 TX (GPIO 17). The RX wire is only needed because this sketch sends UBX; a read-only sketch can leave it off. If your board's second UART is elsewhere, change GNSS_RX / GNSS_TX at the top of UbloxGnss.ino.
On a dev board with a silk-screened
TX/RXheader: those pins are the chip's UART0, wired to the USB serial console - do not put the GPS there or it fights the console. Use plain numbered GPIOs like 16/17.
Upload, open the Serial Monitor at 115200, and give the antenna a view of the sky. You will see:
send worked - the receiver replied to a UBX poll.UBX-NAV-PVT enable.fix=0 means no satellite fix yet (cold start / indoors). Once fix becomes 2 or 3 the latitude/longitude fill in, and the PPS pin starts pulsing (the counter climbs).Getting a first fix outdoors can take from 30 seconds to a few minutes.
This is the "read a cheap breakout, bridge it onto the network" pattern the library uses everywhere. From here: feed the fix into the Time Source feature (GPS is a stratum-1 clock), serve it to a web page over WebSocket, or become an NTP server (see the NtpServer example) using GPS time. For centimeter-accuracy RTK, the NtripCaster example streams RTCM3 corrections.
parsed stays 0. Check the two data wires are crossed (GPS TX -> GPIO 16), the module has power, and the baud matches (GNSS_BAUD, default 9600 - some modules ship at 38400).UBX MON-VER. The send (GPS RX -> ESP32 TX GPIO 17) is not connected, or the module's UBX protocol is disabled. NMEA-only still proves reception.fix=0 forever.** GPS needs sky. Move the antenna to a window or outdoors.The codecs live in the library, so the flags must reach the whole build:
(The Arduino IDE reads the flags from build_opt.h beside the sketch automatically.)
A UBX frame is two sync bytes (B5 62), a class + id that name the message, a little-endian payload length, the payload, and a two-byte Fletcher checksum over everything in between. pc_ubx_stream_feed is a byte-at-a-time state machine: it hunts for the sync bytes, reads the length, collects exactly that many payload bytes while running the checksum, and only emits a frame if the checksum matches - otherwise it resyncs. Any byte that is not part of a UBX frame is passed straight through, so an ordinary NMEA line assembler runs on the leftovers. Building is the reverse: pc_ubx_build frames a payload and appends the checksum; pc_ubx_build_poll sends the empty "please send me this message" request. All of it is fixed-size, no heap, and unit-tested on a PC (test/test_ubx, checked against the published u-blox poll frames); only the UART read/write runs on the ESP32. See src/services/timing_position/ubx/ubx.h and src/services/timing_position/nmea0183/nmea0183.h.