Hardware Overview: Telit HE910-D on Siemens IOT2040
The Siemens SIMATIC IOT2040 is an Intel Quark (x86) industrial gateway with a mini-PCIe slot that accepts the Telit HE910-D cellular modem. The HE910-D is a HSPA+ (UMTS/GSM) module on a PCIe form factor, and the gateway's built-in SIM holder drives its USIM line. The "D" variant differs from the plain HE910 by supporting a second diversity antenna path, which improves receiver performance in low-RSRP installations but otherwise shares the same AT command set and PPP interfaces. The module exposes its diagnostic and AT ports as a USB CDC-ACM device at /dev/ttyACM0 once the option and cdc_acm kernel modules bind the USB endpoints.
| Item | Value |
|---|---|
| Modem VID:PID (USB) | 1bc7:0021 (Telit HE910-D) |
| Diagnostic / AT port | /dev/ttyACM0 |
| PPP-capable port | /dev/ttyACM0 (after ATD*99#) |
| Default baud | 115200 bps, 8N1 |
| SIM holder | Mainboard-mounted micro-SIM |
| Antenna connectors | MAIN (primary) + AUX (diversity) |
Custom SD Image Build: Required Yocto Layers
The Siemens-provided IOT2000 image is built on the Yocto Project (Kirkstone / Dunfell branches depending on the release). When the standard iot2000setup-tool is included but the cellular stack is missing, the build must add the meta-openembedded networking and cellular layers, plus a custom bbappend for the modem-aware recipes. Source the upstream image configuration from the official siemens/iot2000 GitHub repository.
The following recipe set must be merged into local.conf or a custom image recipe before bitbaking:
IMAGE_INSTALL_append = " \\
ppp pppd \\
ofono \\
connman connman-client \\
iot2000setup \\
usbutils usb-modeswitch \\
kernel-module-ppp-generic \\
kernel-module-ppp-async \\
kernel-module-ppp-deflate \\
kernel-module-ppp-mppe \\
kernel-module-slhc \\
kernel-module-option \\
kernel-module-cdc-acm \\
kernel-module-usbserial \\
"
kernel-module-option driver is mandatory for the HE910-D to enumerate its USB endpoints as /dev/ttyACM0. Without it, the modem powers up but produces no /dev/ttyACM* nodes. That is the most common cause of list-modems reporting Type=hardware with Powered=0 and Online=0.After bitbaking, flash the resulting .wic image to a Class 10 SD card (8 GB minimum) using dd or balenaEtcher. Boot the IOT2040, log in as root via the debug UART or HDMI console, and confirm the kernel log shows the option driver binding the Telit VID:
dmesg | grep -i telit
# expected output:
# option 1-1:1.0: GSM modem (1-port) converter detected
# usb 1-1: GSM modem (1-port) converter now attached to ttyACM0
Required Kernel Modules and Device Nodes
A persistent failure mode in the field is the absence of /dev/ppp after pppd launches. The IOT2000 default kernel does not auto-load ppp_generic and slhc, and the Yocto image's udev rules do not create the /dev/ppp character device. Load the modules explicitly and create the device node:
modprobe ppp_generic
modprobe slhc
modprobe ppp_async
modprobe ppp_deflate
modprobe ppp_mppe
mknod /dev/ppp c 108 0
chmod 600 /dev/ppp
Persist the modules by listing them in /etc/modules-load.d/ppp.conf so they survive reboot:
# /etc/modules-load.d/ppp.conf
ppp_generic
slhc
ppp_async
ppp_deflate
ppp_mppe
option
cdc_acm
A correct enumeration at boot should look like this:
lsmod | grep -E "ppp|option|cdc"
ls -l /dev/ppp /dev/ttyACM0
# crw------- 1 root root 108, 0 Jan 1 00:00 /dev/ppp
# crw-rw---- 1 root dialout 166, 0 Jan 1 00:00 /dev/ttyACM0
The 108 major number is the canonical assignment for the PPP multiplexer and must match what the kernel's ppp_generic registers. If mknod uses a different major, pppd silently fails with "pppd is unable to open the /dev/ppp device".
Verifying the Modem with AT Commands
Before any high-level daemon (ofono, connman, iot2000setup) is engaged, validate the radio on the raw serial port. This separates hardware faults from stack faults and is the single most useful first step when list-modems reports a powered-down hardware device. The Telit HE910 AT command reference covers the full instruction set used below.
stty -F /dev/ttyACM0 115200 cs8 -cstopb -ixon raw
cat /dev/ttyACM0 & # background the reader
In a second terminal:
printf 'AT\\r\\n' > /dev/ttyACM0 # expect: OK
printf 'AT+CPIN?\\r\\n' > /dev/ttyACM0 # expect: +CPIN: READY
printf 'AT+CSQ\\r\\n' > /dev/ttyACM0 # expect: +CSQ: <rssi>,99
printf 'AT+CREG?\\r\\n' > /dev/ttyACM0 # expect: +CREG: 0,1
printf 'AT+COPS?\\r\\n' > /dev/ttyACM0 # expect: +COPS: 0,0,"<op>"
printf 'AT+CGDCONT=1,"IP","internet"\\r\\n' > /dev/ttyACM0
printf 'AT+CGACT=1,1\\r\\n' > /dev/ttyACM0
| Command | Purpose | Healthy response |
|---|---|---|
| AT | Modem alive | OK |
| AT+CPIN? | SIM state | +CPIN: READY |
| AT+CSQ | RSSI / BER | +CSQ: 12,99 (≥10 workable, ≥15 good) |
| AT+CREG? | CS registration | +CREG: 0,1 or +CREG: 0,5 (roaming) |
| AT+COPS? | Operator name | +COPS: 0,0,"Vodafone IT" |
| AT+CGDCONT? | PDP context | +CGDCONT: 1,"IP","internet" |
If the modem answers AT with OK and the SIM reports READY, the radio path is healthy and the next step is ofono. If the modem fails to answer, swap in a known-good test SIM, then verify antenna cabling (primary on MAIN, diversity on AUX) before suspecting the modem itself.
ofono Modem Activation Workflow
ofono is the Linux cellular daemon that translates dbus calls into the Telit AT command sequence. The reference implementation is maintained at the ofono project. On the IOT2040, the modem is enumerated through the cdc_acm and option drivers, but the activation sequence requires the modem to be in Powered=1 and Online=1 state before the cellular context can be brought up. A common field failure is the "Operation failed" error from activate-context, which usually traces back to either an unfinished network registration or an incorrect APN.
Enable the ofono debug log to capture the failure reason:
systemctl stop ofono
/usr/lib/ofono/test/ofonod -d '*' --foreground 2>/tmp/ofono.log &
The expected happy-path sequence is:
# In a second session, using ofono's bundled test tools:
/usr/lib/ofono/test/list-modems
# [ /telit_0 ]
# Powered = 1
# Online = 1
# Features = gprs net sms
# Interfaces = org.ofono.Modem org.ofono.NetworkRegistration org.ofono.ConnectionManager
# Type = hardware
# Emergency = 0
/usr/lib/ofono/test/activate-context 1 "internet" ""
# expect: /telit_0/context1 active
If list-modems returns Powered=0 and Online=0 (the symptom reported in the original troubleshooting thread), the most common cause is the option driver not having claimed the modem's USB endpoints. Confirm:
lsusb | grep -i telit
# 1bc7:0021 Telit Wireless Solutions HE910-D
ls -l /dev/ttyACM*
If /dev/ttyACM0 is missing, force-bind the driver:
echo "1bc7 0021" > /sys/bus/usb/drivers/option/new_id
If list-modems shows Powered=1 but activate-context returns org.ofono.Error.Failed, capture the ofono log and look for these patterns:
- "Operation not allowed" or "+CME ERROR: 514" in the log — APN rejected. Confirm the APN string with the carrier (e.g. internet, web.vodafone.de, internet.t-d1.de).
- "PDP context activation failed" — roaming restriction or no data on the SIM. Insert a SIM that has an active data plan.
-
"Not registered" — antennas disconnected or RSSI too low. Check
AT+CSQ; values below 5 fail to attach reliably on HSPA cells. -
"Sequencing error" in the GPRS state machine — the
optiondriver claimed the diagnostic endpoint but not the modem-management endpoint. Re-seat the SIM and re-plug the modem, or reboot.
PPP Daemon Setup for the ppp0 Interface
When the application requires a ppp0 interface directly (legacy SCADA bridges, IPsec transport, or a PLC that does not understand the connman dbus API), pppd can be invoked against /dev/ttyACM0. Use a chat script that walks the modem through PIN entry, APN selection, and the data call.
Create /etc/ppp/peers/iot2040-cellular:
/dev/ttyACM0
115200
noipdefault
defaultroute
replacedefaultroute
persist
holdoff 10
maxfail 0
debug
nodetach
crtscts
lock
noauth
novj
novjccomp
noccp
ipcp-accept-local
ipcp-accept-remote
lcp-echo-interval 30
lcp-echo-failure 5
connect '/usr/sbin/chat -v -f /etc/ppp/chat-iot2040'
Create /etc/ppp/chat-iot2040:
ABORT "BUSY"
ABORT "ERROR"
ABORT "NO DIALTONE"
SAY "Initializing cellular modem..."
TIMEOUT 30
"" AT
OK ATE0
OK AT+CPIN?
"READY" AT+CFUN=1
OK AT+CREG?
OK AT+CGDCONT=1,"IP","internet"
OK ATD*99#
CONNECT ""
Launch with:
pppd call iot2040-cellular
# expect in syslog:
# Connect: ppp0 <--> /dev/ttyACM0
# local IP address 10.x.x.x
# remote IP address 10.64.64.64
A persistent ppp0 can be added to /etc/network/interfaces or wrapped as a systemd service that depends on ofono.service coming up first. lcp-echo-interval 30 and lcp-echo-failure 5 prevent the link from idling out on networks that aggressively time out inactive PDP contexts.
iot2000setup Cellular Configuration
The iot2000setup tool is a Siemens-maintained curses-based configuration front-end for the IOT2000 image. It includes a Cellular menu that drives both the ofono context and the connman service. When the menu shows options greyed out or returns "configuration not supported", the underlying ofono/connman stack is missing or unreachable.
Before using iot2000setup, validate the prerequisites:
systemctl status ofono
systemctl status connman
dbus-send --system --dest=org.ofono / org.ofono.Manager.GetModems
# expected: array containing /telit_0
If both services are up and list-modems returns a healthy HE910-D, the iot2000setup menu will offer:
- Provider selection (auto-scan via
AT+COPS=?) - APN entry (string, e.g. internet)
- Authentication (none / PAP / CHAP / both)
- PIN entry (left blank if SIM has no PIN, or the 4–8 digit value)
A successful run writes /var/lib/connman/cellular.config and reloads connman. The interface should appear as cellular0 in ip link output within 15 seconds.
If the menu aborts with a Python traceback, run it under strace to capture the failing dbus call, then re-check that the ofono user (typically ofono) is in the dialout group:
usermod -aG dialout ofono
systemctl restart ofono
HE910 vs HE910-D: What Changes
The two modules share the same Telit AT firmware family and the same USB enumeration (VID 0x1bc7), but the HE910-D adds a second antenna connector for downlink diversity. For ofono and pppd this is invisible — the option driver binds the same /dev/ttyACM0 and the AT command set is identical. Where it does matter is in field installation: on the HE910-D the second antenna must be terminated with a 50 Ω load or attached to a second antenna. Leaving it floating does not prevent registration but degrades throughput and increases the AT+CSQ variance, which causes ofono context activations to fail intermittently in marginal coverage areas.
| Aspect | HE910 | HE910-D |
|---|---|---|
| USB VID:PID | 1bc7:0021 | 1bc7:0021 |
| Antenna connectors | 1 (MAIN) | 2 (MAIN + AUX) |
| ofono binding | /telit_0 | /telit_0 |
| PPP port | /dev/ttyACM0 | /dev/ttyACM0 |
| AT firmware branch | HE910 | HE910-D (T0D or later) |
| 3G/HSPA+ bands | Quad-band | Quad-band + diversity gain |
Troubleshooting Matrix
| Symptom | Likely root cause | Corrective action |
|---|---|---|
| /dev/ttyACM0 absent | option/cdc_acm modules not loaded | modprobe option cdc_acm; force-bind 1bc7:0021 |
| list-modems: Powered=0, Online=0 | USB driver not bound to modem endpoints | Re-check lsusb; bind driver manually via sysfs |
| pppd: cannot open /dev/ppp | ppp_generic/slhc not loaded, /dev/ppp node missing | modprobe ppp_generic slhc; mknod /dev/ppp c 108 0 |
| activate-context: org.ofono.Error.Failed | APN wrong, no data plan, or low RSSI | Verify AT+CSQ, AT+CREG, AT+CGDCONT |
| iot2000setup: cellular menu greyed out | ofono/connman not running or not in dialout group | systemctl restart; usermod -aG dialout ofono |
| ppp0 appears but no default route | replacedefaultroute missing from peers file | Add replacedefaultroute to /etc/ppp/peers/... |
| ppp0 drops after 60 s | Idle timeout or LCP echo failure | Add lcp-echo-interval 30 lcp-echo-failure 5 |
| AT+CPIN: SIM PIN | SIM locked | AT+CPIN="1234"; disable PIN via phone if persistent |
| AT+CREG: 0,3 | Registration denied | Re-seat SIM, check IMEI with AT+CGSN |
| High CSQ variance (5–18) | Diversity antenna floating on HE910-D | Terminate AUX with 50 Ω or attach second antenna |
| connman cellular0 never appears | iot2000setup wrote config but connman not reloaded | connmanctl enable cellular; systemctl restart connman |
Verification Procedure
After configuration, run the following end-to-end check before deploying to the field. All five steps must pass for the IOT2040 to have a working cellular data path on the HE910-D.
# 1. Hardware path
lsusb | grep -i 1bc7:0021
ls -l /dev/ttyACM0 /dev/ppp
# 2. AT-level
stty -F /dev/ttyACM0 115200 raw -echo
printf 'AT+CSQ\\r\\n' > /dev/ttyACM0
printf 'AT+CREG?\\r\\n' > /dev/ttyACM0
# 3. ofono state
/usr/lib/ofono/test/list-modems
# expect: Powered=1, Online=1, Interfaces includes ConnectionManager
# 4. PPP or connman interface
ip link show ppp0 # if using pppd
ip link show cellular0 # if using iot2000setup
# 5. End-to-end ICMP over the cellular link
ping -I ppp0 8.8.8.8 -c 4
If list-modems reports Powered=1, Online=1 and the ICMP echoes return, the link is healthy. Record the IMEI (AT+CGSN), the operator name, and the assigned IP for the as-built documentation that accompanies the cabinet.
AT+CREG? every 300 s and re-dials the PDP context if registration drops to 0,0. The IOT2040 watchdog daemon (systemd's WatchdogSec) is sufficient when paired with a small shell script that calls systemctl restart pppd-iot2040.FAQ
Why does ofono's list-modems show the HE910-D with Powered=0 even though AT commands work on ttyACM0?
The raw AT path is opened by the cdc_acm driver on the diagnostic endpoint, but ofono also needs the modem-management endpoints bound to the option driver. If only cdc_acm is loaded, the modem replies to AT but ofono cannot transition it to Powered=1. Run modprobe option and verify lsusb shows the Telit 1bc7:0021 bound to the option driver rather than only to cdc_acm.
What kernel modules are required for ppp0 to come up on the IOT2040?
Load ppp_generic, slhc, ppp_async, ppp_deflate, and ppp_mppe in that order, then create the character device with mknod /dev/ppp c 108 0 and chmod 600. Without slhc, pppd starts but the kernel rejects the SLHC-compressed frames; without ppp_async, the TTY-side discipline is missing and ppp0 never appears under ifconfig.
Why does iot2000setup's cellular menu fail to apply the configuration?
The setup tool writes a config file and reloads connman. If connman is not running, the menu reports success but no interface comes up. Verify systemctl status connman returns active and that the ofono user belongs to the dialout group so it can read/write /dev/ttyACM0.
Can I use the HE910 and the HE910-D interchangeably on a custom IOT2040 image?
Yes. Both share the same USB VID:PID (1bc7:0021) and the same AT command set. The only practical difference is the second antenna connector on the HE910-D, which improves downlink diversity but is not required for registration or ppp0 setup.
Which APN should I configure for a European industrial SIM?
It depends on the operator, not on the modem. For Vodafone Germany use web.vodafone.de, for T-Mobile Germany internet.t-d1.de, for Vodafone Italy web.omnitel.it, and for generic MVNOs internet is the most common default. The APN is configured with AT+CGDCONT=1,"IP","<apn>" before the data call and is what ofono's activate-context passes through to the modem.