Cellular Connectivity

Cellular Connectivity

Bring LTE WAN to the Sixfab Edge AI Expansion Board on Raspberry Pi 5. This guide covers the M.2 Key-B modem slot, the nano SIM, antenna setup, and end-to-end data-connection bring-up with the Quectel CM Tool (quectel-cm) over QMI.

M.2 Key-B USB 3.2 Gen 1 (5 Gbps) 1× nano SIM nano eUICC supported Concurrent with NVMe + AI
Edge AI Expansion Board · Connectivity & Storage · Cellular Connectivity · Updated 2026-05-14 · Tutorial
How do I get LTE/5G connectivity on the Edge AI Expansion Board?

Install a Quectel M.2 Key-B modem into the CELLULAR LTE/5G slot, insert a nano SIM, attach antennas, and bring the link up with quectel-cm over QMI. The board does not include antennas; supply them according to your modem module. The modem appears as a USB device on the internal USB 3.2 Gen 1 hub (the same hub that carries the NVMe slot), so cellular and storage run independently and can be used together with active AI inference with no measurable AI-throughput degradation.

How the cellular path connects to Raspberry Pi 5

The Edge AI Expansion Board's CELLULAR LTE/5G slot is an M.2 Key-B socket wired into the board's internal USB 3.2 Gen 1 hub. The hub also carries the NVMe slot, and the hub itself reaches the Raspberry Pi 5 over a dedicated USB Bridge PCBA, not over the pogo pins, not over the PCIe FFC. The OS sees the modem as a standard USB cellular device on Bus 002.

Why this matters for setup

Because the modem reaches the Pi 5 over USB, no PCIe driver or extra kernel module is needed for the modem itself. Standard Linux USB cellular drivers (qmi_wwan, option, usbserial) that ship with Raspberry Pi OS handle enumeration. The hub and the bridge are entirely out-of-the-box for the kernel; what you configure is the modem and the connection manager on top of it.

The NVMe slot lives on the same internal USB hub. The hub splits the Pi 5's USB 3.0 bandwidth at hardware level, so the modem and the NVMe SSD enumerate as independent USB devices and can transfer data in parallel. AI inference runs on the separate PCIe path, which the cellular and storage subsystems do not touch.

What you need

Cellular bring-up needs four things in addition to a working Edge AI Expansion Board stack: the modem itself, a SIM card with active service, antennas suited to the modem, and the APN from your network operator.

M.2 Key-B LTE modem Required
The Quectel EM05-G Global M.2 Module (LTE Cat 4, 150 Mbps DL / 50 Mbps UL) is the validated module for the Edge AI Expansion Board. Any Quectel M.2 Key-B module that supports QMI mode also works with the flow on this page.
nano SIM or nano eUICC Required
The board has one nano SIM slot; there is no onboard eSIM chip, but nano-form eUICC ("programmable SIM") cards work in the same slot. The SIM must be activated by the carrier and not PIN-locked.
Antennas Required
The Expansion Board carries no built-in antennas. The EM05-G exposes three U.FL antenna interfaces: Main, Diversity, and GNSS. Use U.FL/IPEX pigtails sized to match.
Carrier APN Required
The Access Point Name for the operator. For Sixfab SIMs this is super; for other operators, consult the SIM documentation. Some plans also require username and password, but most do not.
Antenna connector types vary by module

The Expansion Board provides the M.2 socket; the RF connectors live on the modem module. The Quectel EM05-G uses U.FL/IPEX connectors for its Main, Diversity, and GNSS ports. Other Quectel families differ: the EC25/EG25 series uses U.FL as well, while many 5G modules use MHF4 and expose 4 ports for sub-6 MIMO. Always cross-check the module datasheet before ordering pigtails or external antennas.

Install the modem

The cellular slot is the third of the three M.2 slots, labelled CELLULAR LTE/5G on the silkscreen. Antenna pigtails attach to the modem before the module is seated, since the RF connectors face up and become awkward to reach once the module is screwed down.

Power off the Pi 5 before installing or removing the modem

The Edge AI Expansion Board is not hot-pluggable. Disconnect the USB-C power cable from the Expansion Board before inserting or removing any M.2 module, modem included. Hot-plugging risks the modem, the SIM, the SIM slot, and the board itself.

1

Insert the nano SIM card

