Files
orin-nano-env-setup/docs/impl/reports/SIM7600-SETUP.md
T
2026-10-09 16:39:41 +09:00

8.6 KiB
Raw Blame History

type, date
type date
report 2026-10-07

SIM7600G-H-M.2 (LTE + GNSS) Setup on Jetson Orin Nano

Result

Item State
LTE data via ModemManager + NetworkManager (QMI, wwan0) Working: IPv4 + IPv6, ~9 Mbit/s DL observed
Route priority: Ethernet (100) > WiFi (600) > LTE (1000) Working
GNSS engine + gpsd on /dev/sim7600-gps Working: first 3D fix 2026-10-09 in the car (indoors: satellites seen, no fix)

Hardware

  • Board: Jetson Orin Nano, hostname mikkeli-orin-nano, kernel 5.15.148-tegra (L4T 36.4.4)
  • Modem: Waveshare SIM7600G-H-M.2 on the SIM7600G-H-M2 4G HAT, connected over USB
    • USB ID 1e0e:9001 (default composition, AT+CUSBPIDSWITCH? → 9001)
    • Firmware LE20B04SIM7600G-H-M2 / SIM7600G_V2.0.2
  • SIM: povo (KDDI/au MVNO), APN povo.jp, no user/password. Registers as KDDI KDDI (44051), LTE band 18.

USB interfaces (PID 9001)

Iface Port Driver Role (as ModemManager sees it)
0 ttyUSB0 option diagnostics (ignored)
1 ttyUSB1 option NMEA GPS → /dev/sim7600-gps
2 ttyUSB2 option AT (primary)
3 ttyUSB3 option AT
4 ttyUSB4 option audio
5 cdc-wdm0 + wwan0 qmi_wwan (self-built) QMI control + network

Problems hit and fixes

1. sim-missing: SIM inserted after the modem powered up

ModemManager reported failed reason: sim-missing, but AT+CPIN? returned READY. SIM hot-swap is off on this module (AT+UIMHOTSWAPON: 0), so a SIM seated after power-on isn't noticed until the modem re-initializes. Restarting ModemManager (or re-plugging the modem) fixes it.

Hot-swap was deliberately left off. Turning it on needs the right AT+UIMHOTSWAPLEVEL for the HAT's SIM-detect wiring, and getting that wrong makes the modem report "no SIM" permanently. Insert the SIM before powering the modem.

2. Tegra kernel has no qmi_wwan / cdc-wdm

CONFIG_USB_NET_QMI_WWAN and CONFIG_USB_WDM are unset in the stock L4T kernel, so interface 5 had no driver, leaving PPP over a ttyUSB port as the only data path. Fixed by building both modules out of tree from upstream stable v5.15.148 (see rebuild).

3. PPP dial causes NW DETACH on KDDI

With PPP, every ATD*99***<cid># ended about 32 s later with NO CARRIER + +CGEV: NW DETACH, +CEER: No service available. Two causes:

  • PDP context 1 (the LTE initial-attach APN) was preset to au.au-net.ne.jp, which a povo SIM can't use, and ModemManager put povo.jp on a new context 5. Fixed by setting context 1 to povo.jp (see below). After that the attach itself brings up a default bearer with an address.
  • Even with that fixed, a PPP dial on context 1 still triggered a network detach: PPP tries to activate a context that is already the active default bearer. QMI does not have this problem: it uses the existing default bearer. Do not use PPP with this SIM.

Setting the attach APN (with ModemManager stopped; the setting persists in modem NVRAM):

AT+CFUN=4                          # radio off, SIM stays powered (CFUN=0 powers the SIM down → CGDCONT returns ERROR)
AT+CGDCONT=1,"IPV4V6","povo.jp"
AT+CGDCONT=5                       # remove stray contexts ModemManager had created
AT+CFUN=1
AT+CGPADDR=1                       # should now show an IPv4 + IPv6 address

Configuration applied

Kernel modules

Source + Makefile live in ~/infra/qmi_wwan/ (per GUIDELINES §1):

~/infra/qmi_wwan/
├── Makefile        # obj-m += cdc-wdm.o qmi_wwan.o ; `make install` → /lib/modules/$(uname -r)/misc/ + depmod
├── cdc-wdm.c       # linux-stable v5.15.148 drivers/usb/class/cdc-wdm.c
└── qmi_wwan.c      # linux-stable v5.15.148 drivers/net/usb/qmi_wwan.c (has QMI_QUIRK_SET_DTR(0x1e0e, 0x9001, 5))

Installed to /lib/modules/5.15.148-tegra/misc/{cdc-wdm,qmi_wwan}.ko. They auto-load through the USB modalias after depmod, so no /etc/modules entry is needed.

NetworkManager connection povo

