Bus Pirate 6 · Volume 4

Bus Pirate 6 Volume 4 — The Syntax Language and the VT100 / On-Screen UI

Bracket transactions, repeat/delay/partial-byte operators, macros, on-board files, the live status bar

Contents

SectionTopic
1About this volume
2Top-level commands (any mode)
· 2.1The help system: ? and ??
· 2.2Device info, mode select, config: i, m, c
· 2.3# reset and # line-comment (the dual meaning)
· 2.4$ jump to bootloader
· 2.5~ self-test
· 2.6Power and pull-ups: W, w, V, v, P, p
· 2.7Aux pin: a, A, @
· 2.8Frequency / PWM: f, F, g, G
· 2.9Display, bit order, conversion: o, l, L, =, |
· 2.10On-board NAND filesystem: ls, cd, mkdir, rm, cat
3The syntax language
· 3.1Transaction delimiters: [ and ]
· 3.2Continuation: >
· 3.3Numeric literals: hex, binary, decimal, ASCII
· 3.4Read operators: r and r:N
· 3.5Repeat: :N
· 3.6Delays: d, d:N, D, D:N
· 3.7Partial-byte write/read: 0x5a.4, r.4
· 3.8Whitespace as numeric separator
· 3.9# line comment (commit 93aefde)
· 3.10The 255-character line limit
4Worked syntax examples per protocol
· 4.1I²C: [0x90 r:4 0x91 r:4]
· 4.2SPI: [0x90 r:4]
· 4.3UART: streaming write and read
· 4.41-Wire: [0x55 r:8]
5Macros
· 5.1Listing and running stored macros: (0) and (n)
· 5.2Storing macros on the NAND
6The on-board NAND filesystem
7The VT100 status bar
· 7.1What it shows
· 7.2Color coding and the c palette
8The on-screen ST7789V mirror
9Menu-bar + F-keys (firmware Mar 2026+)
10Differences from the classic BP3.6 syntax language
11Cheatsheet updates for Vol 12

1. About this volume

This volume documents everything you can type at the BP6 prompt — the top-level commands valid in any mode, the syntax language used inside a mode, the macro system, the on-board NAND filesystem commands, and the on-screen UI elements that mirror what the terminal sees. Read this first if you’re going to use the BP6 every day. Vols 6-7 walk specific protocol modes on top of this foundation; Vol 9 walks end-to-end workflows that combine multiple commands into recipes.

The syntax language is the Bus Pirate’s defining UX. It’s compact, regular, and protocol-agnostic — the same [ ] brackets delimit a transaction whether you’re in I²C, SPI, or 1-Wire mode; the same r:N operator reads N bytes regardless of which protocol does the actual reading. Once it’s in your fingers, you stop noticing it.

Documentation source: firmware.buspirate.com/command-reference/syntax is the canonical syntax reference; docs.buspirate.com/docs/command-reference/ is the canonical command reference. Where the docs lag the firmware, the firmware source (src/syntax_compile.c and src/commands/) is the source of truth.


2. Top-level commands (any mode)

These commands are valid at any prompt — they don’t depend on the current protocol mode. Many of them are single-character mnemonics; the uppercase / lowercase distinction matters for some pairs (on / off, set / read).

2.1 The help system: ? and ??

  • ? — context-sensitive help. Lists the commands valid in the current mode.
  • ?? — verbose help. Same list, plus per-command summaries.

Both render to the terminal. The LCD doesn’t mirror help — you need a serial console for the full text.

2.2 Device info, mode select, config: i, m, c

  • i — device info dump. Firmware version, build hash, RP2350B unique chip ID, free heap, free NAND space, ARM-vs-RISC-V architecture, current mode. The chip ID is what shows up as the unit’s S/N (see Vol 1 § 7).
  • m — mode select. Prints the mode list and prompts for a choice. Each mode then runs its own setup wizard (pin assignment, speed, parity, etc.). Cancelling at any point returns you to the prompt without changing the active mode.
  • c — config. Sub-menus for color palette, language (i18n), LED brightness, and miscellaneous device-wide settings. Persistent across reboots (settings stored on the on-board NAND).

