Add bus pirate bit bang mode support

I want to add an implementation to the BBIO1 protocol, in order to be backwards compatible with bus pirate 3.

Are there any other efforts to do the same?
Where is an up to date documentation of the BBIO protocol?
I know for SPI that there is a large bulk transfer that is not documented on the dangerousprototypes site.

I’ve done a bit of work. The basic bitbang mode (base mode) is mostly there. There’s some work done on the SPI mode. But, the logic analyzer currently takes over binary mode. There’s a github bug report pointing where (maybe yours?). It should take over after 5 x 0x00 and then 0x2, but I changed it for debugging.

When I went to remove the debug code, @dreg reported that the flashrom implementation was using the terminal interface to get version info and parsing the output. So, there was some discussion of faking the old terminal mode output too, but I looked into the horror of that abyss of spaghetti code and decided it’s probably easier to make something proper and nice - and then submit patches for projects to update (or forking and hosting our own cross platform compiles via github workflow like you did for the firmware). It’s not 2009 anymore, and we have much better tooling for handling stuff like this, was my gut feeling.

Binary mode is the next thing i want to tackle after the stack overflow issue and file system sharing approach. Specifically I want to get SPI (and I2C and 1-Wire) going with some modern flash/eeprom apps.

There’s been some various discussion. I started with a “data first” approach, using 0x7e to escape commands and the rest being data. A couple posters far more knowledgeable than I pointed out some issues in that approach, and suggested “protocol buffer”.

I looked into protocol buffers, and found C tooling and read how to use it. It looks really cool for the user side experience in almost any language. It feels a bit heavy to me, and there’s warnings about unexpectedly high memory use in the docs (not sure host or client).

That’s kind of where it’s at. It’s the next thing after I push those two big fixes. Any thoughts, feedback, etc all totally welcome. Now would be the time to lock something good in for the long term.

This describes what is and is not implemented.

You are right, it’s better to start from scratch, and focus our efforts on building BBIO2 learning from the mistakes of the past, and probably it will be easier to patch the open source software that uses bus pirate, than bringing back to life the old protocol.

The bus pirate hardware has much more RAM, and especially FLASH (16MB), plus the capability to present two different serial devices, one for humans and one for machines.

I suggest to go with an opcode like approach for the new version, maybe there even some abstractions that can be made, so some opcodes can be shared between “modes”.
In addition, I suggest to move to 16bit commands instead of 8bit, so we would have more flexibility.

I recently added RTS handling. Maybe a super simple way is to do command/data indication with the RTS signal. However, I understand there may be situations where the RTS and data arrive out of order. And it’s almost guaranteed to arrive out of order because we put the usb data in a command queue, and RTS is handled through the system config struct immediately. The queue could be made wider, but then we’re wasting a lot of ram and it will be less deep overall.

The last binary mode we just kind of added things as we needed them. It’s really awful code. This time I’d like to structure it like the modes/syntax compiler with structs of pointers to simple functions. In fact, after the latest rework we may even be able to reuse the same mode structs, just slightly differently. Once the interface is acceptable it shouldn’t take much to build that part out in a much more consistent way.

As a consequence of the make-do dev process last time, there isn’t consistent access to accessories in all modes (PSU, pullups, pin twiddling). I’ve seen code dip in and out of modes to do stuff like ADC measurement. So, I’d like to have that all available as a standard set of commands available from all modes (global commands) and then consistent local commands for read/write/start/stop/etc.

Also, I think access to modes should be through a string designation that’s the same as the command prompt, rather that relying on numbering to remain the same other time.

<data> <data> | 0x7E <command byte> <command data> | <data> <data>

The fastest thing for me, would be to use a simple escape code to indicate command, and then send n bytes of data required by that command. I think I can get that prototyped pretty quickly with the libraries in the /pirate/ folder. Then, if it seems like a protocol buffer is a good idea, I can work in integrating that as the front end to the new BBIO2.