Locate the nano SIM slot on the Expansion Board (push-pull tray on the side of the cellular M.2 slot). Insert the nano SIM with the contacts facing down and the chamfered corner aligned with the slot marking. Push until it clicks; the slot is spring-loaded.

nano eUICC cards work in the same slot. There is no electrical difference, only firmware-level profile management. If you are using a Sixfab eUICC card, profile provisioning happens after the connection is up.

Nano SIM card being inserted into the SIM slot on the Edge AI Expansion Board
2

Attach antenna pigtails to the modem

With the modem held by its edges, snap the antenna pigtails onto the modem's RF connectors. The Quectel EM05-G exposes three U.FL antenna interfaces: Main, Diversity, and GNSS. Attach the Main and Diversity pigtails for cellular operation, and optionally the GNSS pigtail if positioning is required.

Press straight down on each pigtail until you hear or feel a faint click. Do not rock or twist the connector. U.FL connectors are fragile and rated for a small number of mating cycles. If a connector fails to seat with light pressure, reposition rather than forcing it.

Quectel EM05-G modem with U.FL antenna pigtails attached to the Main, Diversity, and GNSS connectors
3

Seat the modem in the M.2 Key-B slot

Insert the modem into the CELLULAR LTE/5G slot at a 30-degree angle. The gold contacts on the modem edge must seat fully into the M.2 connector. The notch in the modem edge aligns with the Key-B key in the slot, which physically prevents installing the wrong-key module.

Quectel EM05-G modem inserted at a 30-degree angle into the CELLULAR LTE/5G M.2 Key-B slot
4

Secure the modem with an M2 × 6 mm flat-head screw

Press the modem flat against the board. Drive a single M2 × 6 mm flat-head screw through the mounting hole on the free end of the modem into the board's threaded standoff. Hand-tight is the spec; no power driver. The module should sit parallel to the board, locked in place, with the antenna pigtails routed away from the M.2 slots above.

M2 × 6 mm flat-head screw being driven through the modem mounting hole into the board standoff
5

Route antennas out of the enclosure

Route the antenna pigtails clear of the heatsink, the Pi 5 active cooler fan, and the M.2 modules above the cellular slot. Connect the external antennas (or the SMA bulkheads, if you are using a panel-mount setup) to the free ends of the pigtails. Power the Pi 5 back on once the antennas are physically attached and the SIM is fully seated.

Antenna pigtails routed clear of the heatsink and connected to external antennas on the assembled stack
Never power the modem without antennas attached

Operating the modem with no antenna (or with only one antenna on a multi-port modem) can damage the RF front end over time and registers as a high VSWR fault on some modules. Always attach antennas before powering up, and remove power before unseating an antenna pigtail.

Verify the modem enumerates on USB

Once the Pi 5 is back up with the modem installed, the modem should appear as a USB device on the internal hub. Verify this first, before touching any configuration: if lsusb does not list the modem, no amount of software setup will work.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# List USB devices and look for the modem on Bus 002
lsusb
Expected output Modem detected
# Example with a Quectel EM05-G installed alongside an NVMe SSD
Bus 002 Device 003: ID 2c7c:0125 Quectel Wireless Solutions Co., Ltd. EM05-G
Bus 002 Device 002: ID 0bda:9210 Realtek Semiconductor Corp. RTL9210 NVMe Bridge
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

The line you care about is the one with the Quectel VID:PID. Quectel's USB vendor ID is 2c7c; the product ID identifies the module. Common examples:

Quectel EM05-G Primary
LTE Cat 4 · Global
Default mode 2c7c:0125
QMI mode 2c7c:0125
Quectel EC25 LTE Cat 4
Default mode 2c7c:0125
QMI mode 2c7c:0125
Quectel EG25-G LTE Cat 4 · Global
Default mode 2c7c:0125
QMI mode 2c7c:0125

The VID:PID can change depending on the modem's USB composition mode (which interfaces it exposes). After you switch the modem to QMI mode in the next step, you may see the PID change. That is expected.

If lsusb shows no Quectel device

The first three things to check, in order:

  • The USB Bridge PCBA cable between the Expansion Board and the Raspberry Pi 5 is firmly seated. This single cable carries both the modem and the NVMe data, so if the NVMe also doesn't appear, the bridge is the most likely cause.
  • The modem is fully seated in the M.2 Key-B slot at the correct angle, and the M2 × 6 mm screw is tightened.
  • The PSU is at least 27 W. Modems are power-heavy, especially during registration; an under-spec PSU produces under-voltage events that disconnect USB devices.