2.3 # reset and # line-comment (the dual meaning)

Historically (pre-2026-04-07): # at column 0 was a soft-reset command. Type it at the prompt and the firmware re-initializes — equivalent to power-cycling without a USB unplug.

After commit 93aefde (2026-04-07): # is also a line-comment character in the syntax parser. Anywhere in a syntax line, # and everything after it (to the line end) is discarded. The reset behavior is preserved only when # is the first character of input and the rest of the line is empty — i.e., bare # followed by Enter.

Practical consequence: you can now annotate pasted command sequences:

W 3.3       # set PSU to 3.3 V
P           # enable pull-ups on configured pins
[0x90 r:4]  # I²C read 4 bytes from address 0x48

Previously each # would have triggered a reset — not great for pasted scripts.

2.4 $ jump to bootloader

$ at the prompt makes the firmware report the expected UF2 filename for the current board, then reboots into the RP2350’s BOOTSEL mass-storage mode. The RPI-RP2 USB drive appears on the host; drop the UF2 onto it.

This is the canonical firmware-update path. Hardware fallback (hold BOOTSEL button while plugging in USB) still works if firmware is unresponsive, but $ is faster for normal updates.

2.5 ~ self-test

~ runs the built-in self-test. Walks per-pin output drive (forces each IO high, then low, verifies readback via the look-behind buffer or per-pin ADC), checks the PSU output rail at several voltages, exercises the LCD, blinks the LED chain, and reports pass/fail.

Useful after a firmware update to confirm nothing regressed, and as a sanity check before believing a “the BP6 seems broken” symptom (often a probe-cable issue, not the unit).

2.6 Power and pull-ups: W, w, V, v, P, p

CommandAction
W <voltage>Set PSU output voltage (1.0-5.0 V) and enable the rail
wDisable PSU output
VRead PSU output voltage (live ADC sample) — continuous-update display
vRead PSU output voltage — single snapshot
PEnable pull-ups on configured pins
pDisable pull-ups

W and w are output control; V and v are measurement; P and p are pull-up control. The pull-up state is global (all configured pins together), not per-pin from the prompt — for per-pin control, use the mode’s own pin-config wizard.

The V continuous display is useful: type V, walk around the bench, see how the PSU droops when you connect a target — the LCD updates in real time.

2.7 Aux pin: a, A, @

The BP6 has a single auxiliary pin (the AUX header’s GPIO, not the parallel-tap of IO0-7). Commands:

  • A — drive AUX pin high
  • a — drive AUX pin low
  • @ — read AUX pin (one-shot)

Use cases: trigger an oscilloscope, sync to an external event, drive an enable line that doesn’t fit on the 8 IO pins.

2.8 Frequency / PWM: f, F, g, G

CommandAction
fMeasure frequency on the current frequency-input pin (one-shot)
FMeasure frequency continuously
gGenerate PWM (prompts for frequency and duty cycle)
GStop PWM generation

Frequency measurement uses a PIO state machine to count edges over a known interval. Resolution: roughly ±0.1% at frequencies above 1 kHz; below that the measurement window grows.

PWM generation uses another PIO state machine. Frequency range: ~1 Hz to a few hundred kHz; duty cycle 0-100% in 1% steps.

2.9 Display, bit order, conversion: o, l, L, =, |

  • o — output format. Sub-menu picks binary / decimal / hex / ASCII / mixed for syntax-output formatting.
  • l / L — bit-order set. l = LSB-first, L = MSB-first (the default). Affects how bytes are clocked out / in for protocols where it matters (SPI mostly; UART is fixed-format).
  • = — convert a number between bases. Prompts for the value and renders it in binary / decimal / hex / ASCII.
  • | — reverse bits of a number. Useful for hand-crafting bit patterns when an SPI device expects LSB-first but the syntax language defaults to MSB.

2.10 On-board NAND filesystem: ls, cd, mkdir, rm, cat

