A field‑tested guide to getting the Waveshare SIM7080G Cat‑M/NB‑IoT HAT talking, registering on a cellular network, and providing internet on a Raspberry Pi over the GPIO‑header UART (no USB).
Everything here was learned the hard way on a real deployment (Raspberry Pi Zero 2 W, Telstra Cat‑M1 in Australia). The steps are generic; carrier‑specific values (band, APN) are called out and use Telstra Australia as the worked example — substitute your own.
TL;DR of the four things that will waste your afternoon:
- The PWRKEY line (BCM GPIO4) floats by default and makes the module power‑cycle every ~15 s — looks exactly like a random power fault. Hold it low:
gpio=4=op,dl.- You must disable Bluetooth to get the good UART (PL011). Otherwise you're on the flaky mini‑UART and baud rates drift.
- The modem scans every band by default (can take ~20 min) — lock it to your carrier's band or it looks like "no signal".
- Cat‑M/LTE TX current spikes (~2 A) sag the 5 V rail and reset the module. Add a 1000 µF capacitor across VCC/GND — see docs/hardware-and-wiring.md.
- Hardware & wiring (incl. the capacitor mod)
- UART setup — disable Bluetooth, use the PL011
- Power control — the PWRKEY / GPIO4 gotcha
- Talking to the modem — baud & AT commands
- Registering on the network — mode, band lock, APN
- Power supply & the capacitor
- Internet over PPP
- GNSS / GPS (optional)
- Troubleshooting
- Scripts
- HAT: Waveshare SIM7080G Cat‑M/NB‑IoT HAT (SIMCom SIM7080G module).
- Host: any 40‑pin Raspberry Pi (tested on a Pi Zero 2 W).
- Link: the module's UART is wired to the Pi's GPIO‑header UART
(GPIO14 TXD / GPIO15 RXD). In this configuration the HAT presents no USB
device —
lsusbwill only show the root hub. All control is over the serial port and GPIO. - Antenna: the main cellular connector (not the GNSS one — they're separate u.FL sockets). Use an antenna that covers your carrier's band.
- Power: the HAT draws its 5 V from the Pi header. This is the weak spot — see §6.
Some Waveshare SIM7080G boards have a jumper that routes the module's UART either to an on‑board USB‑UART bridge (a USB‑C port) or to the GPIO header. This guide assumes the GPIO‑header route. Check your board's jumper if you can't find the device on
/dev/serial0.
Full wiring details and the 1000 µF capacitor mod are in docs/hardware-and-wiring.md.
Free up the good UART (the PL011, aka ttyAMA0) by disabling Bluetooth, and
turn off the serial login console so it doesn't fight you for the port.
Edit /boot/firmware/config.txt (Raspberry Pi OS Bookworm; on older
releases it's /boot/config.txt):
enable_uart=1
dtoverlay=disable-bt
# Hold the modem's PWRKEY line released so the module powers on and STAYS on
# (see section 3 — this line is essential):
gpio=4=op,dlThen disable the serial console:
sudo raspi-config # Interface Options → Serial Port → login shell: NO, hardware: YES
# or edit /boot/firmware/cmdline.txt and remove any `console=serial0,115200`
sudo systemctl disable --now hciuart # belt-and-braces: stop BT grabbing the UART
sudo rebootAfter the reboot, verify:
ls -l /dev/serial0 # → ...ttyAMA0 (GOOD: the PL011)
# ...ttyS0 (BAD: the mini-UART — BT not disabled)
pinctrl get 14 15 # → a0 (ALT0), not a5Why this matters: the mini‑UART (ttyS0) derives its clock from the VPU
core frequency, so its real baud rate drifts as the Pi throttles — you get
intermittent garbage and "no response" on the modem. The PL011 (ttyAMA0) has
a stable clock. Always end up on ttyAMA0.
This is the single most confusing part of the board, so read it carefully.
The module's PWRKEY is wired to BCM GPIO4 through an inverting driver:
| GPIO4 state | PWRKEY | Effect |
|---|---|---|
| driven LOW | released (idle) | module runs normally |
| driven HIGH | pressed | a sustained press toggles power |
| floating (default at boot!) | self‑pressing | module power‑cycles every ~15 s |
If you do nothing, GPIO4 boots as a floating input, the PWRKEY "presses itself", and the module turns on… then a sustained press turns it off ~11 s later… then on again… forever. This looks exactly like a flaky power supply or random resets. It is not — it's the floating pin.
Fix (already in the config.txt above):
gpio=4=op,dl # drive GPIO4 output-low from boot = PWRKEY released = stableToggling power in software (e.g. to duty‑cycle the modem for battery use):
pulse GPIO4 high for ~1.5 s, then back low — that's one PWRKEY press, which
toggles the module on↔off. Confirm the new state by whether it answers AT.
See scripts/modem_power.sh.
./scripts/modem_power.sh # pulse PWRKEY: powers the module on if off, off if onBaud rate: on this HAT over the PL011, 57600 was the reliable rate — not the commonly‑cited 115200. Lock it so it stops auto‑baud‑guessing:
AT+IPR=57600 # persists across power cycles
The very first
ATafter opening the port (or after changing baud) often gets no reply while the module auto‑syncs — always sendATat least twice before concluding a baud rate is wrong.
Quick sanity checks (use scripts/modem_at.py):
./scripts/modem_at.py "AT" "AT" "ATI" "AT+CPIN?" "AT+CSQ" "AT+CEREG?"| Command | Expect | Meaning |
|---|---|---|
AT |
OK |
module alive |
ATI |
SIM7080... |
firmware/model |
AT+CPIN? |
+CPIN: READY |
SIM present & unlocked |
AT+CSQ |
+CSQ: <rssi>,99 |
signal (see note below) |
AT+CEREG? |
+CEREG: 0,1 |
registered (1=home, 5=roaming) |
Don't trust
AT+CSQas your health signal — some SIM7080/7028 firmware reports99,99(undetectable) even while camped and registered. UseAT+CEREG?instead (enable unsolicited reports withAT+CEREG=2).
Three things have to be right: radio access technology, band, and APN.
AT+CNMP=38 # network mode: LTE only
AT+CMNB=1 # LTE-M mode: Cat-M1 only
# (default is often NB-IoT (2) — many
# consumer networks don't offer NB-IoT)
AT+CBANDCFG="CAT-M",28 # BAND LOCK — see below. 28 = Telstra AU (700MHz)
AT+CGDCONT=1,"IP","telstra.internet" # APN (yours will differ)
AT+CFUN=0 # cycle the radio to apply the band change
AT+CFUN=1
The band‑lock is the big time‑saver. By default the module scans every
supported band (17+), and per SIMCom's network‑search app note that can take
up to ~20 minutes before it concludes anything — during which
AT+CEREG?/AT+CPSI? just say NO SERVICE and it looks broken. Locking to
your carrier's single band cuts registration to ~1–2 minutes.
Find your carrier's Cat‑M1 band (examples):
| Carrier / region | Cat‑M1 band | AT+CBANDCFG |
|---|---|---|
| Telstra (Australia) | B28 (700 MHz) | AT+CBANDCFG="CAT-M",28 |
| AT&T (US) | B12 | AT+CBANDCFG="CAT-M",12 |
| Verizon (US) | B13 | AT+CBANDCFG="CAT-M",13 |
| Vodafone (EU) | B20 | AT+CBANDCFG="CAT-M",20 |
Confirm registration:
AT+CEREG? # → +CEREG: 0,1 (registered, home)
AT+CPSI? # → detail: LTE CAT-M1, band, cell id, RSRP...
SIM notes (from real experience):
- A standard consumer Telstra SIM works on Cat‑M1 — no special IoT plan needed for LTE‑M.
- Telstra NB‑IoT is different — it needs a business/IoT‑data SIM; consumer SIMs are rejected at attach (EMM cause 12, "tracking area not allowed"). If you only have NB‑IoT coverage, budget for the right SIM.
AT+CBANDCFGandAT+CNMP/AT+CMNBpersist in NVM.AT&WreturnsERRORon this module — it doesn't support the classic Hayes save; that's fine.
SIM7028 (NB‑IoT‑only sibling board): the band‑lock syntax is different —
AT+QCBAND=0,28(the leading0mode digit is required;AT+QCBAND=28returnsERROR). Set it with the radio off (AT+CFUN=0first).
This is the fix most people are missing. A Cat‑M1/LTE module pulls a short, sharp current spike (~2 A peak on Band 28) each time it transmits. The Pi's 5 V rail and the HAT's header pins have enough resistance/inductance that the voltage briefly sags under that spike, which either:
- resets the module mid‑registration (registration cycles 1→2→1 and never
holds; volatile settings like
AT+CEREG=2revert within seconds), or - browns out the whole Pi and reboots it.
vcgencmd get_throttled reading 0x0 does not rule this out — the
sags are fast transients that reset the SoC without latching the sticky
under‑voltage flag.
Add bulk capacitance across the modem's VCC (5 V) and GND to act as a local energy reservoir that supplies the TX spike so the rail doesn't sag:
- Value: 1000 µF (470–1000 µF works), low‑ESR electrolytic, ≥ 6.3 V rating (10 V+ preferred).
- Where: directly across the HAT's VCC (5 V) and GND pins, as close to the module as possible.
- Polarity — important: an electrolytic is polarised. The striped side is the negative leg → GND; the other leg → VCC/5 V. A reversed electrolytic gets hot and can vent. Double‑check before powering on, and touch‑test that it stays cool.
Pi/HAT 5V rail (VCC) ───────────┬───────────► to SIM7080G VCC
│
+ ───┴─── 1000 µF low-ESR
═══════════ electrolytic
- ───┬─── (stripe = − = GND)
│
Pi/HAT GND ──────────────────────┴───────────► to SIM7080G GND
Also worth doing (any combination):
- Feed the Pi from a genuine 2.5–3 A 5 V supply with a short, thick cable.
- Or give the HAT its own 5 V supply, sharing a common ground with the Pi.
After adding the cap, confirm the fix: registration should now hold (a
steady +CEREG: 0,1) instead of cycling, and journalctl --list-boots should
stop showing short, unexpected reboots.
Once registered, dial a PPP data session to get an ppp0 network interface.
sudo apt install pppCopy the example configs (edit the APN/band for your carrier):
sudo cp config/ppp/peers/telstra /etc/ppp/peers/telstra
sudo cp config/ppp/chatscripts/sim7080-telstra /etc/chatscripts/sim7080-telstra
sudo pppd call telstra # brings up ppp0 with a cellular IPVerify:
ip -4 addr show ppp0 # → an inet address (e.g. 10.x.x.x)
ping -I ppp0 -c3 1.1.1.1 # data path works over cellular
sudo poff telstra # tear downThe example dials ATD*99# on the telstra.internet context at 57600 baud
with nocrtscts (the GPIO UART has no hardware flow control). See
config/ppp/ and the comments in the peer file.
The SIM7080G has an integrated GNSS receiver on a separate antenna connector.
AT+CGNSPWR=1 # power on GNSS
AT+CGNSINF # +CGNSINF: <run>,<fix>,<utc>,<lat>,<lon>,...
AT+CGNSPWR=0 # power off to save current when not needed
A fix needs a GNSS antenna on the GPS connector (not the cellular one) and
a clear view of the sky; cold‑start TTFF is ~0.5–several minutes. fix=0 with
lat/lon = 0.000000 means no fix yet (usually no/bad antenna or no sky view).
| Script | Purpose |
|---|---|
scripts/modem_at.py |
Send AT commands and print replies (./modem_at.py "AT" "AT+CEREG?") |
scripts/modem_power.sh |
Pulse the PWRKEY (GPIO4) to toggle module power |
scripts/modem_raw_capture.py |
Dump raw UART bytes — for diagnosing baud/framing issues |
Python scripts need pyserial (pip install pyserial); modem_power.sh uses
pinctrl (ships with Raspberry Pi OS).
Written up from a real Cat‑M1 deployment. Contributions welcome — especially band/APN values for other carriers and notes on other SIM7080G board variants. Licensed under MIT.
This guide is not affiliated with Waveshare or SIMCom. AT commands follow the SIM7070_SIM7080_SIM7090 Series AT Command Manual; consult it for the authoritative reference.