Configure the modem for QMI mode

quectel-cm talks to the modem over QMI (Qualcomm MSM Interface). QMI is the default mode shipped from the Quectel factory on most modules, so this step is often a verification only. If the module has been reconfigured previously, for example, to ECM or MBIM, you must switch it back before quectel-cm will work.

Open a serial console to the modem's AT-command interface. Raspberry Pi OS auto-creates one or more /dev/ttyUSB nodes for the modem; the AT port is typically /dev/ttyUSB2 or /dev/ttyUSB3. Use any serial terminal you like; minicom is shown below at 115200 baud.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Install minicom if you don't already have a serial terminal
sudo apt install -y minicom

# Open the modem's AT-command port (adjust ttyUSB number for your module)
sudo minicom -D /dev/ttyUSB2 -b 115200

Once the terminal is open, send the two AT commands below. The first sets the USB network composition to QMI (usbnet=0); the second is a full-functionality reset (CFUN=1,1) that reboots the modem so the new mode takes effect.

modem.at · QMI mode switch AT
AT+QCFG="usbnet",0AT+CFUN=1,1

The modem will reboot automatically after AT+CFUN=1,1. Wait roughly 10 to 15 seconds for it to come back, then close the serial terminal and verify the QMI device node exists on the Pi 5:

bash · pi@raspberrypi: ~
After modem reboot
# Confirm the QMI character device is present
ls /dev/cdc-wdm*
Expected output QMI device ready
/dev/cdc-wdm0
Module compatibility

The AT+QCFG="usbnet" parameter is supported on the Quectel EM05-G as well as the broader EC25/EG25 and RM502Q series, which are the families Sixfab currently stocks and tests. quectel-cm supports most Quectel modules that implement the QMI protocol; USB network configuration and AT-command behaviour may vary across module families, so consult the official Quectel QConnectManager user guide for advanced or unusual modules.

/dev/cdc-wdm0 doesn't appear?

If the device node is missing, check the following:

  • The USB Bridge PCBA cable between the Expansion Board and the Pi 5 is securely connected.
  • The modem powered up; re-run lsusb and confirm the Quectel device is still listed.
  • The qmi_wwan kernel driver is loaded: lsmod | grep qmi_wwan.
  • The QMI mode switch actually applied; re-open the AT console and run AT+QCFG="usbnet" with no argument; the response should be +QCFG: "usbnet",0.

Build the Quectel CM Tool

quectel-cm is Quectel's official connection-manager utility for QMI modules. It handles network registration, IP-address acquisition over DHCP, DNS setup, and routing. The tool ships as source; Sixfab mirrors the canonical package from Quectel's QConnectManager release on sixfab.com.

Install the build prerequisites first. Raspberry Pi OS Bookworm and Trixie both work; any modern Debian-based distribution with Linux kernel 3.4 or newer is fine.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# 1. Refresh package lists and install build tools
sudo apt update
sudo apt install -y build-essential wget unzip

Then download the QConnectManager source, unzip it, rename the directory for clarity, and compile quectel-cm with make. The build is short and has no external dependencies beyond build-essential.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# 2. Move into your home directory
cd ~

# 3. Download QConnectManager source from Sixfab's mirror
wget https://sixfab.com/wp-content/uploads/2023/09/Quectel_QConnectManager_Linux_V1.6.5.zip

# 4. Unzip and rename for convenience
unzip -q Quectel_QConnectManager_Linux_V1.6.5.zip
mv Quectel_QConnectManager_Linux_V1.6.5 quectel-cm
cd quectel-cm

# 5. Build the quectel-cm binary
make

The build produces a single executable, quectel-cm, in the current directory. There is no make install step; the binary runs from wherever you built it. Many users keep it in ~/quectel-cm/; if you want it on the system PATH, copy it to /usr/local/bin/.

What about the default.script file?

The release tarball includes a default.script file alongside the binary. It is used by quectel-cm's built-in DHCP client to configure the WAN interface with the IP, DNS servers, and default route that the carrier assigns. Keep it in the same directory as the binary; no manual editing is needed for standard deployments.

Connect to the network

With the modem in QMI mode and quectel-cm built, you can bring up the data connection. The flow is straightforward: identify your APN, launch quectel-cm in the background, verify the wwan0 interface received an IP address, and test internet connectivity with ping.