The BP6’s 1 Gbit NAND is mounted as a FatFS filesystem (Vol 2 § 8). Standard Unix-ish commands operate on it:

  • ls — list files in current directory
  • cd <dir> — change directory
  • mkdir <dir> — create directory
  • rm <file> — delete file
  • cat <file> — print file contents to terminal

Use cases:

  • Store macro scripts as text files; cat plays them back through the parser.
  • Store wordlists, captured pcap, WiGLE CSVs.
  • Drop files onto the BP via USB MSC from the host; ls and cat from the BP to verify.

format re-initializes the filesystem (destructive — loses all stored data). Used when the FatFS corrupts (rare, but possible after an unclean unplug).


3. The syntax language

The syntax language operates inside a mode. After you m into I²C or SPI (etc.), what you type at the prompt is syntax-language input, not top-level commands. Same prompt; different parser.

3.1 Transaction delimiters: [ and ]

[ opens a transaction; ] closes it. What “transaction” means depends on the mode:

  • I²C: [ = START condition; ] = STOP condition.
  • SPI: [ = CS asserted (low); ] = CS deasserted (high).
  • 1-Wire: [ = reset pulse + presence detect; ] = idle.
  • UART: [ = open the port for streaming; ] = close it (mostly a no-op since UART is async).
  • JTAG: [ = TAP state machine to TEST-LOGIC-RESET; ] = release.

Brackets must balance per line. Mixed brackets — like [0x90 r:4 with no ] — produce a parse error.

You can have multiple bracketed transactions per line: [0x90 r:4] [0x91 r:4] is two separate I²C transactions, each with its own START/STOP, on one input line.

3.2 Continuation: >

> is “execute without START.” Used inside a transaction to send a partial sequence without a new START condition. Most useful for repeated I²C transactions that share an address:

[0x90 r:1 > r:1 > r:1]

This is: START, write 0x90, read 1, continue (no repeated START) read 1, continue read 1, STOP. Equivalent to a single 3-byte read after one address write.

For most workflows you don’t need > — the simpler [0x90 r:3] works the same way. > matters when a device’s protocol requires explicit “no repeated START” semantics.

3.3 Numeric literals: hex, binary, decimal, ASCII

Four literal formats:

  • 0x<hex> — hexadecimal. 0x55, 0xff, 0x1234.
  • 0b<binary> — binary. 0b10101010, 0b11110000.
  • <decimal> — decimal. 123, 255.
  • "<ascii>" — ASCII string. "hello" writes the bytes 0x68 0x65 0x6c 0x6c 0x6f.

Type doesn’t matter to the bus — all become bytes — but the literal format is preserved in the readback for clarity. 0xFF reads back as 0xFF not 255.

Multi-byte values: 0x1234 writes two bytes (0x12 then 0x34, MSB-first by default — flip with l).

3.4 Read operators: r and r:N

  • r — read one byte (or one bit, depending on mode).
  • r:N — read N bytes. r:4 reads 4 bytes.
  • r.B — read B bits (partial byte). See § 3.7.

Reads return ACKed bytes for I²C, MOSI-quiet-MISO-active bytes for SPI, etc. The mode decides what “reading” means.

r:N is the most common operator after numeric literals — used in every flash dump, every EEPROM read, every JTAG IDCODE check.

3.5 Repeat: :N

:N after any token repeats it N times. Works on literals, reads, and delays:

  • 0x55:2 writes 0x55 0x55 (two bytes of the same value).
  • 0:8 writes eight zero bytes.
  • r:4 reads 4 bytes (this is the r:N form — same operator, generalized).
  • d:10 delays 10 µs.
  • D:5 delays 5 ms.

The repeat range is bounded by the 255-character line limit (§ 3.10), not by an explicit max-N.

3.6 Delays: d, d:N, D, D:N

  • d — delay 1 microsecond.
  • d:N — delay N microseconds.
  • D — delay 1 millisecond.
  • D:N — delay N milliseconds.

Used inside transactions to give a slow device time to process. Example: writing to an I²C EEPROM:

