Crash in scan_bitmap_to_channel_list during Matter BLE commissioning on ESP32-C3 with external antenna
Crash in scan_bitmap_to_channel_list during Matter BLE commissioning on ESP32-C3
Environment
- Chip: ESP32-C3 with external u.FL antenna
- Framework: Arduino ESP32 core 3.3.6 (also tested 3.3.5 and 3.3.7 — same crash)
- IDF version: (bundled with Arduino core 3.3.6)
- Board: ESP32-C3 Dev Module, 4MB flash, 160MHz
- OS: macOS and Linux (crash reproduces on both)
Bug description
scan_bitmap_to_channel_list() in the WiFi driver (libnet80211.a) crashes with a load access fault during Matter BLE commissioning on ESP32-C3. The crash occurs deterministically at the same instruction address across multiple runs and configurations. It happens after the device receives WiFi credentials via BLE from the Matter controller (IKEA Dirigera) and the WiFi driver begins scanning for the target SSID.
Suspected trigger
The crash began occurring after attaching a high-gain external antenna (u.FL). Previously, the u.FL connector had no antenna attached (0-ohm resistor selects u.FL path, not chip antenna), resulting in very weak reception and few visible APs. With the external antenna, the device can see significantly more access points.
Analysis: 5GHz channel bitmap on a 2.4GHz-only chip
Disassembly of scan_bitmap_to_channel_list shows two loops:
- Bits 1-14: processes 2.4GHz channels — writes channel numbers directly
- Bits for 5GHz channels: maps bit positions to channel numbers 36, 40, 44, ... using offsets (+32, +33)
The crash at 0x42112d8a is in the 5GHz channel processing loop. The ESP32-C3 is a 2.4GHz-only chip (Wi-Fi 4, 802.11 b/g/n, 2.4 GHz per Espressif's datasheet).
Hypothesis: The Matter commissioning controller (IKEA Dirigera) provisions WiFi credentials that include 5GHz channel information (the target AP is dual-band). When these 5GHz channel bits are passed to scan_bitmap_to_channel_list, the function attempts to process them, but the 5GHz scan context (a structure accessed at offset 0x2C) is NULL because the C3 never initializes 5GHz radio structures.
This would explain:
- Why it only crashes with the external antenna: stronger reception → Dirigera detects the router's 5GHz band → includes 5GHz channel info in provisioning
- Why it only crashes during Matter commissioning: normal
WiFi.scanNetworks()only uses 2.4GHz channels on the C3, so the 5GHz code path is never hit - Why the same firmware worked before: bare u.FL connector = too weak signal, Dirigera may not have detected 5GHz or followed a different provisioning path
- Why it's not reported by others: most ESP32-C3 users either don't use Matter, or use the chip antenna (weaker signal, 5GHz less likely to be included)
Crash details
The crash is 100% reproducible across:
- Multiple Arduino ESP32 core versions (3.3.5, 3.3.6, 3.3.7)
- Multiple host computers (Mac and Linux)
- Multiple firmware versions (including older commits where commissioning previously worked)
- Full flash erases between attempts
- Various
CHIP_CONFIG_PACKET_BUFFER_POOL_SIZEvalues (6 and 10)
Register dump (most recent, with healthy heap)
[EVT] 0xC000 free=12496 block=7156 min=9052
Guru Meditation Error: Core 0 panic'ed (Load access fault). Exception was unhandled.
Core 0 register dump:
MEPC : 0x42112d8a RA : 0x42112d78 SP : 0x3fcbc930 GP : 0x3fc96000
TP : 0x3fcbca90 T0 : 0x4005890e T1 : 0x4215669c T2 : 0x0000db00
S0/FP : 0x3fca8a80 S1 : 0x3fca8e14 A0 : 0x00000000 A1 : 0x00000040
A2 : 0x00000002 A3 : 0x00000000 A4 : 0x3fcba7c0 A5 : 0x3fca8a84
A6 : 0x4211278a A7 : 0x0000e009 S2 : 0x3fca8a89 S3 : 0x3fca8a88
S4 : 0x5000027c S5 : 0x00000001 S6 : 0x3fcd6c70 S7 : 0x3fce0000
S8 : 0x3ff1b000 S9 : 0x3fce0000 S10 : 0x3fcdf934 S11 : 0x00000000
T3 : 0x0000000b T4 : 0x3fcbc89d T5 : 0x00000008 T6 : 0x00000005
MSTATUS : 0x00001881 MTVEC : 0x40380001 MCAUSE : 0x00000005 MTVAL : 0x0000002cKey values:
MCAUSE: 0x00000005— Load access faultMTVAL: 0x0000002c— Faulting address (NULL + 0x2C offset)MEPC: 0x42112d8a— Crash instruction (consistent across ALL crashes)
Symbol resolution
$ riscv32-esp-elf-addr2line -f -C 0x42112d8a
scan_bitmap_to_channel_listConfirmed by symbol table — the function spans 0x42112c3e to 0x42112db4:
42112c3e T scan_bitmap_to_channel_list
42112db4 T scan_set_desChanAll crash instances (same firmware, different heap configurations)
| Run | free heap | largest block | min ever | MEPC |
|---|---|---|---|---|
| 1 (pool=10, pages=8) | 10,072 | 3,060 | 2,292 | 0x42112d8a |
| 2 (pool=10, pages=4) | 10,072 | 3,060 | 2,512 | 0x42112d8a |
| 3 (pool=6, pages=4) | 9,652 | 4,084 | 4,800 | 0x42112d8a |
| 4 (pool=6, pages=4, no enclosure) | 12,496 | 7,156 | 9,052 | 0x42112d8a |
Run 4 proves this is not a heap exhaustion issue — 9KB minimum free heap, 7KB largest block.
Events before crash
E (54890) chip[DMG]: Fail to retrieve data ... clusterId: 0x0000_0046, attributeId: 0x0000_0006 err = 5c3
E (55003) chip[DMG]: Fail to retrieve data ... clusterId: 0x1349_FC00, attributeId: 0x0000_0001 err = 5c3
[EVT] 0xD007 free=18284 block=7412 min=12212
[EVT] 0xC000 free=12496 block=7156 min=9052
Guru Meditation Error: Core 0 panic'ed (Load access fault). Exception was unhandled.The cluster errors (0x0046 = ICD Management, 0x1349_FC00 = vendor-specific) occur before commissioning begins and are likely unrelated. The crash happens during the WiFi scan phase after BLE credential exchange.
The crash happens during Matter commissioning — the device starts standalone, and commissioning is triggered by a button press which enables BLE advertising for Matter.
Steps to reproduce
- ESP32-C3 with external antenna (u.FL) in an environment with many visible WiFi APs
- Flash a Matter-enabled Arduino sketch using ESP32 Arduino core 3.3.6
- Start Matter BLE commissioning (device advertises over BLE)
- Use a Matter controller to commission the device
- After the controller sends WiFi credentials and the device begins WiFi scanning, it crashes
Expected behavior
WiFi scan completes successfully and device connects to the provisioned network.
Actual behavior
Device crashes in scan_bitmap_to_channel_list with a NULL pointer dereference (load from address 0x2C) every time, at the exact same instruction.
Disassembly of crash site
The 5GHz loop section where the crash occurs:
42112d42: li a3,36 # first 5GHz channel number
42112d46: li a0,0
42112d48: li t3,7
42112d4a: li t4,1
42112d4c: li t5,11
42112d4e: li t6,28 # loop bound (28 5GHz channels)
42112d50: j 42112da0 # enter loop
...
42112d7c: addi a1,a5,1 # increment count
42112d80: add a5,a5,t1 # advance pointer (t1 = g_scan->offset_76)
42112d82: sb a2,0(a5) # store channel number
42112d86: sll a5,t4,a6 # build bit mask
42112d8a: not a5,a5 # ← MEPC (crash reported here)t1 is loaded from g_scan->offset_76 at 0x42112d06. If the 5GHz scan context is not initialized on the C3, this pointer or a derived structure could be NULL, leading to the access fault at offset 0x2C.
Confirmed workaround
Removing the external antenna before commissioning avoids the crash. The device commissions successfully with the bare u.FL connector (weak signal), and once commissioned, the external antenna can be reattached — the device reconnects to WiFi without going through scan_bitmap_to_channel_list.
This confirms the crash is triggered by the antenna improving reception during the WiFi scan phase of Matter commissioning.
Source: espressif/arduino-esp32