The NEO-6M gives position, altitude and UTC time over a serial line at 9600 baud. The S3 has three hardware UARTs, so the GPS gets its own (Serial1) while USB keeps the Serial Monitor.
The S3-specific detail is the pin assignment: pass RX 18 / TX 17 to Serial1.begin() rather than relying on the core’s defaults. Take the board outdoors or near a window for the first fix.
Wiring
| ESP32-S3-DevKitC-1 | NEO-6M GPS module (GY-NEO6MV2) | Wire | Notes |
|---|---|---|---|
| 5V | VCC | red | The module has its own 3.3 V regulator. |
| GND | GND | black | |
| 18 | TX | yellow | GPS TX → S3 RX (GPIO18). 3.3 V signal. |
| 17 | RX | green | S3 TX (GPIO17) → GPS RX. Only needed to send config commands. |
3.3–5 V (on-board 3.3 V regulator) part, 3.3 V board. The module’s TX is a 3.3 V signal, which every board reads fine. Its RX pin is 3.3 V logic: from a 5 V Arduino TX, add a 1 kΩ / 2 kΩ divider. You only need RX if your sketch sends configuration commands.
Board quirks
- Arduino core 3.x starts
Serial1on RX 15 / TX 16 on the S3 unless you pass pins. The sketch callsSerial1.begin(9600, SERIAL_8N1, 18, 17), matching the S3’s native UART1 pins. - Don’t use TX/RX (GPIO43/44) for the GPS: they are UART0, wired to the USB bridge behind the UART port, and carry your Serial Monitor.
- The module’s TX is a 3.3 V signal even on 5 V power, so it connects directly to the S3.
- First fix needs open sky and can take 2–5 minutes (cold start). The blue LED on the module blinks once a second when it has a fix.
Code
// NEO-6M GPS on an ESP32-S3-DevKitC-1 via UART1.
// VCC → 5V, GND → GND, GPS TX → GPIO18 (S3 RX), GPS RX → GPIO17 (S3 TX).
// Arduino core 3.x defaults Serial1 to RX 15 / TX 16 on the S3, so the pins are passed explicitly.
#include <TinyGPSPlus.h>
constexpr int GPS_RX = 18; // S3 receives on GPIO18 from GPS TX
constexpr int GPS_TX = 17; // S3 transmits on GPIO17 to GPS RX
TinyGPSPlus gps;
void setup() {
Serial.begin(115200); // UART USB-C port
Serial1.begin(9600, SERIAL_8N1, GPS_RX, GPS_TX);
Serial.println("NEO-6M on Serial1 (RX 18, TX 17) - first fix can take a few minutes outdoors");
}
void loop() {
while (Serial1.available()) gps.encode(Serial1.read());
static uint32_t last = 0;
if (millis() - last < 2000) return;
last = millis();
if (gps.charsProcessed() < 10) {
Serial.println("No data from GPS - check GPS TX to GPIO18 and power");
} else if (!gps.location.isValid()) {
Serial.printf("Waiting for fix... satellites: %lu\n", (unsigned long)gps.satellites.value());
} else {
Serial.printf("Lat %.6f Lng %.6f Sats %lu Alt %.0f m %02d:%02d:%02d UTC\n",
gps.location.lat(), gps.location.lng(), (unsigned long)gps.satellites.value(),
gps.altitude.meters(), gps.time.hour(), gps.time.minute(), gps.time.second());
}
}// NEO-6M GPS on an ESP32-S3-DevKitC-1 via UART1.
// VCC → 5V, GND → GND, GPS TX → GPIO18 (S3 RX), GPS RX → GPIO17 (S3 TX).
// Arduino core 3.x defaults Serial1 to RX 15 / TX 16 on the S3, so the pins are passed explicitly.
#include <TinyGPSPlus.h>
constexpr int GPS_RX = 18; // S3 receives on GPIO18 from GPS TX
constexpr int GPS_TX = 17; // S3 transmits on GPIO17 to GPS RX
TinyGPSPlus gps;
void setup() {
Serial.begin(115200); // UART USB-C port
Serial1.begin(9600, SERIAL_8N1, GPS_RX, GPS_TX);
Serial.println("NEO-6M on Serial1 (RX 18, TX 17) - first fix can take a few minutes outdoors");
}
void loop() {
while (Serial1.available()) gps.encode(Serial1.read());
static uint32_t last = 0;
if (millis() - last < 2000) return;
last = millis();
if (gps.charsProcessed() < 10) {
Serial.println("No data from GPS - check GPS TX to GPIO18 and power");
} else if (!gps.location.isValid()) {
Serial.printf("Waiting for fix... satellites: %lu\n", (unsigned long)gps.satellites.value());
} else {
Serial.printf("Lat %.6f Lng %.6f Sats %lu Alt %.0f m %02d:%02d:%02d UTC\n",
gps.location.lat(), gps.location.lng(), (unsigned long)gps.satellites.value(),
gps.altitude.meters(), gps.time.hour(), gps.time.minute(), gps.time.second());
}
}Library: TinyGPSPlus (Mikal Hart) — compiled with TinyGPSPlus 1.0.3.
Expected serial output
NEO-6M on Serial1 (RX 18, TX 17) - first fix can take a few minutes outdoors
Waiting for fix... satellites: 3
Lat 12.971599 Lng 77.594566 Sats 8 Alt 921 m 06:41:12 UTCNEO-6M on Serial1 (RX 18, TX 17) - first fix can take a few minutes outdoors Waiting for fix... satellites: 3 Lat 12.971599 Lng 77.594566 Sats 8 Alt 921 m 06:41:12 UTC
Common errors
“No data from GPS”
TX and RX crossed the wrong way, or the pins weren’t passed to Serial1.begin(). GPS TX must go to GPIO18.
Data but never a fix
Indoors or under a concrete roof. Full fix.