[0x90 0x00 0x00 0x55 0xAA] D:5

Write address 0x0000 with bytes 0x55, 0xAA, then close transaction, then wait 5 ms (the typical EEPROM write cycle time) before issuing the next operation.

Delays are busy-wait inside the syntax runner — they pause the CPU but don’t disable interrupts, so USB and the display keep working.

3.7 Partial-byte write/read: 0x5a.4, r.4

The .B suffix sends or reads exactly B bits, not a full byte:

  • 0x5a.4 — write the low 4 bits of 0x5a (which are 0b1010). Useful when a protocol needs a 4-bit or 12-bit field.
  • 0x5432.12 — write the low 12 bits of 0x5432 (which are 0b010000110010).
  • r.4 — read 4 bits, return as a value 0-15.

Used heavily for non-byte-aligned protocols like Microwire (3-Wire), some JTAG state machines, and a few custom protocols. The mode has to support arbitrary-width transfers — most do.

3.8 Whitespace as numeric separator

Whitespace separates tokens. 0x55 0xAA writes two bytes (0x55 then 0xAA). 0x55,0xAA is a parse error (no comma operator).

Whitespace inside a token is illegal: 0x 55 is a parse error.

3.9 # line comment (commit 93aefde)

Added 2026-04-07 in commit 93aefde. Anywhere on a syntax line, # and everything after it is discarded. This lets pasted command sequences carry inline annotations:

W 3.3       # set PSU to 3.3 V for this target
[0x48 r:1]  # read 1 byte from I²C address 0x48 (typical temperature sensor)

This is also why the # reset command is now restricted to bare # at column 0 with nothing else on the line — the parser distinguishes by context. The comment behavior is non-destructive; you can’t accidentally reset by leaving a # in a command line.

If you need a comment at the start of a line: any non-empty content before the # (even a single space) treats it as a comment, not a reset. Bare # Enter is reset; # Enter (note leading space) is a no-op comment.

3.10 The 255-character line limit

BC_MAX_LINE is 255. A syntax line longer than that is rejected with a “line too long” error. This bounds the worst-case bytecode array size and avoids the parser allocating dynamically.

Workaround for long sequences: store them as a file on the NAND and cat them — the parser reads the file line by line. Or break a long line into multiple lines; bracket transactions don’t have to be on one line (a [ on one line and ] on the next is fine, though unusual).


4. Worked syntax examples per protocol

4.1 I²C: [0x90 r:4 0x91 r:4]

I²C address 0x48 (the 7-bit address). The 8-bit form with R/W bit is 0x90 (write) or 0x91 (read).

Sequence:

  1. [ — I²C START
  2. 0x90 — write address byte with W=0 (write mode)
  3. r:4 — read 4 bytes (the device’s response, ACKed by master)
  4. 0x91 — write address byte with W=1 (read mode; this triggers a repeated START internally)
  5. r:4 — read 4 more bytes
  6. ] — I²C STOP

A typical use: address 0x48 is a TI TMP102 temperature sensor. The first 4 bytes read are the temperature register (after a pointer write); the second 4 are configuration register data.

4.2 SPI: [0x90 r:4]

SPI doesn’t have an address byte — the chip-select line picks the chip. The 0x90 here is a command byte to whatever the SPI target is. For a 25-series flash chip, 0x90 is the “Read Manufacturer/Device ID” command.

Sequence:

  1. [ — assert CS (low)
  2. 0x90 — clock out the byte 0x90 over MOSI
  3. r:4 — clock out 4 dummy bytes on MOSI, capture MISO into the read buffer
  4. ] — deassert CS (high)

For a Winbond W25Q-class chip, this returns the manufacturer ID (0xEF) and the device code (varies by capacity).

4.3 UART: streaming write and read

UART is asynchronous; brackets are mostly a no-op. Typical usage:

[ "HELLO\r\n" r:8 ]