Step 1: Find your APN

The APN identifies your network operator's data gateway. Without the correct APN, the modem will register on the cellular network but will not be able to open a data session. Common defaults:

Other carriers
APN Operator-specific

Consult the SIM documentation or contact the carrier. Some plans also require a username and password; most do not.

Step 2: Start the connection

Run quectel-cm with the -s flag followed by your APN. The trailing & sends it to the background so the shell remains usable for verification.

bash · pi@raspberrypi: ~/quectel-cm
On Raspberry Pi 5
# Launch the connection manager in the background (replace `super` with your APN)
sudo ./quectel-cm -s super &

quectel-cm will print a stream of status messages: it queries the modem, waits for network registration, opens a QMI data session, and starts a DHCP request on the WAN interface. Within a few seconds you should see a line confirming an IP address has been assigned to wwan0.

Step 3: Verify the WAN interface

Once the data session is up, quectel-cm brings the wwan0 network interface online with an IP address assigned by the carrier. Confirm it with ip a.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Inspect the wwan0 interface
ip a show wwan0
Expected output IP assigned
4: wwan0: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:50:f4:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 10.x.x.x/30 brd 10.x.x.x scope global dynamic noprefixroute wwan0
       valid_lft 7172sec preferred_lft 7172sec

The line you care about is inet 10.x.x.x. This is the IPv4 address the carrier handed out; it confirms that the modem registered, the APN was accepted, and the data session is open. Carrier-assigned addresses are typically in the carrier's private CGNAT range (often 10.x.x.x or 100.64.x.x); they are not directly routable from the public internet unless your plan includes a public IP.

Step 4: Test internet connectivity

The final check is a ping out the cellular interface. The -I wwan0 flag forces ping to use the cellular link rather than whichever default route the system picks; useful while Wi-Fi or Ethernet is also up.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Send three pings out the cellular interface
ping -I wwan0 -c 3 8.8.8.8
Expected output Cellular online
PING 8.8.8.8 (8.8.8.8) from 10.x.x.x wwan0: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=58 time=42.3 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=58 time=38.1 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=58 time=39.7 ms

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 38.1/40.0/42.3/1.7 ms

Three successful replies with 0% packet loss confirm that the cellular link is up and reaching the public internet. Typical LTE latency to a well-peered host like 8.8.8.8 sits in the 30–80 ms range; 5G NR sub-6 can drop into the 15–40 ms range. Spikes above 200 ms or sporadic packet loss usually indicate weak signal, cell-edge conditions, or carrier congestion.

Stopping the connection

To bring the cellular link down cleanly, terminate the quectel-cm background process. quectel-cm closes the QMI data session and releases the WAN interface as it exits.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Stop the connection manager and drop the data session
sudo killall quectel-cm

Run quectel-cm as a systemd service

For headless deployments, the cellular link must come up automatically at boot and recover from transient disconnects without manual intervention. The cleanest path on Raspberry Pi OS is a small systemd unit that supervises quectel-cm: it starts after networking is online, restarts on exit, and writes its output to the journal.

Move the binary somewhere stable, then create the unit. The recipe below assumes the binary lives at /usr/local/bin/quectel-cm with its default.script sitting alongside it. Adjust the APN to match your carrier.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# 1. Move the binary and its DHCP helper script to a system-wide location
sudo cp ~/quectel-cm/quectel-cm /usr/local/bin/
sudo cp ~/quectel-cm/default.script /usr/local/bin/
sudo chmod +x /usr/local/bin/quectel-cm /usr/local/bin/default.script

# 2. Create the systemd unit file
sudo tee /etc/systemd/system/quectel-cm.service >/dev/null <<'EOF'
/etc/systemd/system/quectel-cm.service INI
[Unit]Description=Quectel CM cellular connection managerAfter=network-online.target dev-cdc--wdm0.deviceWants=network-online.targetStartLimitIntervalSec=0 [Service]Type=simpleWorkingDirectory=/usr/local/binExecStart=/usr/local/bin/quectel-cm -s superRestart=on-failureRestartSec=10s [Install]WantedBy=multi-user.target

Save the unit with EOF, then enable and start it:

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# 3. Reload, enable on boot, start now
sudo systemctl daemon-reload
sudo systemctl enable --now quectel-cm.service

# 4. Confirm status and follow the journal
sudo systemctl status quectel-cm.service
sudo journalctl -u quectel-cm.service -f
How the recipe behaves

