Version 13 (modified by Ron Eisworth, 5 years ago) ( diff )


GW16126 miniPCIe BLE / LTE Cat-M1 modem

The GW16126 is a miniPCIe form-factor card that features both a BLE 5.0 radio and a Cat-M1 modem designed for the IoT market.

The GW16126 interfaces with a host over USB 2.0 and uses the following pins on the miniPCIe card edge:

  • GND: pin 4,9,15,18,21,26,27,29,34,35,40,43,50
  • VDD_3P3: pin 2,24,39,41,52
  • USB_DM: pin 36
  • USB_DP: pin 38

Power draw varies greatly with the activity of the LTE Cat-M1 modem but typically varies between the milliwatt range to a max of around 2W

On the USB bus the following are present:

  • USB2514 USB 2.0 2-port HUB
    • FT231X USB UART connected to a u-blox NINA-B30x BLE module
    • u-blox NINA-B301 BLE module USB 2.0 controller
    • u-blox SARA-R4 Cat M-1 / NB1 modem with nano-SIM socket

These look like the following with lsusb:

ID 05c6:90b2 Qualcomm, Inc. 
ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)
ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub

The following devices will be created by the kernel modules:

  • /dev/ttyUSB0 (hci_uart) (CONFIG_BT_HCIUART, CONFIG_BT_HCIUART_H4 hci_uart)
  • /dev/ttyUSB1 (qcdm) (CONFIG_USB_SERIAL_OPTION option)
  • /dev/ttyUSB2 (at) (CONFIG_USB_SERIAL_OPTION option)
  • /dev/cdc-wdm0 (qmi) (CONFIG_USB_NET_QMI_WWAN qmi_wwan)
  • /sys/class/net/wwan0 (net) (CONFIG_USB_NET_QMI_WWAN qmi_wwan)

The drivers do not add the modem device ID (05c6:90b2) until mainline kernel 4.17.

If for some reason you don't have all the drivers enabled above or have them static, you may find the /dev/ttyUSB devices enumerate in a different order. You can use a variety of ways to determine which device is which:

  • mmcli -m 0 will report details about detected modems and what devices they are on
  • ls -d /sys/bus/usb/drivers/ftdi_sio/*/ttyUSB* will tell you which tty is attached to the ftdi_sio driver to attach the Bluetooth HCI_UART to
  • ls -d /sys/bus/usb/drivers/option/*/ttyUSB* will tell you which tty's are attached to the option driver for the modem.

u-blox SARA-R4 LTE Cat M-1 modem

The u-blox SARA-R410M-52B LTE Cat M1 modem supports M1 bands 2,4,5,12,13. For more info on the CATM1 standard and use cases see the following CATM1 Explained Link.

The modem features a Qualcomm chipset that uses the 'option' and 'qmi_wwan' Linux drivers providing the following devices:

  • /dev/ttyUSB1 (qcdm)
  • /dev/ttyUSB2
  • /dev/cdc-wdm0 (qmi)
  • /sys/class/net/wwan0 (net)

The modem is supported by Linux ModemManager and libqmi-utils.

General modem information that should be understood is located on the Gateworks Modem Wiki Page

Note, because this modem uses raw-ip, DHCP does not work and a IP will not automatically be applied to the interface. The provider will give an IP and then it must manually be applied to the wwan0 interface.

