SparkFun Thing Plus Matter (MGM240P) and OpenThread Border Router addon configuration

Hi folks,

Trying to get the SparkFun Thing Plus Matter (MGM240P) working with the OpenThread Border Router addon and can’t seem to get the addon happy, even though both the bootloader and the RCP firmware are showing signs of life…

Flashed the bootloader and the RCP firmware (from: Release v2025.6.2 · Nerivec/silabs-firmware-builder · GitHub):

> commander.exe flash --masserase sparkfun_mgm240p_bootloader_3.1.2.gbl sparkfun_mgm240p_openthread_rcp_2.7.2.0_GitHub-fb0446f53_921600_sw_flow.gbl --device MGM240PB32VNA

Parsing file sparkfun_mgm240p_bootloader_3.1.2.gbl...
Parsing file sparkfun_mgm240p_openthread_rcp_2.7.2.0_GitHub-fb0446f53_921600_sw_flow.gbl...
Erasing chip...
Flash was erased successfully
Writing 16384 bytes starting at address 0x08000000
Writing 114688 bytes starting at address 0x08006000
Comparing range 0x08000000 - 0x08003FFF (16 KB)
Comparing range 0x08006000 - 0x08021FFF (112 KB)
Comparing range 0x08006000 - 0x0800DFFF (32 KB)
Comparing range 0x0800E000 - 0x08015FFF (32 KB)
Comparing range 0x08016000 - 0x0801DFFF (32 KB)
Comparing range 0x0801E000 - 0x08021FFF (16 KB)
Erasing range 0x08000000 - 0x08003FFF (2 sectors, 16 KB)
Erasing range 0x08006000 - 0x08021FFF (14 sectors, 112 KB)
Programming range 0x08000000 - 0x08001FFF (8 KB)
Programming range 0x08002000 - 0x08003FFF (8 KB)
Programming range 0x08006000 - 0x08007FFF (8 KB)
Programming range 0x08008000 - 0x08009FFF (8 KB)
Programming range 0x0800A000 - 0x0800BFFF (8 KB)
Programming range 0x0800C000 - 0x0800DFFF (8 KB)
Programming range 0x0800E000 - 0x0800FFFF (8 KB)
Programming range 0x08010000 - 0x08011FFF (8 KB)
Programming range 0x08012000 - 0x08013FFF (8 KB)
Programming range 0x08014000 - 0x08015FFF (8 KB)
Programming range 0x08016000 - 0x08017FFF (8 KB)
Programming range 0x08018000 - 0x08019FFF (8 KB)
Programming range 0x0801A000 - 0x0801BFFF (8 KB)
Programming range 0x0801C000 - 0x0801DFFF (8 KB)
Programming range 0x0801E000 - 0x0801FFFF (8 KB)
Programming range 0x08020000 - 0x08021FFF (8 KB)
Verifying range 0x08000000 - 0x08003FFF (16 KB)
Verifying range 0x08006000 - 0x08021FFF (112 KB)
Flashing completed successfully!
DONE

Held GPIOC0 low, reset the board:

universal-silabs-flasher.exe --device \\.\COM35 probe
2026-01-17 14:39:39.375 colossus universal_silabs_flasher.flasher INFO Probing ApplicationType.GECKO_BOOTLOADER at 115200 baud
2026-01-17 14:39:39.417 colossus universal_silabs_flasher.flasher INFO Detected bootloader version '3.1.2'
2026-01-17 14:39:39.417 colossus universal_silabs_flasher.flasher INFO Detected ApplicationType.GECKO_BOOTLOADER, version '3.1.2' at 115200 baudrate (bootloader baudrate 115200)

Bootloder appears to work.

Reset again, after releasing GPIOC0, and I see some output from the RCP firmware:

00 f1                                            .ñ              
00 f1                                            .ñ              
00 f1                                            .ñ              
00 f1                                            .ñ              
00 f1                                            .ñ

Pressed the reset button 5 times, each time that output line was generated - RCP firmware works? The blue LED on the board is also on.

Tried spinel-cli but it seems to fail:

python spinel-cli.py -u \\.\COM35 -b 921600
spinel-cli.py:2034: SyntaxWarning: invalid escape sequence '\*'
  """
Module readline unavailable
spinel-cli > v
spinel-cli ver. 0.1.0
Copyright (c) 2016 The OpenThread Authors.
spinel-cli > version
Error
spinel-cli > state
Error
spinel-cli > scan
Error
Error
Error
Error

But this was on Windows, and perhaps that’s the reason this failed?

And finally, connecting this to the RPi5 with HA running:

-----------------------------------------------------------
 Add-on: OpenThread Border Router
 OpenThread Border Router add-on
-----------------------------------------------------------
 Add-on version: 2.15.3
 You are running the latest version of this add-on.
 System: Home Assistant OS 16.3  (aarch64 / raspberrypi5-64)
 Home Assistant Core: 2026.1.2
 Home Assistant Supervisor: 2026.01.1
-----------------------------------------------------------
 Please, share the above information when looking for help
 or support in, e.g., GitHub, forums or the Discord chat.
-----------------------------------------------------------
s6-rc: info: service banner successfully started
s6-rc: info: service otbr-agent: starting
[14:40:36] INFO: Setup OTBR firewall...
[14:40:36] INFO: Migrating OTBR settings if needed...
2026-01-17 14:40:37 homeassistant asyncio[226] DEBUG Using selector: EpollSelector
2026-01-17 14:40:37 homeassistant zigpy.serial[226] DEBUG Opening a serial connection to '/dev/serial/by-id/usb-Silicon_Labs_J-Link_OB_000449051225-if00' (baudrate=921600, xonxoff=False, rtscts=False)
2026-01-17 14:40:37 homeassistant serialx.platforms.serial_posix[226] DEBUG Configuring serial port '/dev/serial/by-id/usb-Silicon_Labs_J-Link_OB_000449051225-if00'
2026-01-17 14:40:37 homeassistant serialx.platforms.serial_posix[226] DEBUG Configuring serial port: [0, 0, 3248, 0, 4100, 4100, [b'\x03', b'\x1c', b'\x7f', b'\x15', b'\x04', 0, 0, b'\x00', b'\x11', b'\x13', b'\x1a', b'\x00', b'\x12', b'\x0f', b'\x17', b'\x16', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00']]
2026-01-17 14:40:37 homeassistant serialx.platforms.serial_posix[226] DEBUG Setting low latency mode: True
2026-01-17 14:40:37 homeassistant serialx.platforms.serial_posix[226] DEBUG Setting modem pins: ModemPins[!dtr !rts]
2026-01-17 14:40:37 homeassistant serialx.platforms.serial_posix[226] DEBUG TIOCMBIC: 0x00000006
2026-01-17 14:40:37 homeassistant zigpy.serial[226] DEBUG Connection made: <serialx.platforms.serial_posix.PosixSerialTransport object at 0x7fb24d79d0>
2026-01-17 14:40:37 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending frame SpinelFrame(header=SpinelHeader(transaction_id=0, network_link_id=0, flag=2), command_id=<CommandID.RESET: 1>, data=b'\x02')
2026-01-17 14:40:37 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending data b'~\x80\x01\x02\xea\xf0~'
2026-01-17 14:40:37 homeassistant serialx.descriptor_transport[226] DEBUG Immediately writing b'~\x80\x01\x02\xea\xf0~'
2026-01-17 14:40:37 homeassistant serialx.descriptor_transport[226] DEBUG Sent 7 of 7 bytes
2026-01-17 14:40:39 homeassistant universal_silabs_flasher.spinel[226] DEBUG Device did not respond to reset, continuing
2026-01-17 14:40:39 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending frame SpinelFrame(header=SpinelHeader(transaction_id=3, network_link_id=0, flag=2), command_id=<CommandID.PROP_VALUE_GET: 2>, data=b'\x08')
2026-01-17 14:40:39 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending data b'~\x83\x02\x08\xbc\x9a~'
2026-01-17 14:40:39 homeassistant serialx.descriptor_transport[226] DEBUG Immediately writing b'~\x83\x02\x08\xbc\x9a~'
2026-01-17 14:40:39 homeassistant serialx.descriptor_transport[226] DEBUG Sent 7 of 7 bytes
2026-01-17 14:40:41 homeassistant universal_silabs_flasher.spinel[226] DEBUG Failed to send SpinelFrame(header=SpinelHeader(network_link_id=0, flag=2), command_id=<CommandID.PROP_VALUE_GET: 2>, data=b'\x08'), trying again in 0.10s (attempt 1 of 3)
2026-01-17 14:40:41 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending frame SpinelFrame(header=SpinelHeader(transaction_id=3, network_link_id=0, flag=2), command_id=<CommandID.PROP_VALUE_GET: 2>, data=b'\x08')
2026-01-17 14:40:41 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending data b'~\x83\x02\x08\xbc\x9a~'
2026-01-17 14:40:41 homeassistant serialx.descriptor_transport[226] DEBUG Immediately writing b'~\x83\x02\x08\xbc\x9a~'
2026-01-17 14:40:41 homeassistant serialx.descriptor_transport[226] DEBUG Sent 7 of 7 bytes
2026-01-17 14:40:43 homeassistant universal_silabs_flasher.spinel[226] DEBUG Failed to send SpinelFrame(header=SpinelHeader(network_link_id=0, flag=2), command_id=<CommandID.PROP_VALUE_GET: 2>, data=b'\x08'), trying again in 0.10s (attempt 2 of 3)
2026-01-17 14:40:43 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending frame SpinelFrame(header=SpinelHeader(transaction_id=3, network_link_id=0, flag=2), command_id=<CommandID.PROP_VALUE_GET: 2>, data=b'\x08')
2026-01-17 14:40:43 homeassistant universal_silabs_flasher.spinel[226] DEBUG Sending data b'~\x83\x02\x08\xbc\x9a~'
2026-01-17 14:40:43 homeassistant serialx.descriptor_transport[226] DEBUG Immediately writing b'~\x83\x02\x08\xbc\x9a~'
2026-01-17 14:40:43 homeassistant serialx.descriptor_transport[226] DEBUG Sent 7 of 7 bytes
2026-01-17 14:40:45 homeassistant universal_silabs_flasher.spinel[226] DEBUG Failed to send SpinelFrame(header=SpinelHeader(network_link_id=0, flag=2), command_id=<CommandID.PROP_VALUE_GET: 2>, data=b'\x08'), trying again in 0.10s (attempt 3 of 3)
2026-01-17 14:40:45 homeassistant serialx.descriptor_transport[226] DEBUG Closing at the request of the application
2026-01-17 14:40:45 homeassistant zigpy.serial[226] DEBUG Waiting for serial port to close
2026-01-17 14:40:45 homeassistant serialx.descriptor_transport[226] DEBUG Closing connection: None
2026-01-17 14:40:45 homeassistant serialx.descriptor_transport[226] DEBUG Closing file descriptor 7
2026-01-17 14:40:45 homeassistant serialx.descriptor_transport[226] DEBUG Calling protocol `connection_lost` with exc=None
2026-01-17 14:40:45 homeassistant zigpy.serial[226] DEBUG Connection lost: None
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/universal_silabs_flasher/spinel.py", line 260, in send_frame
    return await asyncio.shield(future)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/local/bin/migrate_otbr_settings.py", line 223, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/usr/local/bin/migrate_otbr_settings.py", line 154, in main
    hwaddr = await get_adapter_hardware_addr(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/bin/migrate_otbr_settings.py", line 101, in get_adapter_hardware_addr
    rsp = await protocol.send_command(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/universal_silabs_flasher/spinel.py", line 292, in send_command
    return await self.send_frame(frame, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/universal_silabs_flasher/spinel.py", line 259, in send_frame
    async with asyncio_timeout(timeout):
  File "/usr/lib/python3.11/asyncio/timeouts.py", line 98, in __aexit__
    raise TimeoutError
TimeoutError
[14:40:45] WARNING: otbr-agent exited with code 1 (by signal 0).
Chain OTBR_FORWARD_INGRESS (0 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             PKTTYPE = unicast
DROP       all  --  anywhere             anywhere             match-set otbr-ingress-deny-src src
ACCEPT     all  --  anywhere             anywhere             match-set otbr-ingress-allow-dst dst
DROP       all  --  anywhere             anywhere             PKTTYPE = unicast
ACCEPT     all  --  anywhere             anywhere            
otbr-ingress-deny-src
otbr-ingress-deny-src-swap
otbr-ingress-allow-dst
otbr-ingress-allow-dst-swap
Chain OTBR_FORWARD_EGRESS (0 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
[14:40:45] INFO: OTBR firewall teardown completed.
s6-svlisten1: fatal: /run/s6-rc/servicedirs/otbr-agent failed permanently or its supervisor died
s6-rc: warning: unable to start service otbr-agent: command exited 1
s6-rc: info: service legacy-cont-init: stopping
s6-rc: info: service banner: stopping
s6-rc: info: service mdns: stopping
/run/s6/basedir/scripts/rc.init: warning: s6-rc failed to properly bring all the services up! Check your logs (in /run/uncaught-logs/current if you have in-container logging) for more information.
/run/s6/basedir/scripts/rc.init: fatal: stopping the container.
s6-rc: info: service banner successfully stopped
Default: mDNSResponder (Engineering Build) (Dec 15 2025 09:15:25) stopping
s6-rc: info: service legacy-cont-init successfully stopped
s6-rc: info: service fix-attrs: stopping
s6-rc: info: service fix-attrs successfully stopped
s6-rc: info: service s6rc-oneshot-runner: stopping
s6-rc: info: service s6rc-oneshot-runner successfully stopped
[14:40:45] INFO: mDNS ended with exit code 4 (signal 0)...
s6-rc: info: service mdns successfully stopped

I have also tried a different bootloader and RCP firmware combo (from: Release 20250627 · darkxst/silabs-firmware-builder · GitHub) and the results were the same.

I am probably missing something very obvious here, any pointers are much appreciated.

Thanks!

1 Like

Got it working in the end, recording this here for other folks who might find themselves in the same situation.

I suspected that the J-Link OB serial port (what’s exposed through the USB-C connector) could be the issue here, a few mentions of problems with higher baud rates. Bypassed it by popping off R20 on the board:

…and connected a CP2104 UART to pins A5 (TX on Thing Plus, RX on CP2104) and A6 (RX on Thing Plus, TX on CP2104). Still powering the board through the USB-C connector.

Everything works as expected now, using the mgm240p_openthread_rcp_2.5.3.0_GitHub-1fceb225b_gsdk_2024.6.3_no_flow_460800.gbl from Release 20250627 · darkxst/silabs-firmware-builder · GitHub

There is a chance this could also work without the R20 rework, and with the higher baudrate firmware, but I was fed up enough that I did not try them out and probably won’t touch this for a while now that it is working.