The After=dev-cdc--wdm0.device dependency makes systemd wait until the QMI character device exists before launching quectel-cm. That avoids the race where the unit starts before the kernel has finished probing the modem on cold boot. Restart=on-failure with a 10-second delay handles modem reboots, signal loss, and transient carrier failures without flooding the journal.

Signal quality and band locking

Once the link is up, the two most useful pieces of telemetry are the radio-link quality (RSRP, RSRQ, SINR, RSSI) and the band the modem chose. Both come out of the modem over the AT-command interface; the link itself stays up while you query.

Read signal quality with AT+QENG

Reopen the AT port (typically /dev/ttyUSB2) and issue AT+QENG="servingcell". The reply enumerates the serving cell along with the four canonical LTE quality metrics.

modem.at · serving-cell quality AT
AT+QENG="servingcell"
Example response Signal acquired
+QENG: "servingcell","NOCONN","LTE","FDD",286,01,1A2B3C4,123,1850,3,4,4,B2D9,-95,-11,-65,14,-

OK

The four metrics that matter, read left-to-right from the trailing block: RSRP, RSRQ, RSSI, SINR. The example shows RSRP -95 dBm, RSRQ -11 dB, RSSI -65 dBm, SINR 14 dB. The position field 3 is the LTE band number; field 286,01 is the MCC/MNC of the serving network.

Excellent
Good
Fair
Poor
RSRP dBm
≥ -80
-80 to -90
-90 to -100
≤ -100
RSRQ dB
≥ -10
-10 to -15
-15 to -20
≤ -20
SINR dB
≥ 20
13 to 20
0 to 13
≤ 0
RSSI dBm
≥ -65
-65 to -75
-75 to -85
≤ -85

Poll signal quality from a script

For monitoring loops, drive the AT port through a one-shot pipe rather than holding a long-running terminal. The snippet below opens /dev/ttyUSB2 at 115200 baud, sends the query, and waits 1 second for the response.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# One-shot AT query, returns the +QENG line for parsing
sudo stty -F /dev/ttyUSB2 115200 cs8 -cstopb -parenb raw
echo -e 'AT+QENG="servingcell"
' | sudo tee /dev/ttyUSB2 >/dev/null
sudo timeout 1 cat /dev/ttyUSB2

Lock to a specific network mode or band

The EM05-G is an LTE-only module and registers on LTE-FDD, LTE-TDD, WCDMA, and CDMA networks per region. Locking to a single radio access technology removes time spent on fallback handovers in poor coverage. The control AT command depends on the module family: AT+QCFG="nwscanmode" on EM05/EC25/EG25, and AT+QNWPREFCFG="mode_pref" on 5G modules like the RM5xx series.

modem.at · network-mode preference (EM05-G) AT
AT+QCFG="nwscanmode",3,1      // 0=auto, 1=GSM, 2=WCDMA, 3=LTE onlyAT+QCFG="nwscanseq",030201,1  // search order: LTE, WCDMA, GSMAT+QCFG="iotopmode",2,1       // 0=Cat M1, 1=NB-IoT, 2=both (Cat 4 ignores)

To lock to a specific LTE band, set the band mask. The mask is a hex bitfield: bit 0 = B1, bit 1 = B2, bit 2 = B3, and so on. The example below locks the EM05-G to LTE Band 3 (B3) and Band 7 (B7), the two dominant European LTE bands.

modem.at · LTE band lock AT
AT+QCFG="band",0,44,0,1       // GSM=0, LTE=0x44 (B3|B7), WCDMA=0, effective=immediate
Band lock can leave you with no service

Band locks persist across modem reboots. If the device moves to a region where the locked bands are not deployed, the modem registers nowhere and looks "dead". Always confirm the carrier and region bands before locking, and keep AT+QCFG="band",0,0,0,1 handy to clear the mask back to "all bands enabled".

GPS/GNSS positioning with the EM05-G

The Quectel EM05-G includes a dedicated GNSS receiver covering GPS, GLONASS, Galileo, and BeiDou. The receiver shares the modem's RF stage with the cellular path, so it can run concurrently with a data session. Position fixes come out over the same AT port as plain NMEA sentences or via a dedicated AT-command query. The GNSS antenna attaches to the third (Aux/GNSS) U.FL connector on the module.

Enable GNSS