Examples: (set APN env var appropriately)

  • Ubuntu using NetworkManager:
    root@xenial-newport:~# nmcli --version
    nmcli tool, version 1.2.6
    root@xenial-newport:~# nmcli connection down id 'Wired connection 1'
    Connection 'Wired connection 1' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/0)
    root@xenial-newport:~# nmcli connection add type gsm ifname cdc-wdm0 con-name mymodem apn $APN
    Connection 'mymodem' (1c6d1b7f-2c89-4e21-93ee-231073605578) successfully added.
    root@xenial-newport:~# nmcli connection up id mymodem 
    Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3)
    root@xenial-newport:~# ifconfig wwan0
    wwan0     Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
              inet addr:  P-t-P:  Mask:
              RX packets:581 errors:0 dropped:0 overruns:0 frame:0
              TX packets:676 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:354005 (354.0 KB)  TX bytes:54090 (54.0 KB)
    root@xenial-newport:~# ping -c2
    PING ( 56(84) bytes of data.
    64 bytes from ( icmp_seq=1 ttl=52 time=568 ms
    64 bytes from ( icmp_seq=2 ttl=52 time=188 ms
    --- ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1000ms
    rtt min/avg/max/mdev = 188.688/378.624/568.561/189.937 ms
  • Ubuntu using ModemManager:
    root@xenial-newport:~# mmcli --modem 0
    /org/freedesktop/ModemManager1/Modem/0 (device id '5cbc1489609fb1b95308ccf41b45f14e0f57771d')
      Hardware |   manufacturer: 'u-blox'
               |          model: 'SARA-R410M-52B'
               |       revision: 'L0.  1  [Aug 01 2018 14:05:07]'
               |   H/W revision: '10000'
               |      supported: 'lte'
               |        current: 'lte'
               |   equipment id: '357812090840163'
      System   |         device: '/sys/devices/platform/soc@0/848000000000.pci/pci0000:00/0000:00:10.0/usb1/1-1/1-1.3/1-1.3.3'
               |        drivers: 'option1, qmi_wwan'
               |         plugin: 'Generic'
               |   primary port: 'cdc-wdm0'
               |          ports: 'ttyUSB0 (qcdm), ttyUSB1 (at), cdc-wdm0 (qmi), wwan0 (net)'
      Numbers  |           own : '16127498744'
      Status   |           lock: 'sim-pin2'
               | unlock retries: 'sim-pin (3), sim-pin2 (3), sim-puk (10), sim-puk2 (10)'
               |          state: 'disabled'
               |    power state: 'on'
               |    access tech: 'unknown'
               | signal quality: '0' (cached)
      Modes    |      supported: 'allowed: 4g; preferred: none'
               |        current: 'allowed: 4g; preferred: none'
      Bands    |      supported: 'eutran-1, eutran-2, eutran-3, eutran-4, eutran-5, eutran-8, eutran-12, eutran-13, eutran-17, eutran-18, eutran-19, eutran-20, eutran-39'
               |        current: 'eutran-1, eutran-2, eutran-3, eutran-4, eutran-5, eutran-8, eutran-12, eutran-13, eutran-17, eutran-18, eutran-19, eutran-20, eutran-39'
      IP       |      supported: 'ipv4, ipv6, ipv4v6'
      3GPP     |           imei: '357812090840163'
               |  enabled locks: 'none'
               |    operator id: 'unknown'
               |  operator name: 'unknown'
               |   subscription: 'unknown'
               |   registration: 'unknown'
               |    EPS UE mode: 'csps-2'
      SIM      |           path: '/org/freedesktop/ModemManager1/SIM/0'
      Bearers  |          paths: 'none'
    root@xenial-newport:~# mmcli --modem 0 | grep imei
      3GPP     |           imei: '357812090840163'
    root@xenial-newport:~# mmcli --modem 0 --enable
    successfully enabled the modem
    root@xenial-newport:~# mmcli --modem 0 --simple-connect="apn=$APN" # Note 'CallFailed' is likely an invalid APN
    successfully connected the modem
    root@xenial-newport:~# mmcli --modem 0 --bearer 0
    Bearer '/org/freedesktop/ModemManager1/Bearer/0'
      Status             |   connected: 'yes'
                         |   suspended: 'no'
                         |   interface: 'wwan0'
                         |  IP timeout: '20'
      Properties         |         apn: 'NIMBLINK.GW12.VZWENTP'
                         |     roaming: 'allowed'
                         |     IP type: 'none'
                         |        user: 'none'
                         |    password: 'none'
                         |      number: 'none'
                         | Rm protocol: 'unknown'
      IPv4 configuration |   method: 'static'
                         |  address: ''
                         |   prefix: '29'
                         |  gateway: ''
                         |      DNS: '', ''
                         |      MTU: '1428'
      IPv6 configuration |   method: 'unknown'
      Stats              |          Duration: '0'
                         |    Bytes received: 'N/A'
                         | Bytes transmitted: 'N/A'
    root@xenial-newport:~# ifdown eth0
    Killed old client process
    Internet Systems Consortium DHCP Client 4.3.3
    Copyright 2004-2015 Internet Systems Consortium.
    All rights reserved.
    For info, please visit
    Listening on LPF/eth0/00:d0:12:0f:f5:83
    Sending on   LPF/eth0/00:d0:12:0f:f5:83
    Sending on   Socket/fallback
    DHCPRELEASE on eth0 to port 67 (xid=0x3cab7268)
    Restarting ntp (via systemctl): ntp.service.
    root@xenial-newport:~# ifconfig wwan0
    root@xenial-newport:~# route add default gw
    root@xenial-newport:~# echo "nameserver" > /etc/resolv.conf
    root@xenial-newport:~# ping
    root@xenial-newport:~# ping -c2
    PING ( 56(84) bytes of data.
    64 bytes from ( icmp_seq=1 ttl=52 time=568 ms
    64 bytes from ( icmp_seq=2 ttl=52 time=188 ms
    --- ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1000ms
    rtt min/avg/max/mdev = 188.688/378.624/568.561/189.937 ms
  • Ubuntu using libqmi only (no NetworkManager or ModemManager)
    root@xenial-newport:~# qmicli --version
    qmicli 1.20.2
    Copyright (C) 2012-2018 Aleksander Morgado
    License GPLv2+: GNU GPL version 2 or later <>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    root@xenial-newport:~# systemctl stop NetworkManager # don't conflict with NetworkManager
    root@xenial-newport:~# systemctl stop ModemManager # don't conflict with ModemManager
    root@xenial-newport:~# ifdown eth0 # bring down eth0 so not confused for WAN/LAN link.
    root@xenial-newport:~# cat << EOF > /etc/qmi-network.conf
    > APN=$APN
    > PROXY=yes
    > EOF
    root@xenial-newport:~# qmicli -p -d /dev/cdc-wdm0 --wda-set-data-format=raw-ip
    [/dev/cdc-wdm0] Successfully set data format
                            QoS flow header: no
                        Link layer protocol: 'raw-ip'
           Uplink data aggregation protocol: 'disabled'
         Downlink data aggregation protocol: 'disabled'
                              NDP signature: '0'
    Downlink data aggregation max datagrams: '0'
         Downlink data aggregation max size: '0'
    root@xenial-newport:~# qmicli -p -d /dev/cdc-wdm0 --set-expected-data-format=raw-ip
    [/dev/cdc-wdm0] expected data format set to: raw-ip
    root@xenial-newport:~# qmi-network /dev/cdc-wdm0 start
    Loading profile at /etc/qmi-network.conf...
        APN user: unset
        APN password: unset
        qmi-proxy: yes
    Checking data format with 'qmicli -d /dev/cdc-wdm0 --wda-get-data-format --device-open-proxy'...
    Device link layer protocol retrieved: raw-ip
    Getting expected data format with 'qmicli -d /dev/cdc-wdm0 --get-expected-data-format'...
    Expected link layer protocol retrieved: raw-ip
    Device and kernel link layer protocol match: raw-ip
    Starting network with 'qmicli -d /dev/cdc-wdm0 --wds-start-network=apn='NIMBLINK.GW12.VZWENTP'  --client-no-release-cid --device-open-proxy'...
    Saving state at /tmp/qmi-network-state-cdc-wdm0... (CID: 4)
    Saving state at /tmp/qmi-network-state-cdc-wdm0... (PDH: 2194536080)
    Network started successfully
    root@xenial-newport:~# qmicli --device /dev/cdc-wdm0 --wds-get-current-settings
    [/dev/cdc-wdm0] Current settings retrieved:
               IP Family: IPv4
            IPv4 address:
        IPv4 subnet mask:
    IPv4 gateway address:
        IPv4 primary DNS:
      IPv4 secondary DNS:
                     MTU: 1428
                 Domains: none
    root@xenial-newport:~# ifconfig wwan0 netmask # assign IP 
    root@xenial-newport:~# route add default gw wwan0 # assign route
    root@xenial-newport:~# echo "nameserver" > /etc/resolv.conf # assign nameserver

CAT M1 SIM Support

Note that the CAT M1 modem requires a CATM1 SIM from the carriers. These SIMs are typically different than the standard LTE SIMs (used in your phone). The following Verizon SIM has been tested and is available here. Note this SIM will not automatically work with the GW16126 because the GW16126 is not end device certified with Verizon. Customers will need to work with their particular cellular carrier to get test SIMs that will work properly with the modem. Certification should also be discussed at the same time.

One may also want to disable system updates that may run in the background on the OS that is being used to avoid any overages on the SIM data plan.

u-blox NINA-B301 BLE module

The u-blox NINA-B301 stand-alone Bluetooth 5 low engery module contains an open Nordic nRF52840 multiprotocol SoC.

Bluetooth HCI (GW16126)

The standard GW16126 comes the nRF52840 pre-programmed by Gateworks with Zephyr Project hci_uart offering a bluetooth HCI UART host controller. The Open-Source Zephyr Project provides a small scalable real-time operating system (RTOS) well suited for small ARM processors such as the one in the nRF52840 and its hci_uart sample code implements a BLE HCI via the H4 UART protocol with the following:

  • 1mbps baudrate
  • 8bits, no parity, 1 stop bit
  • hardware flow control required

To use the GW16126 bluetooth HCI with Linux you need the following:

  • Linux 4.10+ kernel with the following:
    • HCI UART with H4 (CONFIG_BT_HCIUART and CONFIG_BT_HCIUART_H4) in order to provide a bluetooth HCI over UART
  • Bluetooth stack such as BlueZ (4.45+)

The following shows how you would interact with the BLE controller via BlueZ on Ubuntu bionic:

apt-get install bluez
# configure bluez to run expirimental features
sed -i '/^ExecStart=/ s/$/ -E/' /lib/systemd/system/bluetooth.service 
# restart bluetoothd
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
# attach HCI UART
dev=$(basename $(ls -d /sys/bus/usb/drivers/ftdi_sio/*/ttyUSB*))
modprobe hci_uart
btattach -B /dev/$dev -S 1000000 -P h4 &
# scan for BLE devices
hcitool -i hci0 lescan


root@bionic-newport:~# echo 8 > /proc/sys/kernel/printk
root@bionic-newport:~# dev=$(basename $(ls -d /sys/bus/usb/drivers/ftdi_sio/*/ttyUSB*))
root@bionic-newport:~# modprobe hci_uart
[   35.314383] Bluetooth: Core ver 2.22
[   35.318121] NET: Registered protocol family 31
[   35.322614] Bluetooth: HCI device and connection manager initialized
[   35.328997] Bluetooth: HCI socket layer initialized
[   35.333904] Bluetooth: L2CAP socket layer initialized
[   35.338983] Bluetooth: SCO socket layer initialized
[   35.350560] Bluetooth: HCI UART driver ver 2.3
[   35.355057] Bluetooth: HCI UART protocol H4 registered
root@bionic-newport:~# btattach -B /dev/$dev -S 1000000 -P h4 &
[1] 2138
Attaching Primary controller to /dev/ttyUSB0
Switched line discipline from 0 to 15
Device index 0 attached
[   57.834717] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[   57.840137] Bluetooth: BNEP socket layer initialized
root@bionic-newport:~# hciconfig 
hci0:   Type: Primary  Bus: UART
        BD Address: 00:00:00:00:00:00  ACL MTU: 27:7  SCO MTU: 0:0
        UP RUNNING 
        RX bytes:527 acl:0 sco:0 events:41 errors:0
        TX bytes:258 acl:0 sco:0 commands:41 errors:0

root@bionic-newport:~# hcitool -i hci0 lescan
LE Scan ...
3C:A3:08:10:51:FE (unknown)
FC:B4:88:8E:32:61 (unknown)
FC:B4:88:8E:32:61 (unknown)
3C:A3:08:10:51:FE LEDBlue-081051FE 

Zephyr Project Firmware

While the nRF52840 comes pre-programmed with firmware to make it a fully featured Bluetooth HCI you could develop your own firmware and re-program it if desired.

The Zephyr Project is a scaleable real-time operating system (RTOS) supporting multiple hardware architectures, optimized for resource constrained devices, and built with security in mind. The Zephyr Project supports the Nordic nRF58240 within the u-blox NINA-B3 BLE module and can be modified to give it a personality of its own. Some examples within the Zephyr Project that are suited for the GW16123 out of the box are:

  • HCI uart
  • BLE beacon

Gateworks has added GW16126 board support to Zephyr here via commit ba5f00ad


  1. Install Zephyr source
    git clone
    cd ~/zephyr  # or to your directory where zephyr is cloned
    # install more requirements via pip
    pip3 install --user -r scripts/requirements.txt
  2. Build HCI UART (what Gateworks pre-programms into the GW16126):
    # setup shell for building Zephyr
    cd $ZEPHYR_BASE/samples/bluetooth/hci_uart
    mkdir -p build/gw16126 && cd build/gw16126
    cmake -DBOARD=nrf52840_gw16126 ../..
    ls zephyr/zephyr.hex
  3. Build Bluetooth Beacon:
    # setup shell for building Zephyr
    cd $ZEPHYR_BASE/samples/bluetooth/beacon
    mkdir -p build/gw16126 && cd build/gw16126
    cmake -DBOARD=nrf52840_gw16126 ../..
    ls zephyr/zephyr.hex


CollapsibleStart(Programming the nRF58240)

Programming the nRF58240

While the nRF52840 comes pre-programmed with firmware to make it a fully featured Bluetooth HCI you could develop your own firmware and re-program it if desired. The device can be programmed via SWD using the FT231X CBUS pins as follows:


To program you can use OpenOCD with the sysfsgpio interface as long as you have a kernel that supports GPIO in the ftdi-sio driver (Linux 4.20+).

The following will create a gw16126.cfg OpenOCD interface file specifying SWD and mapping the SWCLK/SWDIO pins to the FT231X CBUS2/CBUS1 pins:

  1. Create an OpenOCD interface file for the GW16126 that defines the Linux gpio signals for SWD:
    base=$(for i in $(ls -1d /sys/class/gpio/gpiochip*); do [ "ftdi-cbus" = "$(cat $i/label)" ] && cat $i/base; done)
    [ "$base" ] || { echo "Error: could not find ftdi-cbus device - Linux 4.20+ required"; }
    cat << EOF > gw16126.cfg
    interface sysfsgpio
    transport select swd
    Show quoted text
    sysfsgpio_swd_nums $((base + 2)) $((base + 1))
  2. Build OpenOCD from git master for nRF52840 support:
    apt-get install build-essential git flex bison pkg-config libtool autoconf automake texinfo libusb-1.0-0-dev
    git clone git:// openocd
    cd openocd
    ./configure --enable-sysfsgpio
    make install
    • alternatively you can fetch from a zip archive via {{{wget --no-check-certificate}}} but note that the bootstrap script which checkout jimtcl as git submodules so this doesn't really help

  • I've been having issues on bionic because NTP isn't working right which leads to certificate issues. You can disable by git config --global http.sslverify false
  1. Program firmware:
    # openocd -f gw16126.cfg -f target/nrf52.cfg \
       -c init -c "reset init" -c halt -c "nrf5 mass_erase" -c "program zephyr_uart_hci.hex verify" -c reset -c exit
    Open On-Chip Debugger 0.10.0+dev-00563-gda4b2d5b (2018-10-20-01:03)
    Licensed under GNU GPL v2
    For bug reports, read
    SysfsGPIO nums: swclk = 462, swdio = 461
    adapter speed: 1000 kHz
    cortex_m reset_config sysresetreq
    Info : SysfsGPIO JTAG/SWD bitbang driver
    Info : SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)
    Info : This adapter doesn't support configurable speed
    Info : SWD DPIDR 0x2ba01477
    Info : nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints
    Info : Listening on port 3333 for gdb connections
    target halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
    Info : nRF52840-QIAA(build code: C0) 1024kB Flash
    target halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
    ** Programming Started **
    auto erase enabled
    Warn : using fast async flash loader. This is currently supported
    Warn : only with ST-Link and CMSIS-DAP. If you have issues, add
    Warn : "set WORKAREASIZE 0" before sourcing nrf51.cfg/nrf52.cfg to disable it
    wrote 49152 bytes from file zephyr.hex in 117.544823s (0.408 KiB/s)
    ** Programming Finished **
    ** Verify Started **
    verified 47036 bytes in 2.723827s (16.864 KiB/s)
    ** Verified OK **


u-blox Connectivity Software (GW16126-SP399)

The GW16126-SP399 comes with the nRF52840 pre-programmed (and locked) by u-blox with the u-blox Connectivity Software.

Connection parameters:

  • 115200baud, 8 data bits no stop bit

Protocol details:


  • Serial port interaction
    # query configured role
    # set to central
    # store and power cycle
    # report scan results
  • command line usage:
    dev=$(basename $(ls -d /sys/bus/usb/drivers/ftdi_sio/*/ttyUSB*))
    stty -F $dev 115200 ignbrk -brkint -icrnl -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
    cat $dev & # continually display responses from tty in background
    # request manufactuer identify
    printf 'AT+GMI\r\n' > $dev
    # request model
    printf 'AT+GMM\r\n' > $dev
    # request serial number
    printf 'AT+GSN\r\n' > $dev
    # request misc details
    printf 'AT+ATI0\r\n' > $dev
    # change role to central, write nvram, and reset
    printf 'AT+UBTLE=1\r\n' > $dev
    printf 'AT&W\r\n' > $dev
    printf 'AT+CPWROFF\r\n' > $dev
    # scan for BLE devices
    sleep 1
    printf 'AT+UBTD\r\n' > $dev

See also ublox s-center software for use on Windows

Software Support

In General, the following software is necessary for the GW16126:

  • LTE Cat-M1 modem:
    • Linux 4.17+ kernel with option driver (CONFIG_USB_SERIAL_OPTION) and qmi driver (CONFIG_USB_NET_QMI_WWAN)
      • Linux 4.5+ needed for QMI RAW IP support (unless backported)
      • Linux 4.17+ needed for ublox R410M (unless backported)
  • BLE HCI:
    • Linux 4.5+ kernel
    • hci_uart driver (CONFIG_BT_HCIUART, CONFIG_BT_HCIUART_H4 hci_uart)
    • Userspace cryptographic algorithm support (CONFIG_CRYPTO_USER_API*) (for generation of random bdaddr in BlueZ)
    • Bluetooth stack such as BlueZ (4.45+ with Experimental support (-E param on bluetoothd))


  • LTE Cat-M1 modem: requires network-manager modemmanager libqmi
  • BLE HCI: requires bluez
  • fully supported (with the above)

OpenWrt 18.6.1:

  • requires kmod-usb-net-opton, kmod-usb-net-qmi-wwan, kmod-usb-serial, kmod-usb-serial-ftdi, kmod-usb-serial-qualcomm, kmod-bluetooth, kmod-crypto-user, kmod-crypto-hash, bluez-daemon, uqmi
  • fully supported (with the above)

OpenWrt 16.02:

  • will not work without backporting qmi raw-ip support and modem ID's to option1/qmi-wwan driver

Attachments (4)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.