This writes “HELLO\r\n” out the TX line, then reads up to 8 bytes from RX (with a default timeout if fewer arrive). For interactive UART work, the BP6 also has a “transparent UART bridge” mode where the BP6 acts as a USB-to-UART pass-through — useful for opening a console on an embedded board without leaving the BP6’s syntax-language framing in the way.

4.4 1-Wire: [0x55 r:8]

1-Wire’s “transaction” is the reset pulse + presence detect.

Sequence:

  1. [ — 1-Wire reset pulse + presence detect (the device responds with a presence pulse; the BP6 detects it)
  2. 0x55 — ROM command “Match ROM” (followed by 8 bytes of ROM ID — though here we’re being lazy and reading; for a real match you’d write 8 bytes)
  3. r:8 — read 8 bytes (typical ROM ID readback for a Skip-ROM + Read-ROM sequence)
  4. ] — idle

For a DS18B20 temperature sensor on the wire: the first 8 bytes you read after a Skip-ROM (0xCC not 0x55) and Read-Scratchpad (0xBE) sequence are the temperature, alarm thresholds, configuration, and CRC.


5. Macros

Macros let you replay a stored command sequence with a single short token.

5.1 Listing and running stored macros: (0) and (n)

  • (0) — list all stored macros for the current mode.
  • (n) — run macro number n. The macro’s stored text is fed through the syntax parser as if you typed it.

Each mode has its own macro namespace. Macros stored in I²C mode don’t appear in SPI mode’s list.

5.2 Storing macros on the NAND

Macros are stored as files in the BP6’s on-board NAND under a per-mode directory (e.g., /macros/i2c/). Each file is a text file with the macro’s syntax-language contents. Create them by dropping files onto the USB MSC mount, or use the BP6’s cat > file syntax (limited; see firmware docs for the canonical workflow).

This is one of the BP6’s underused features — most users discover the macro system only after wanting it. Once you’ve established a “scan, dump, verify” recipe for a chip family, parking it as a macro makes the next session faster.


6. The on-board NAND filesystem

The NAND mounts as a USB Mass Storage device when the BP6 enumerates. From the host’s side it looks like a small removable drive — drop files on, drag files off. From the BP6’s side, use ls, cd, mkdir, rm, cat (§ 2.10).

Practical directory layout (firmware default, can be customized):