sudo nmcli con add type gsm ifname '*' con-name povo gsm.apn povo.jp \
    connection.autoconnect yes connection.autoconnect-retries 0 \
    ipv4.route-metric 1000 ipv6.route-metric 1000 ipv6.method auto
  • ifname '*': binds to whichever modem ModemManager exposes (now cdc-wdm0).
  • connection.metered yes (added 2026-10-08): marks LTE as metered so bulk transfers can refuse it. Project Yukart's map-tile sync uses this as its second guard (LAN-only rsync).
  • autoconnect-retries 0 (forever): the default of 4 retries left the link permanently down after early failures. In a car, the modem may come up after NetworkManager.
  • Metric 1000 vs NM defaults Ethernet 100 / WiFi 600 → LTE only carries traffic when both are gone. Right after connecting the route can briefly show metric 21000 (NM's +20000 penalty until its connectivity check passes); it settles to 1000.

Check:

mmcli -m any                        # state: connected, primary port: cdc-wdm0
ip route show default               # wlP1p1s0 metric 600, wwan0 metric 1000
curl --interface wwan0 https://ifconfig.me

Failover test (2026-10-08)

Ran /usr/local/sbin/lte-failover-test.sh as a detached unit (systemd-run --unit=lte-failover-test). It turns the WiFi radio off for 180 s, samples every 10 s, then turns it back on, logging to /var/log/lte-failover-test.log. A wifi-failsafe timer (systemd-run --on-active=10min nmcli radio wifi on) was armed first, so a broken LTE path couldn't lock out a remote session.

Phase Default route Public IPv4 Ping 1.1.1.1 Tailscale → halogen
WiFi on wlP1p1s0 (600) home ISP ~12 ms direct, LAN (3–4 ms)
WiFi off wwan0 (1000), within 10 s KDDI 106.128.x.x 25–55 ms direct over IPv6 to halogen's home IPv6 (40–85 ms), no DERP relay
WiFi back wlP1p1s0; IPv4 within 15 s, IPv6 within ~45 s (NM connectivity check) home ISP ~12 ms direct, LAN

Zero failed samples (IPv4, DNS, Tailscale ping). An SSH session over Tailscale stayed up across both switches. Carrier CGNAT on IPv4 doesn't matter because povo gives a global IPv6 address, which Tailscale uses for a direct path.

Note: wwan0 also gets a kernel-installed IPv6 RA default route at metric 1024. That still ranks below WiFi (600) and only wins during the brief NM connectivity-check penalty (+20000) after WiFi returns.

GNSS

  • GNSS engine was already running (AT+CGPS? → 1,1). Set to start on boot: AT+CGPSAUTO=1 (persists in modem).
  • ModemManager location is not used. gpsd owns the NMEA port; ModemManager only labels it (gps) and leaves it unopened.
  • Stable device name, /etc/udev/rules.d/99-sim7600-gps.rules:
    SUBSYSTEM=="tty", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{ID_USB_INTERFACE_NUM}=="01", SYMLINK+="sim7600-gps"
    
  • apt install gpsd gpsd-clients, /etc/default/gpsd:
    DEVICES="/dev/sim7600-gps"
    GPSD_OPTIONS="-n"
    USBAUTO="false"     # hotplug would let gpsd probe the modem's AT ports and conflict with ModemManager
    
  • systemctl enable --now gpsd.socket gpsd

Check: cgps or gpspipe -w -n 10. On 2026-10-07, tested indoors, gpsd saw nSat: 10, uSat: 0, mode: 1 (no fix). Next: test with the GNSS antenna (IPEX, labeled GNSS on the HAT) with a clear view of the sky. A cold start can take a few minutes.

2026-10-09, in the car: first fix, mode: 3 (3D) with 4 of 9 satellites used, GPS time valid. Passive GNSS antenna on the dashboard, facing the sky. No setup changes were needed; the indoor tests simply lacked sky view. If fixes prove slow or drop out while driving, try an active antenna (check the HAT supplies antenna bias first).

Rebuilding qmi_wwan after a kernel update

Out-of-tree modules do not survive a kernel update. Signs: ModemManager shows primary port: ttyUSB2 and there is no /dev/cdc-wdm0.

cd ~/infra/qmi_wwan
# if the kernel's upstream base version changed, refresh the sources:
#   V=v5.15.xxx; for f in drivers/net/usb/qmi_wwan.c drivers/usb/class/cdc-wdm.c; do
#     curl -fL -o $(basename $f) "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/$f?h=$V"; done
make clean && make && sudo make install
sudo modprobe qmi_wwan && sudo systemctl restart ModemManager

Useful one-offs

  • Talk to the modem directly: sudo systemctl stop ModemManager, then use a terminal on /dev/ttyUSB2; start ModemManager again afterwards. (ModemManager holds ttyUSB2/3 while running.)
  • Verbose ModemManager log incl. AT traffic: sudo mmcli -G debug then journalctl -u ModemManager -f (resets on restart).