Many products talk over a radio module such as a Digi XBee, and many set the radio up every time they start: the network, the channels, the addresses, the baud rate. Those commands travel over two pins you can probe. Capture them once and you know exactly how the device's radio is configured, and how to talk to it with your own. Our worked example is a Digi XBee-PRO S3B, a 900 MHz module; the method is the same for any module with a serial port.
Digi's through-hole XBee modules share a 20-pin footprint, two rows of ten pins 2 mm apart, and put these four signals on the same pins. From the pin tables of Digi's user guides for the XBee-PRO 900HP/XSC S3 and S3B (90002173), the XBee/XBee-PRO S1 802.15.4 (90000982) and the S2C 802.15.4 (90001500):
| Pin | Name | What it is |
|---|---|---|
| 1 | VCC | Power: 2.1 to 3.6 V on the XBee-PRO 900HP (S3B), 2.8 to 3.4 V on the S1, 2.7 to 3.6 V on the S2C |
| 2 | DOUT | UART data out: what the radio sends to the device (its replies) |
| 3 | DIN / CONFIG | UART data in: what the device sends to the radio (its commands) |
| 10 | GND | Ground |
Surface-mount XBees (soldered flat) are numbered differently: on the S2C, GND is pin 1, DOUT pin 3 and DIN pin 4. Other makers' modules, Laird's for example, put their serial port on other pins: the module's data sheet names its TX and RX, and everything below applies to them too.
A device sets an XBee up in one of two ways.
AT command mode is readable text. The device stays silent for one second (the guard time, GT), sends +++, stays silent for another second, and the radio answers OK and a carriage return. Then each command is AT, two letters and an optional value in hexadecimal, ended by a carriage return: ATID7FFF. The radio answers OK (or ERROR), or the value when the command only asks. ATCN leaves command mode and applies the changes; so do 10 seconds without a command (CT's default). When the radio is not taking commands, it is in transparent mode: whatever arrives on DIN is sent over the air.
API mode (AP = 1 or 2) uses binary frames instead. Each starts with the byte 0x7E, then two length bytes, the frame data, and a checksum. A local AT command is frame type 0x08, then a frame ID, the two command letters and the value. Setting the preamble ID to 2 looks like this on the wire:
7E 00 05 08 01 48 50 02 5C
0x7E starts it; 00 05 is the length (5 bytes follow before the checksum); 08 is the frame type; 01 the frame ID; 48 50 the letters H and P; 02 the value. The checksum is 0xFF minus the low byte of the sum of those 5 bytes: 0x08 + 0x01 + 0x48 + 0x50 + 0x02 = 0xA3, and 0xFF − 0xA3 = 0x5C. The radio answers with frame type 0x88. Decode API traffic in Hex, not ASCII. A device whose radio was set to API mode earlier (and saved with WR) sends no +++ at all.
For the XBee-PRO 900HP (S3B), from Digi's user guide 90002173; values are hexadecimal.
| Command | What it sets | Range and default |
|---|---|---|
| ATID | The network ID. Radios talk only to radios with the same ID (and preamble ID and channels). | 0 to 0x7FFF; default 0x7FFF |
| ATHP | The preamble ID, checked before the network ID: another way to keep neighbouring networks apart. | 0 to 7; default 0 |
| ATCM | The channel mask: one bit per frequency the radio may hop on. In the US the channels are 400 kHz apart from 902.4 MHz (bit 0) to 927.6 MHz (bit 63); every radio in a network needs the same set. | default 0xFFFFFFFFFFF7FFFF: every channel but 19 (910 MHz) |
| ATDH, ATDL | The destination address, high and low 32 bits: where the radio sends what arrives on DIN in transparent mode. 0x000000000000FFFF is the broadcast address. | default 0 and 0xFFFF (broadcast) |
| ATSH, ATSL | Ask the radio's own 64-bit address, its serial number, set at the factory. The 900HP has no separate short address. | read only |
| ATCE | Messaging options: whether this radio repeats for others, and indirect messaging for sleeping radios. | 0 to 6; default 0 |
| ATTO | Transmit options for transparent mode; bits 6 and 7 pick the delivery: point-to-multipoint, repeater (directed broadcast) or DigiMesh. | default 0xC0 (DigiMesh) on the 200 kb/s module, 0x40 on the 10 kb/s |
| ATBD | The serial baud rate between radio and device: 1 to 8 are 2400, 4800, 9600, 19,200, 38,400, 57,600, 115,200 and 230,400. The radio switches when it leaves command mode, so replies after ATCN come at the new rate. | default 3 (9600) |
| ATAP | API mode: 0 transparent (AT), 1 API, 2 API with escaped characters. | default 0 |
| ATPL | Transmit power: 0 to 4 are about +7, +15, +18, +21 and +24 dBm. | default 4 |
| ATWR | Writes the settings to the radio's non-volatile memory, so they survive a power cycle. | no value |
| ATCN | Leaves command mode and applies pending changes. | no value |
| ATVR | Asks the firmware version (hexadecimal; ours answers 8075). | read only |
Other XBee families use other commands. The 2.4 GHz 802.15.4 XBees (S1, S2C) pick a channel with CH and a network with ID (the PAN ID), and have a 16-bit address, MY (Digi's S1 guide, 90000982). ATVR tells you which firmware you are dealing with; look its commands up in that module's own user guide.
If the capture stops on a glitch as the device switches on rather than on the first command, move the trigger point further left or arm a little after switch-on. A device's microcontroller may also leave its pins floating for a moment while it resets: a little hum or a slow rise there is normal.
An illustration of a typical AT-mode start-up for a 900HP radio, not a capture of any particular product (the screenshot above is the real one):
| DIN (device to radio) | DOUT (radio to device) | Meaning |
|---|---|---|
+++ | OK | Command mode, after a second of silence either side |
ATID1A2B | OK | Network ID 0x1A2B |
ATHP3 | OK | Preamble ID 3 |
ATDH0, ATDLFFFF | OK, OK | Send to every radio in the network (broadcast) |
ATBD6 | OK | 57,600 baud, from when command mode ends |
ATWR | OK | Saved |
ATCN | OK | Back to transparent mode: from now on DIN carries the device's data, at the new rate |
A start-up like this one changes rate in the middle of the record, so Auto rate cannot fit one rate to all of it: decode the part before ATCN at the old rate and the part after at the new one, or zoom into one part at a time (when to distrust Auto).
On NovaOS the event table beside the plot lists each decoded character or frame with its time; with the scope stopped it covers the whole record. Storage, Save, Decode table, B1 .csv writes the table to a file, which a spreadsheet opens.
Coming in NovaOS: a bus logger that writes decoded traffic to a file continuously, capture after capture, and an XBee decoder that names each AT command and API frame. This guide will show both once they are in a release.
On a through-hole XBee, DOUT (pin 2) is the radio's transmit line to the device, and DIN (pin 3) its receive line from the device. Probe DIN for the commands and DOUT for the replies. GND is pin 10.
Either the radio was configured once and saved with ATWR, so the device sends nothing at start-up, or the device uses API mode, whose commands are binary frames starting with 0x7E. Switch the decoder to Hex and look for 7E.
A 10× probe loads each pin with 10 MΩ and about 10 to 20 pF; at these baud rates it does not disturb the line. Clip carefully: a slipped probe can short two neighbouring pins 2 mm apart.
Whatever its BD setting says: 9600 from the factory (BD = 3), on the XBee-PRO 900HP and the 2.4 GHz modules alike. A device may change it with ATBD; the new rate starts when command mode ends. Measure it if unsure: how.
Yes. Any module configured over a serial port, a Laird module or another XBee family, can be watched the same way: find its TX and RX pins in its data sheet, probe both, and capture the start-up. The commands differ; the module's own manual explains them.
An XBee radio's serial line, from the wiring to the decoded answer: the trigger on the start bit, the time base and the decoder settings.
Find an unknown baud rateMeasure one bit, divide one by it, snap to a standard rate; the U trick, how close is close enough, and when to trust the scope's Auto.
An ESP32's boot messageThe first serial signal to try: every ESP32 prints one at 115,200 baud on every reset. Probe one pin, press EN, decode, and read why it reset.