XM10 Extension Module SDK v2.7.0¶
Release date: 2026-09-08 | Target boards: Rev 1.1 · Rev 2.0 | New API: General-purpose Serial (Rev 2.0)
At a glance¶
This release is about letting the XM10 talk to outside devices over a serial line.
- A general-purpose Serial API is now available. You can use the XM10's External UART (PD5/PD6) from
XM_APIalone — connect two XM10 boards together, or talk to an Arduino, a PC, or another MCU using whatever message format you decide. - Example 43 was added — a ping-pong example where two XM10 boards exchange data. Rev 2.0 now ships 46 examples (was 45).
- Two folder names inside the SDK changed. If you use the SDK as-is there is nothing to do; if you hand-edited your build settings, please check (see "Three things to check").
- Sensor hub connection stability was improved. Occasional dropouts of the IMU and EMG hubs should now be rarer. It has not been confirmed on a real board yet.
- No public API was removed or renamed. Existing code only needs a rebuild.
Rev 1.1 has no firmware changes. Only the version number was aligned.
Three things to check¶
0. If you were using the Xsens MTi-630 — that API is not in the default build ⚠️¶
Only relevant if this applies to you. If your code calls XM_AttachXsensMTi630() or
XM_ConfigureXsensMTi630(), upgrading to v2.7.0 gives you an "undeclared function" compile error.
Why: there is only one External UART port, so the general-purpose Serial API and the Xsens driver cannot both use it. Instead of letting the two collide and misbehave quietly, the choice is now made at build time — you pick one of the two.
What to do — open XM_FW/System/Config/module.h, change one line, and rebuild.
Setting it to 1 brings the Xsens API back and removes the general-purpose Serial API instead.
If you do not use the Xsens IMU, there is nothing to do.
1. Two folder names inside the SDK changed (Rev 2.0 only)¶
| Before | Now |
|---|---|
XM_FW/IOIF/ |
XM_FW/phoundation-ioif/ |
XM_FW/AGR_MW/ |
XM_FW/phoundation-mw/ |
Most of you need to do nothing. The bundled CMakeLists.txt and .cproject already point at the new paths, and includes that use only the file name — #include "ioif_agrb_uart.h" — are unaffected.
There is one case that needs attention: you added the old folder paths to your own build settings by hand. For example, if your include paths contain XM_FW/IOIF/Inc, change it to XM_FW/phoundation-ioif/Inc. The same applies to any #include "XM_FW/AGR_MW/..." that spells out the path.
The Rev 1.1 SDK keeps the old names.
2. Sensor hub connection stability was improved (Rev 2.0)¶
The CAN-FD connection to the IMU and EMG hubs occasionally dropped out when sensor data arrived in bursts; this should now happen less.
⚠️ This change has not been confirmed on a real board yet. If you use IMU or EMG hubs, be aware this differs from v2.6.0 — please tell us if you see anything unusual.
New API — general-purpose Serial (Rev 2.0)¶
The XM10's External UART (PD5 = TX, PD6 = RX) is now yours to use. It does not matter what is on the other end — another XM10, an Arduino, a PC, a Raspberry Pi, another MCU board.
void Control_Setup(void)
{
XM_SetExternalUartBaudrate(XM_UART_BAUD_115200); // must match the peer
XM_AttachExternalUart(OnSerialRx); // start receiving
}
void Control_Loop(void)
{
/* Parse what arrived (here — not in the callback!) */
/* Send — this does not wait */
XM_SendExternalUartData(buf, len);
}
| Function | What it does |
|---|---|
XM_SetExternalUartBaudrate(baud) |
Baud rate (9600 – 921600) |
XM_AttachExternalUart(cb) |
Start receiving. Call once in Control_Setup() |
XM_SendExternalUartData(buf, len) |
Send — does not wait, max 128 bytes per call |
XM_SendExternalUartDataBlocking(buf, len) |
Send — waits for completion. Control_Setup() only |
XM_EnsureExternalUartRxArmed() |
Revive reception if it stalled (call every ~100 ms) |
📋 Hardware settings — configure your peer to match¶
The board side is already fixed. These are the actual values, and your peer device must match them.
| Item | Value | Changeable |
|---|---|---|
| Peripheral | USART2 (asynchronous) | ✗ |
| TX pin | PD5 (net name EXT_UART_TX) |
✗ |
| RX pin | PD6 (net name EXT_UART_RX) |
✗ |
| Logic level | 3.3 V — never wire 5 V directly | ✗ |
| Default baud | 921600 bps | ✅ XM_SetExternalUartBaudrate() (9600 – 921600) |
| Data / parity / stop | 8 / none / 1 | ✗ |
| Flow control | None — RTS/CTS lines are not used | ✗ |
| Max bytes per send | 128 (XM_EXT_UART_TX_MAX_BYTES) |
✗ |
In one line: 921600 8N1, no flow control. Only the baud rate can be changed (on both ends), and 8N1 cannot be changed from firmware.
The GPIOs have no pull-up or pull-down, so if the peer is powered off or the wire comes loose, the RX line floats and noise can be mistaken for data.
🛑 Do not use this wiring on a Rev 1.1 board. Rev 1.1 has no External UART at all (its only serial ports are UART7/UART8 for the foot sensors), and PD6 there is
USB_PWR_ON— an output that switches USB power. Connecting a peer's TX to it puts two outputs against each other.
Three things to know¶
① The frame format is fixed at 8N1 — 8 data bits, no parity, 1 stop bit. Only the baud rate is configurable, so set your peer device to 8N1.
② Copy, and nothing else, inside the receive callback.
static void OnSerialRx(const uint8_t* data, uint32_t len)
{
/* Copy into your own buffer. Parse in Control_Loop() */
}
This callback runs in the same place that receives the 1 kHz foot-sensor (GRF) stream. Parsing, computing or waiting here delays GRF data by exactly that much. Also, the data pointer is invalid once the callback returns — copy the contents, do not store the pointer.
③ One callback is not one message. A serial link carries a byte stream, not messages. Five bytes sent in one go may arrive as 2 + 3, or with the next message stuck to the end. You have to find the message boundaries yourself — DrainAndParse() in example 43 shows how (scan for a header, then assemble).
XM_SendExternalUartData() returning false is not an error. It means "the previous transmission is still in flight" — just try again on the next cycle. Calling it every tick from a 1 kHz control loop will not stall the loop.
Examples¶
Ex.43 External UART Ping-Pong was added (🛑 Rev 2.0 only).
Flash the same firmware onto two XM10 boards, wire them together, and they exchange a message ten times per second.
Board A Board B
PD5 (TX) ───────────────────────► PD6 (RX)
PD6 (RX) ◄─────────────────────── PD5 (TX)
GND ──────────────────────── GND
- Cross TX and RX. TX-to-TX means nothing arrives.
- Always connect GND.
- This is 3.3 V logic. Wiring a 5 V device directly will damage the board.
Watch g_tx_count, g_rx_frame_ok, g_rx_bad_crc and g_peer_seq in the debugger's Live Expressions to diagnose step by step. Full procedure and a symptom-to-cause table are in the example 43 README.
⚠️ This example has not been run on a real board yet either. Two boards actually exchanging bytes has not been confirmed, so when you first try it, follow the table in the README step by step.
Rev 2.0 now has 46 examples, Rev 1.1 has 42.
Also fixed¶
- IMU channel LED turned off late — the LED state was not applied immediately when a hub connection was lost.
- Packet size in the Ex.09 docs — the Total Data packet size was written as 425 B; corrected to the actual 365 B (documentation only, no behaviour change).
- Build failure on Linux — seven header includes had letter case that did not match the actual file names. This only failed on case-sensitive filesystems (Linux, and some macOS setups); Windows always built fine.
Downloads¶
| File | For |
|---|---|
Rev2.0.zip |
Rev 2.0 board SDK (46 examples) |
Rev1.1.zip |
Rev 1.1 board SDK (42 examples) |
AGR_Bootloader.bin |
XM10 bootloader — identical to v2.6.0 (unchanged in this release) |
SUIT_H10_Binary_20260820.zip |
KIT H10 firmware — identical to v2.6.0 |
SUIT_ContentsFiles_20260820.zip |
H10 content files — identical to v2.6.0 |
The three bootloader/H10 files are re-uploads of the v2.6.0 artefacts. Only the XM10 firmware changed in this release; those components are unchanged.
Extract to a short path (e.g. C:\xm10\). A deep path can hit the Windows path-length limit and break the build — that is a path-length problem, not a code problem.
Compatibility¶
| Item | Notes |
|---|---|
| Existing code | Rebuild only. No public API removed or renamed |
| Hand-edited build settings | Check the folder rename — see "Three things to check" #1 |
| Rev 1.1 | No firmware change. Version number aligned to v2.7.0 |
| General-purpose Serial API | Rev 2.0 only |