/                              ← FatFS root
├── config/                    ← persistent settings
├── macros/
│   ├── i2c/                   ← I²C macros
│   ├── spi/                   ← SPI macros
│   └── jtag/                  ← JTAG macros
├── captures/                  ← PCAP files written by sniffers
├── wardrive/                  ← WiGLE-format CSVs (if you're doing GPS work)
├── portals/                   ← Evil Portal HTML payloads
└── scripts/                   ← .bp6 scripts for `cat`-replay

Files appearing here from the host’s USB MSC are immediately visible to BP6 commands without a reboot. Same the other way: a BP6 mkdir shows up as a new folder on the host’s drive.


7. The VT100 status bar

Bottom-of-terminal display, color-coded, updated at roughly 10 Hz.

7.1 What it shows

Live values, all the time:

  • Current mode (HiZ, UART, I²C, SPI, etc.) and its key config (baud, freq, address bits)
  • Per-pin labels for IO0-IO7: each pin shows its name in the current mode (e.g., in I²C: SDA SCL for IO0 and IO1; -- for unconfigured pins)
  • Live voltage per pin (post-1T45 buffer, from the CD4067 mux — Vol 2 § 7)
  • Pull-up state per pin (a small indicator next to each label)
  • PSU on/off + output voltage + measured current draw
  • Frequency counter / PWM channel state if active (FREQ / PWM indicators)
  • Aux pin state if explicitly set

7.2 Color coding and the c palette

The default color scheme:

  • Red — output, driving high
  • Blue — input, reading low
  • Yellow — input, reading high
  • Gray — input, unconnected / floating
  • Accent color (orange or green, mode-dependent) — active in current mode
  • White — pull-up enabled

Type c at the prompt for a sub-menu that tunes colors per-element. The settings persist in NAND /config/.

For high-contrast / accessibility, the c menu includes a “monochrome” theme that drops to black-on-white.


8. The on-screen ST7789V mirror

The 240×320 IPS LCD shows roughly the same content as the VT100 status bar (§ 7.1). It’s a visual mirror — when you don’t have a terminal connected, the LCD is your status display. When you do have a terminal, you can ignore the LCD.

What the LCD adds beyond the VT100 mirror:

  • Per-mode visual schematic — small icon showing which pin is doing what. Helpful as a quick visual check before connecting probes.
  • Live waveform / level traces for some modes (PWM duty cycle, frequency counter trace). Limited resolution (240×320 isn’t a scope), but useful for “is it doing anything?” sanity checks.
  • Capture progress — when a long workflow runs (flash dump, wardrive), the LCD shows a progress bar.

The LCD updates at ~10 Hz from the same render loop that drives the VT100 status bar. Both come from the same in-firmware state machine; they don’t drift.


9. Menu-bar + F-keys (firmware Mar 2026+)

Added in March 2026 (see Vol 3 § 10): a top-of-terminal menu bar with F-key shortcuts. The menu bar shows command categories (Mode / Power / Display / NAND / etc.) and each is associated with a function-key shortcut (F1-F8).

Use case: discoverability. New users can press F1 and see what’s available without reading the help. Power users mostly ignore the menu bar and stay in the syntax language.

The menu bar is on by default; turn it off with the c config sub-menu.


10. Differences from the classic BP3.6 syntax language

For anyone coming from a BP3.6 (the long-lived 2010-2018 PIC-based generation):

AspectBP3.6BP5/6
Number of I/O pins58
Voltage range3.3 V only (with weak 5 V tolerance)1.2-5.5 V at the target side; 1.0-5.0 V programmable PSU
LCD on-screen UInone240×320 IPS with full status mirror
On-board storagenone1 Gbit NAND mounted as USB MSC
PIO state machinesno8 (BP5) / 12 (BP5XL/BP6)
Bracket syntaxsamesame
r:N, :N repeat, delayssamesame
0x5a.4 partial bytesamesame
[ and ] semanticssame per protocolsame per protocol
$ bootloadernewpresent
# line commentabsentpresent (Apr 2026+)
BBIO host protocolpresentpresent (compat)
BPIO2 host protocolabsentnew (FlatBuffers + COBS)
Smart card / DDR5 SPD / blueTagabsentpresent

The syntax language is largely backward-compatible — a BP3.6 user can type the same I²C and SPI bracket sequences and they work as expected. The new operators (# comment, partial-byte reads, the extended PSU range) are additive.

Macros and the NAND filesystem are the big workflow change. On a BP3.6 you couldn’t store sequences across reboots. On the BP6 you can build up a personal macro library and have it survive forever.


11. Cheatsheet updates for Vol 12

Items from this volume that belong on the laminate cheatsheet:

  • The top-level command alphabet: i m c # $ ~ W w V v P p a A @ f F g G o l L = | ls cd mkdir rm cat ?. Single line.
  • Bracket transactions: [ = START (or CS-low / 1-Wire-reset depending on mode); ] = STOP (or CS-high / idle).
  • Numeric literals: 0x hex, 0b binary, <n> decimal, "..." ASCII.
  • r:N reads N bytes; :N repeats the previous token N times; d:N/D:N for µs/ms delay.
  • 0x5a.4 writes the low 4 bits; r.4 reads 4 bits.
  • # is a line comment (Apr 2026+); bare # at start of line still resets.
  • (0) lists macros; (n) runs macro n.
  • Worked examples for I²C / SPI / 1-Wire / UART — one bracket sequence each.
  • The 255-character line limit.
  • VT100 color key: red=out-high, blue=in-low, yellow=in-high, gray=floating, accent=mode-active, white=pull-up-on.

End of Volume 4. Volume 5 picks up with power and probing — the PSU set/measure workflow, pull-up management, per-pin voltage reads, the frequency counter and PWM generator, and the blueTag JTAG/SWD pin-finder.