16bit is fine with me. It does halve the throughput. I guess it can be compensated by using a write n/readn command where the next n bytes are 8 bit data streams.

While we wait for confirmation the file system and stack overflow bugs are squashed, I’d like to sketch out binary mode.

Legacy commands:
0x00 0x00 0x00 0x00 0x00 0x02 - enter logic analyzer mode (sigrok fails on windows with this driver, something new might be in order)

Global control commands (available in every mode)

Commands Commands
w/W Power supply (off/ON) a/A/@ x Set IO x state (low/HI/READ)
f x/F x Measure freq on IOx (once/CONT) g x/G Generate frequency (off/ON)
p/P Pull-up resistors (off/ON) v x/V x Show volts on IOx (once/CONT)
l/L Bitorder (msb/LSB) # Reset the Bus Pirate
$ Jump to bootloader m Change to a protocol mode such as I2C
> Run bus syntax (global/local)

Local/syntax commands (bus actions)

Commands Commands
[/{ Start/Start II (mode dependent) ]/} Stop/Stop II (mode dependent)
123 Write value (decimal) r Read
/ Clock high \ Clock low
^ Clock tick - Data high
_ Data low . Read data pin state
d/D Delay 1 us/MS (d:4 to repeat) a/A/@.x Set IO.x state (low/HI/READ)
v.x Measure volts on IO.x > Run bus syntax (really a global command…)

A couple considerations:

  • It would be easy to remember if we use the command character as the code for each command. eg r = read = 0x72. However, it will make enum-ing a nice define an absolute nightmare.
  • I feel to start, it is going to be easiest to bypass the syntax compiler and give the host PC direct access to the peripheral.
1 Like


binmode branch in git has my work in progress. Not much so far:

  • A random bit of code and notes in binio.c
  • A new terminal mode ‘BIN’ that will serve as a loopback for debugging the binary mode. Because i really don’t like realterm…

The next step is to tear out all the messy old binmode trails in usb_rx and usb_tx, and make a simple queue with similar functions as the terminal queue. This is going to be key for injecting commands from the terminal bin loopback mode.

Once an echo test is going, I’ll connect the mode struct functions and then add the global commands. I think it will come together quickly once the queue infrastructure is in place.

enum {
    BM_RESET = 0,

Here’s a proof of concept. The new binmode loopback mode sends commands to the binmode queue for testing.

0x01 enables the psu (currently fixed at 3.3volts)
0x03 enables the pull-up resistors


Commands may now have trailing argument bytes, determined in the global_command_struct.

static const struct _binmode_global_struct global_commands[]={ 

PSU enable has four argument bytes:

0x01 <volts integer> <volts decimal (/100)> <current ma> <override current limit (bool)>
0x01 3 30 0 1

This enables the PSU with 3.3volts, 0mA, current limit override.

I really like the idea of plain int values in the protocol. Lots of times (old bus pirate, SUMP LA protocol) you need to calculate the register values, which are drastically different on different hardware and not very portable.

I’ve done some really ugly hacks to get old protocols working on new hardware, and this prevents that nonsense. Will do the same with PWM/freq/ADC values, maybe with second command with direct register/value access.

Modes list

Current command 0x05 (these will change) gives a ; delimited list of plain text mode names. Many that should be simple comma instead?

For the ‘change mode’ command, I think it would be nice to send these strings back so we’re no longer tied to any fixed numbering of the protocols that might drift over time and cause scripts to break. If we change the name of a mode/protocol, it’s easy enough to add a backwards compatible check in binmode.

Error and confirmation

The old binary mode is a jumble of commands that respond or don’t respond. I’m leaning towards a dumb “no-response even on error” mode, with a command to enable a verbose mode. The default isn’t as important as consistent use of success/fail when configured.

Here’s a test firmware, I’ve also pushed to the binmode branch: (174.7 KB)