I think you’d likely be fine with this setup on Trixie
Hello, I am having issues with integration on a Pi 5 and the MM8108 using SDIO.
I followed @live-love-laugh-wifi instructions and installed all of the UPDATED packages successfully.
I am getting this output:
dmesg | grep -E ‘morse|mmc|sdio’
[ 1.957524] rp1-sdio-clk 1f000b0004.sdio_clk0: loaded sdio_clk0
[ 2.434553] sdhci-brcmstb 1000fff000.mmc: Got CD GPIO
[ 2.435314] mmc1: CQHCI version 5.10
[ 2.476967] mmc0: SDHCI controller on 1000fff000.mmc [1000fff000.mmc] using ADMA 64-bit
[ 2.624696] mmc0: new ultra high speed SDR104 SDXC card at address 544c
[ 2.631626] mmc1: SDHCI controller on 1001100000.mmc [1001100000.mmc] using ADMA 64-bit
[ 2.640115] mmcblk0: mmc0:544c USD00 117 GiB
[ 2.645838] mmcblk0: p1 p2
[ 2.648062] mmcblk0: mmc0:544c USD00 117 GiB
[ 2.700913] mmc1: new ultra high speed DDR50 SDIO card at address 0001
[ 2.829234] mmc2: SDHCI controller on 1f00180000.mmc [1f00180000.mmc] using ADMA 64-bit
[ 2.854858] mmc2: new high speed SDIO card at address 0001
[ 2.960711] EXT4-fs (mmcblk0p2): mounted filesystem 56f80fa2-e005-4cca-86e6-19da1069914d ro with ordered data mode. Quota mode: none.
[ 4.057432] EXT4-fs (mmcblk0p2): re-mounted 56f80fa2-e005-4cca-86e6-19da1069914d r/w. Quota mode: none.
[ 4.673375] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43455-sdio for chip BCM4345/6
[ 4.995484] morse micro driver registration. Version 0-rel_1_12_4_2024_Jun_11-6-g63cd0768
[ 4.995583] morse_sdio mmc2:0001:1: sdio new func 1 vendor 0x325b device 0x809 block 0x8/0x8
[ 4.995704] morse_sdio mmc2:0001:2: sdio new func 2 vendor 0x325b device 0x809 block 0x200/0x200
[ 4.995775] morse_sdio mmc2:0001:2: morse_chip_cfg_detect_and_init failed: -19
[ 4.995781] morse_sdio_probe failed. The driver has not been loaded!
Does anybody have any recommendations?
Allow me to bring you a working guide on how to run the HT-HC01 Heltec HAT on the PI over SDIO as a total noob.
Thank the AI overlords for this one, without it, I would have never done it myself.
Heltec HT-HC01 (SDIO) on Raspberry Pi 5 — Working Bringup Guide
A complete, reproducible bringup of the Heltec HT-HC01 Wi-Fi HaLow module (mounted on the HT-HR01 Pi HAT carrier) on a Raspberry Pi 5 running Raspberry Pi OS Bookworm. Tested and confirmed working: associated, DHCP-leased, end-to-end IP connectivity to a HaLow AP.
This consolidates fixes scattered across multiple forum threads (search the community forum for “Raspberry Pi 5 HT-HC01 Heltec 802.11ah Integration”, “HaLow Integration on Raspberry Pi 5”, and “Build Thread: HaLow for Raspberry Pi OS”) and addresses every gotcha encountered along the way.
Hardware
-
Raspberry Pi 5 (8 GB tested, any RAM size should work)
-
Official 27 W USB-C PSU (or known-good 5 V / 5 A supply — undersized PSUs cause sporadic SDIO enumeration failures that look like driver bugs)
-
Heltec HT-HR01 Pi HAT carrier with the HT-HC01 SDIO module installed (verify the small daughter-module silkscreen says
HT-HC01and notHT-HC01P— the “P” is the SPI variant and needs a completely different setup path) -
microSD or USB boot media
Critical: which OS image
Use exactly this image — do not substitute a newer one and do not run apt upgrade after first boot:
Why this specific image: it ships with kernel 6.6.31+rpt-rpi-2712, which exactly matches the prebuilt Morse Micro driver .deb package referenced below. Any other kernel version means you have to rebuild the driver from source — for that path, see the “Build Thread: HaLow for Raspberry Pi OS” thread on the community forum instead. This guide is the easy path.
Flash with Raspberry Pi Imager. In Imager’s custom settings, configure SSH, username/password, Wi-Fi, and locale so you can SSH in headless from first boot.
Step 1 — First boot, verify kernel, install runtime deps
SSH in, then:
sudo apt update
sudo apt install -y libnl-3-dev libnl-genl-3-dev libnl-route-3-dev device-tree-compiler wget
uname -r
The output must read 6.6.31+rpt-rpi-2712 exactly. If it doesn’t, you have the wrong image — reflash and start over. Do not apt upgrade.
Gotcha #1: The Morse Micro
.debpackages depend on the-devversions of libnl, not the runtime-200packages. Install the dev packages as shown.
Step 2 — Suppress PSU low-voltage warnings
Even with a 5 A supply, the Pi 5’s PMIC will sometimes complain because it can’t negotiate USB-PD with non-PD bricks:
echo "avoid_warnings=1" | sudo tee -a /boot/firmware/config.txt
echo "usb_max_current_enable=1" | sudo tee -a /boot/firmware/config.txt
Step 3 — Download the prebuilt Morse Micro packages
Credit: these .deb files were built and shared by community member live-love-laugh-wifi in post #6 of the “HaLow Integration on Raspberry Pi 5” thread on this forum. They are version 1.12.4, targeted at this exact kernel. Grab them from that post (search the forum for the thread title).
You should end up with seven files:
-
mm-firmware_1.12.4-1.deb -
mm-mac80211_6.6.31-rpt-rpi-2712-1.12.4.deb -
mm-driver_1.12.4-rpt-rpi-2712.deb -
mm-overlays_1.12.4-2.deb -
mm-hostapd_1.12.4-1.deb -
mm-wpa-supp_1.12.4-1.deb -
mm-morsecli_1.12.4-1.deb
Put them all in ~/mm/ on the Pi.
Step 4 — Install everything except the driver, then reboot
cd ~/mm
sudo dpkg -i mm-firmware_1.12.4-1.deb
sudo dpkg -i mm-mac80211_6.6.31-rpt-rpi-2712-1.12.4.deb
sudo dpkg -i mm-overlays_1.12.4-2.deb
sudo dpkg -i mm-hostapd_1.12.4-1.deb
sudo dpkg -i mm-wpa-supp_1.12.4-1.deb
sudo dpkg -i mm-morsecli_1.12.4-1.deb
sudo reboot
Gotcha #2: The
mm-overlayspostinst script automatically appends four lines to/boot/firmware/config.txt:dtoverlay=sdio-pi5,poll_once=on dtparam=sdio_overclock=42 dtoverlay=mm-wlan dtoverlay=morse-psLeave them alone. Earlier guides tell you to add
dtoverlay=sdio,poll_once=off,bus_width=4manually — that’s for the Pi 4 and will conflict on the Pi 5, causing a udev timeout that hangs the boot. Do not adddtoverlay=mm6108-sdioeither; it doesn’t exist in this package — the actual overlay name ismm-wlan.
Gotcha #3: Installing the driver before the other packages causes a
mv: cannot move '/lib/modules/placeholder/extra'post-install error. Reboot between installing the other six packages and installing the driver, as shown.
Step 5 — Install the driver after reboot
SSH back in, then:
cd ~/mm
sudo dpkg -i mm-driver_1.12.4-rpt-rpi-2712.deb
Should install without errors.
Step 6 — Configure the Board Configuration File (BCF)
The HT-HC01 uses the MM6108-MF08551 module variant. Heltec doesn’t program the OTP with a board type, so the driver looks for a generic bcf_default.bin and fails with morse_firmware_init failed: -2. Tell the driver explicitly which BCF to load:
ls /lib/firmware/morse/
You should see bcf_mf08551.bin in the list. Then:
echo "options morse country=US bcf=bcf_mf08551.bin" | sudo tee /etc/modprobe.d/morse.conf
sudo iw reg set US
Gotcha #4: This is the single most important fix for the original “Raspberry Pi 5 HT-HC01 Heltec 802.11ah Integration” forum thread. Without the BCF specified, the driver detects the SDIO device and even loads the main firmware, but probe still fails because the per-board calibration file is missing. Set
country=to your actual region (US / AU / CA — these are the only regions the HT-HC01 firmware supports).
Step 7 — Reboot and verify the radio came up
sudo reboot
After reboot:
dmesg | grep -iE 'morse|sdio'
ip link
iw phy
Expected results:
-
dmesgshowsmorse_sdio mmc2:0001:2: Loaded firmware from morse/mm6108.binand nomorse_firmware_init failedlines -
ip linkshows a newwlan1interface with a MAC starting0c:bf:74:(Morse Micro’s OUI) -
iw physhows two phys:phy0(the Pi 5’s built-in 2.4/5 GHz) and a second one (your HaLow radio) with mesh point support, SAE, AP mode, and a list of “5 GHz” frequencies — those are faked by the Morse driver because mainline Linux doesn’t have native 802.11ah support, and they map internally to real sub-GHz HaLow channels
If wlan1 doesn’t appear, check dmesg | grep -i morse for the actual error. The two most common at this point are still BCF (re-check Step 6) or a wrong overlay (re-verify Step 4’s automatically-added lines).
Step 8 — Find your AP and identify its real channel/op_class
Bring the interface up and scan:
sudo ip link set wlan1 up
sudo iw dev wlan1 scan | grep -E 'SSID|freq|signal'
You should see your HaLow AP. Then run a more detailed scan, substituting your actual SSID in place of halow:
sudo iw dev wlan1 scan 2>&1 | sed -n '/SSID: halow/,/BSS /p' | head -60
Look for these two lines:
-
Regulatory Class: <N>— this is the op_class (e.g.,69= 2 MHz channels in US) -
Channels [<N> - <N>]— this is the HaLow channel number (a real S1G channel, not the faked 5 GHz one)
Gotcha #5:
wpa_supplicant_s1g1.12.4 will scan and find an AP, but it often fails to associate if you don’t tell it the exact S1G channel and op_class explicitly in the network block. The “association silently fails with no error” symptom comes from the userspace not knowing which sub-GHz primary to lock onto.
Step 9 — Write the supplicant config
Gotcha #6: Replace
halowbelow with your actual SSID, and replacechannel=26andop_class=69with the values you found in Step 8. Leaving placeholders in the config will silently fail to associate with no useful error message.
For an open (no encryption) AP:
sudo tee /etc/wpa_supplicant/wpa_supplicant_s1g.conf > /dev/null << 'EOF'
country=US
ctrl_interface=/var/run/wpa_supplicant_s1g
network={
ssid="halow"
key_mgmt=NONE
mode=0
channel=26
op_class=69
s1g_prim_chwidth=0
s1g_prim_1mhz_chan_index=0
}
EOF
The s1g_prim_* lines are correct for op_class 69 (2 MHz). If your AP runs op_class 68 (1 MHz), 70 (4 MHz), or 71 (8 MHz), see the channel-width table in the “Build Thread: HaLow for Raspberry Pi OS” post #19 on this forum for the correct s1g_prim_chwidth and s1g_prim_1mhz_chan_index values.
For a WPA3-SAE AP, replace the network block with:
network={
ssid="halow"
key_mgmt=SAE
sae_password="YOUR_PASSWORD"
pairwise=CCMP
ieee80211w=2
mode=0
channel=26
op_class=69
s1g_prim_chwidth=0
s1g_prim_1mhz_chan_index=0
}
and add sae_pwe=1 to the global section at the top.
Step 10 — Set up auto-start as a systemd service
Don’t connect manually — set it up as a service from the start. This avoids the “ctrl_iface in use” collision you’ll otherwise hit later.
sudo tee /etc/systemd/system/halow.service > /dev/null << 'EOF'
[Unit]
Description=HaLow wpa_supplicant_s1g on wlan1
After=network.target
Wants=network.target
[Service]
Type=simple
ExecStartPre=/usr/bin/nmcli dev set wlan1 managed no
ExecStart=/usr/sbin/wpa_supplicant_s1g -D nl80211 -i wlan1 -c /etc/wpa_supplicant/wpa_supplicant_s1g.conf
ExecStartPost=/sbin/dhclient -e IF_METRIC=600 wlan1
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now halow.service
sleep 5
sudo iw dev wlan1 link
ip addr show wlan1
The IF_METRIC=600 argument to dhclient tells it to install the wlan1 default route at metric 600, so a wired eth0 (typical metric ~100) always wins as the primary route when both are connected. Drop that flag if you want HaLow as your primary route.
Gotcha #7: Once
halow.serviceis enabled and running, do not runwpa_supplicant_s1gmanually anymore. The systemd unit owns the control interface socket at/var/run/wpa_supplicant_s1g/wlan1, and a manual invocation will collide with it and fail withctrl_iface exists and seems to be in use. To make config changes, edit/etc/wpa_supplicant/wpa_supplicant_s1g.confand runsudo systemctl restart halow.service.
Step 11 — Verify connectivity
sudo iw dev wlan1 link
ip addr show wlan1
ping -c 5 -I wlan1 <your-AP-gateway-IP>
iw dev wlan1 link should say Connected to <BSSID> with authorized: yes. ip addr show wlan1 should show a leased IPv4 address. Ping should succeed with ~20–40 ms latency on a 2 MHz channel — that’s the real-world fingerprint of HaLow.
The bitrates iw reports will look insane (650 Mbps VHT-MCS 7 etc.) — those are the 5 GHz/VHT shim’s translations of the real S1G MCS rates. For ground truth, ask the chip directly:
sudo morse_cli -i wlan1 stats | grep -E 'RF frequency|Operating BW|Primary Channel|signal|round-trip'
That’ll show actual RF center (e.g., 916000000 Hz), real operating BW (8 MHz), real primary channel BW (2 MHz), MAC-layer round-trip success %, and SNR.
Step 12 — Pin the kernel
So a future security update doesn’t silently break the driver:
sudo apt-mark hold linux-image-rpi-2712 raspberrypi-kernel firmware-brcm80211
Reboot once to validate everything comes up cleanly:
sudo reboot
After it comes back, ip addr show wlan1 should show a leased IP without any manual intervention, and systemctl status halow.service should be green.
Gotcha #8: If
apt updatelater starts failing withTemporary failure resolving ``deb.debian.org, it meansdhclienton wlan1 overwrote/etc/resolv.confwith the HaLow AP’s (non-internet) DNS. Quick fix:echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf. For a permanent fix, add-e RESOLVCONF=noto the dhclient invocation in the systemd unit.
Troubleshooting cheat sheet
| Symptom | Cause | Fix |
|---|---|---|
morse_sdio_probe failed. The driver has not been loaded! with morse_of_probe: No pin configs found |
No correct device tree overlay loaded | The mm-overlays deb installs the right overlay automatically. Don’t add dtoverlay=sdio,poll_once=off,bus_width=4 manually. |
Pi hangs at boot with udev queue timeout |
Conflicting/wrong SDIO overlay in config.txt |
Pull the SD card, edit config.txt on another machine, remove any manually-added dtoverlay=sdio* or dtoverlay=mm6108-sdio lines. Leave the four lines auto-added by mm-overlays. |
morse_firmware_init failed: -2, BCF morse/bcf_default.bin not found |
OTP not programmed, no fallback BCF specified | Step 6 — set bcf=bcf_mf08551.bin in /etc/modprobe.d/morse.conf |
dpkg: error processing package mm-driver, mv: cannot move '/lib/modules/placeholder/extra' |
Driver installed before other packages | Install everything else first, reboot, then install driver |
dpkg: dependency problems prevent configuration of mm-hostapd: depends on libnl-3-dev |
Wrong libnl package family installed | sudo apt install -y libnl-3-dev libnl-genl-3-dev libnl-route-3-dev |
iw scan shows the AP, but wpa_supplicant_s1g says Not connected even though SSID matches |
S1G channel/op_class not specified in config, or SSID placeholder left unreplaced in config | Add explicit channel=, op_class=, s1g_prim_chwidth=, s1g_prim_1mhz_chan_index= to the network block. Double-check ssid= matches your AP exactly. |
ctrl_iface exists and seems to be in use - cannot override it |
The systemd halow.service is already running and holding the socket |
sudo systemctl stop halow.service && sudo rm -f /var/run/wpa_supplicant_s1g/wlan1, then either restart the service or run manually — never both. |
Connected, leased IP, but apt update fails with Temporary failure resolving deb.debian.org |
dhclient on wlan1 overwrote /etc/resolv.conf with the HaLow AP’s (non-internet) DNS |
`echo “nameserver 1.1.1.1” |
Sporadic SDIO probe failures, random wlan1 disappearances |
Undersized PSU | Use the official 27 W USB-C supply |
iw reports 650 Mbps bitrates |
Faked VHT/5 GHz shim — the kernel doesn’t natively understand 802.11ah, so the driver presents itself as a VHT device | Use morse_cli -i wlan1 stats for real PHY info |
Known-good baseline numbers
For comparison when range-testing later:
-
Bench test, ~1 m, line of sight, 2 MHz channel, US
-
RX signal: -13 dBm
-
Noise floor: -68 dBm
-
SNR: ~55 dB
-
MAC TX round-trip success: 88%
-
Ping latency: ~23 ms
-
Chip temperature: 51 °C
-
Vbat: 3.25 V
-
When walking the link out, the four numbers that actually matter for HaLow link health are: signal_avg, tx retries, TX round-trip success %, and Noise dBm from morse_cli stats. Throughput tracks those, not the lying VHT bitrates.
Credits
-
live-love-laugh-wififor building and sharing the 1.12.4.debpackages in the “HaLow Integration on Raspberry Pi 5” thread, post #6 -
ajudgeandcastironclayfor the more recent “Build Thread: HaLow for Raspberry Pi OS” and the channel/op_class reference table -
The original “Raspberry Pi 5 HT-HC01 Heltec 802.11ah Integration” thread reporters for documenting the failure mode this guide resolves