GNSS is off by default to save power. Turn it on with AT+QGPS=1; this powers the receiver and starts acquisition. Time to first fix (TTFF) is typically 30 to 45 seconds cold-start with a clear sky, dropping to 1 to 5 seconds for a hot-start once almanac data has been cached.

modem.at · enable and configure GNSS (EM05-G) AT
AT+QGPSCFG="gnssconfig",1     // 1=GPS+BeiDou+Galileo+QZSS, 0=GPS onlyAT+QGPSCFG="outport","usbnmea" // stream NMEA on /dev/ttyUSB1AT+QGPS=1                     // power on the GNSS receiver

With outport=usbnmea, the modem creates an additional USB serial node (commonly /dev/ttyUSB1) that emits standard NMEA-0183 sentences continuously. Any GPS-aware library on the Pi 5 can read this directly.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Stream raw NMEA from the GNSS output port
sudo stty -F /dev/ttyUSB1 9600 raw
sudo cat /dev/ttyUSB1

One-shot position query

To pull a single fix without streaming NMEA, use AT+QGPSLOC=2 on the AT port. The format flag 2 returns latitude and longitude as decimal degrees (versus the default DMS).

modem.at · one-shot GNSS fix AT
AT+QGPSLOC=2
Example response Fix acquired
+QGPSLOC: 153045.0,41.012345,28.987654,1.2,87.5,3,0.00,0.0,0.0,150526,11

OK

The response fields, in order: UTC time (153045.0), latitude (41.012345°), longitude (28.987654°), HDOP (1.2), altitude in metres (87.5), fix type (3 = 3D fix), course, speed in km/h, speed in knots, UTC date (150526 = 15-May-26), and number of satellites in view (11). An HDOP under 2.0 and at least 7 satellites is typical for a clean fix.

To stop the receiver and save power, run AT+QGPSEND.

Concurrent cellular and GNSS

The EM05-G can run cellular data and GNSS simultaneously. The two share the modem's RF front end; the GNSS antenna is the dedicated third U.FL port. There is no need to bring the data session down to read a position fix.

Failover and data-usage monitoring

For production deployments, cellular usually sits behind a primary link (Wi-Fi or Ethernet) and steps in when the primary fails. Two pieces matter: a routing policy that prefers the primary, and a guard that watches cellular byte counters so a runaway process does not eat the data plan.

Wi-Fi or Ethernet to cellular failover

The simplest mechanism is routing-metric priority. Linux picks the default route with the lowest metric, so as long as Ethernet (eth0) carries a lower metric than cellular (wwan0), packets exit Ethernet whenever it is up. When Ethernet drops, the next-lowest-metric route (cellular) takes over automatically.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Inspect current default routes and their metrics
ip route show default

# Set Ethernet as primary (metric 100), cellular as backup (metric 700)
sudo ip route replace default via 192.168.1.1 dev eth0 metric 100
sudo ip route replace default dev wwan0 metric 700

For persistence across reboots, configure metrics in /etc/dhcpcd.conf with the metric directive per interface. For automatic dead-link detection (not just interface-down), add a short shell script driven by cron or a systemd timer that pings a known target through eth0 and rewrites the metric when the ping fails three times in a row. This is the standard Linux pattern and works equally well with NetworkManager when its connection.autoconnect-priority setting is used in place of raw metrics.

Watch cellular byte counters

The kernel keeps per-interface RX/TX counters in /sys/class/net/<iface>/statistics. A small vnstat install is the canonical way to roll these up into hourly, daily, and monthly totals on Raspberry Pi OS.

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Install vnstat and add the cellular interface
sudo apt install -y vnstat
sudo systemctl enable --now vnstat

# Show daily and monthly totals on wwan0
vnstat -i wwan0 -d
vnstat -i wwan0 -m

For ad-hoc inspection without vnstat, the raw counters are always available:

bash · pi@raspberrypi: ~
On Raspberry Pi 5
# Raw cumulative byte counters since interface came up
cat /sys/class/net/wwan0/statistics/rx_bytes
cat /sys/class/net/wwan0/statistics/tx_bytes

Diagnose registration and data-session issues

Two failure modes account for almost every "cellular doesn't work" report once the hardware is confirmed: the modem registers on the network but no data flows, or the modem is detected on USB but never registers. The diagnostics for each are distinct.

Modem detected but cannot register on a network

Symptom: lsusb shows the Quectel device, /dev/cdc-wdm0 exists, but quectel-cm hangs waiting for registration. The fault is in the radio layer or the SIM.

Check registration status with AT+CREG? on the AT port. The reply is +CREG: <n>,<stat> where stat is the answer:

0
Not registered, not searching

Modem is idle. Check AT+CFUN?; if it returns 0, send AT+CFUN=1 to wake the radio.

1
Registered, home network

Healthy. Radio attached to the home PLMN. Move on to data-session troubleshooting.

Not registered, searching

Coverage issue or band lock. Check the antennas are seated, then clear any band mask with AT+QCFG="band",0,0,0,1.

3
Registration denied

SIM rejected by the network. Confirm SIM activation status and that the carrier has whitelisted the modem's IMEI for this APN/plan.

4
Unknown

Modem is in a transient state, typically right after power-on or a CFUN reset. Retry the query after 30 seconds.

5
Registered, roaming

Healthy on a partner network. Confirm the data plan includes roaming, otherwise data may be billed at premium rates or blocked entirely.

Confirm the SIM is seen and unlocked with AT+CPIN?. The healthy reply is +CPIN: READY. Any other response means the SIM is missing, PIN-locked, or permanently failed.

modem.at · registration triage AT
AT+CPIN?              // SIM presence and PIN stateAT+CREG?              // 2G/3G registration statusAT+CEREG?             // LTE/EPS registration statusAT+COPS?              // currently selected operatorAT+CSQ                // RSSI and BER summary

Registered but no data flows

Symptom: AT+CREG? returns 1 or 5 (registered), but quectel-cm fails to bring wwan0 up or assigns an IP yet pings fail. The fault is at the PDN/APN layer.

First confirm the active APN matches the carrier's expectation. Read it with AT+CGDCONT?; the response lists each PDP context, one per line. Context 1 is the default data context.

modem.at · PDP context AT
AT+CGDCONT?                  // list current PDP contextsAT+CGDCONT=1,"IP","super"   // set context 1 to APN "super" (Sixfab SIMs)AT+CGACT?                    // active PDP contexts (1=active, 0=inactive)AT+CGACT=1,1                 // bring context 1 upAT+CGPADDR=1                  // IP address assigned to context 1

If AT+CGPADDR=1 returns an empty address despite an active context, the carrier rejected the data session. The two common causes are an incorrect APN and a SIM that is provisioned for voice/SMS but not data. Both are carrier-side issues and require contacting the operator.

Quick triage decision tree

On a fresh "it doesn't work" report, run these five commands in order. The first one to return an unexpected value points at the layer to debug.

bash · pi@raspberrypi: ~
Triage order
# 1. Is the modem on USB?           → if no, USB Bridge PCBA cable / power
lsusb | grep 2c7c

# 2. Does QMI exist?                → if no, AT+QCFG="usbnet",0 + AT+CFUN=1,1
ls /dev/cdc-wdm*

# 3. SIM ready?                     → AT+CPIN? must be READY
# 4. Registered?                    → AT+CREG? and AT+CEREG? must be 1 or 5
# 5. Data session up?               → ip a show wwan0 must show inet

Concurrent operation with NVMe and AI inference

All three Expansion Board subsystems (NPU, NVMe, cellular) can run simultaneously with no measurable degradation in AI throughput. The cellular and NVMe paths share the internal USB hub but each gets independent USB endpoints, and the AI accelerator runs on a separate PCIe link entirely.

Validated production pattern

Sixfab has validated the canonical "smart-camera" workload (continuous YOLO inference on the DEEPX NPU, frame storage to the NVMe SSD, and uplink over LTE) with no measurable drop in AI throughput. The PCIe link to the NPU is electrically isolated from the USB path that carries cellular and storage, so the only practical ceiling is the 5 Gbps USB bus that the cellular and storage subsystems share.

Two practical limits to keep in mind when running all three subsystems concurrently:

  • USB current ceiling. All USB ports on the Raspberry Pi 5 share a 1.6 A total-current budget. Modems are power-heavy, especially during transmit; NVMe SSDs draw their own current. Use the minimum 27 W (and recommended 45 W) USB-C PD PSU to keep the system from triggering under-voltage warnings under load.
  • Antenna placement matters more under load. A modem operating at the edge of coverage will boost transmit power, increasing thermals and current draw. If the AI workload is also running hot, place the cellular antennas as far from the Pi 5's metal heatsink and any conductive enclosure surfaces as practical.