
Raw SPI is a new mode that provides high-speed access to the Bus Pirate SPI hardware. It was developed in conjunction with Michal Ludvig, so that AVRDude can use the Bus Pirate to program AVR microcontrollers and EEPROMs.
Firmware v2.3 includes two new raw I/O modes that give computer software and scripts direct access to the Bus Pirate hardware. Hopefully this opens the door to a whole new class of Bus Pirate applications, like chip programmers. In this post we describe the raw SPI access mode. We’ll describe the raw bigbang mode in a few days. The protocol is documented below the break.
Raw SPI mode command table
- 00000000 – Enter raw bitbang mode, reset to raw bitbang mode
- 00000001 – SPI mode/rawSPI version string (SPI1)
- 00000010 – CS low (0)
- 00000011 – CS high (1)
- 00001101 – Sniff all SPI traffic
- 00001110 – Sniff when CS low
- 00001111 – Sniff when CS high
- 0001xxxx – Bulk SPI transfer, send 1-16 bytes (0=1byte!)
- 0010xxxx – Low 4 bits of byte + single byte write/read
- 0011xxxx – High 4 bits of byte
- 0100wxyz – Configure peripherals, w=power, x=pullups, y=AUX, z=CS
- 01010000 – Read peripherals
- 01100xxx – Set SPI speed, 30, 125, 250khz; 1, 2, 2.6, 4, 8MHz
- 01110000 – Read SPI speed
- 1000wxyz – SPI config, w=output type, x=idle, y=clock edge, z=sample
- 10010000 – Read SPI config
Commands are a single byte, except bulk SPI transfers. The Bus Pirate responds to SPI write commands with the data read from the SPI bus during the write. Most other commands return 0×01 for success, or 0×00 for failure/unknown command.
Key points
- Send the raw byte value 0×00 into the user command prompt 20 times to enter bitbang mode.
- Enter 0×01 in bitbang mode to enter raw SPI mode.
- Return to raw bitbang mode from raw SPI mode by sending 0×00 one time.
- Operations that write a byte to the SPI bus also return a byte read from the SPI bus.
- Hex values shown here, like 0×00, represent actual byte values; not typed ASCII entered into a terminal.
- Other values are shown as 8bit binary numbers. Here’s a binary->decimal->hex converter.
Commands
00000000 – Enter raw bitbang mode, reset to raw bitbang mode
This command has two purposes. First, send it to the command line interface 20 times to enter the raw bitbang binary mode. It’s also used to exit the raw SPI mode and return to raw bitbang mode.
Send the value 0×00 to the Bus Pirate command line interface 20 times to enter raw bitbang mode. The Bus Pirate replies ‘BBIOx’, where x is the raw bitbang version number (currently 1).
Once in raw SPI mode (see command 00000001), the 0×00 command returns to raw bitbang mode. Send 0×00 once to return to raw bitbang mode.
00000001 – Enter raw SPI mode, display version string
Once in raw bitbang mode, send 0×01 to enter raw SPI mode. The Bus Pirate responds ‘SPIx’, where x is the raw SPI protocol version (currently 1). Get the version string at any time by sending 0×01 again.
0000001x – CS high (1) or low (0)
Toggle the Bus Pirate chip select pin, follows HiZ configuration setting. CS high is pin output at 3.3volts, or HiZ. CS low is pin output at ground. Bus Pirate responds 0×01.
00001101 – Sniff all SPI traffic, 0000111x – Sniff when CS low(0)/high(1)
The SPI sniffer is implemented in hardware and should work up to 10MHz. It follows the configuration settings you entered for SPI mode. The sniffer can read all traffic, or filter by the state of the CS pin.
- [/] – CS enable/disable
- \ – escape character precedes a data byte value
- (\x) – MISO read
Sniffed traffic is encoded according to the table above. The byte sniffed on the MISO pin is displayed inside (). Data bytes are escaped with the ‘\’ character.
Send a single byte to exit, Bus Pirate responds 0×01 on exit.
0001xxxx – Bulk SPI transfer, send/read 1-16 bytes (0=1byte!)
Bulk SPI allows direct byte reads and writes. The Bus Pirate expects xxxx+1 data bytes. Up to 16 data bytes can be sent at once, each returns a byte read from the SPI bus during the write.
Note that 0000 indicates 1 byte because there’s no reason to send 0. BP replies 0×01 to the bulk SPI command, and returns the value read from SPI after each data byte write.
0100wxyz – Configure peripherals w=power, x=pull-ups, y=AUX, z=CS
Enable (1) and disable (0) Bus Pirate peripherals and pins. Bit w enables the power supplies, bit x toggles the on-board pull-up resistors, y sets the state of the auxiliary pin, and z sets the chip select pin. Features not present in a specific hardware version are ignored. Bus Pirate responds 0×01 on success.
Note: CS pin always follows the current HiZ pin configuration. AUX is always a normal pin output (0=GND, 1=3.3volts).
Read the current settings by sending 01010000.
01100xxx - SPI speed
000=30kHz, 001=125kHz, 010=250kHz, 011=1MHz, 100=2MHz, 101=2.6MHz, 110=4MHz, 111=8MHz
This command sets the SPI bus speed according to the values shown. Default startup speed is 000 (30kHz).
Read the current settings by sending 01110000.
1000wxyz – SPI config, w=HiZ/3.3v, x=CKP idle, y=CKE edge, z=SMP sample
This command configures the SPI settings. Options and start-up defaults are the same as the user terminal SPI mode. w= pin output HiZ(0)/3.3v(1), x=CKP clock idle phase (low=0), y=CKE clock edge (active to idle=1), z=SMP sample time (middle=0). The Bus Pirate responds 0×01 on success.
Default raw SPI startup condition is 0010. HiZ mode configuration applies to the SPI pins and the CS pin, but not the AUX pin. See the PIC24FJ64GA002 datasheet and the SPI section[PDF] of the PIC24 family manual for more about the SPI configuration settings.
Read the current settings by sending 10010000.
0010xxxx, 0011yyyy – Enter SPI data byte in nibbles, read SPI byte
Data bytes can also be entered in two nibbles using this pair of commands. 0011yyyy loads the upper 4 bits of a data byte. 0010xxxx loads the lower 4 bits of the data byte, and writes it to the SPI bus. The bus write returns a byte read.
A byte is transmitted over SPI each time the low bits are sent. Be sure to send the upper bits first, then send the lower bits to complete the data and transmit it. If the upper four bits are the same as the previous byte, then you can increase speed by sending just the lower four bits.
Entering the upper 4 bits returns 1 for success, or 0 for failure. Entering the low bits returns a byte read from the SPI bus.
-
Nice. Couple of questions though…
1) Is this the final version of the protocol or can we still do some mods?
2) The reset command 0×00 – does it reset the BP into HiZ mode?
3) 0011000x (CS) – the fact that it’s inverted is IMO really confusing. If someone is that far that he is using binary mode he probably knows whether he wants CS High or Low – there’s no need for ‘user friendly’ enable/disable confusion.
4) 0100wxyz (Configure peripherals) – can we have a command for reading the peripherals config as well? Maybe make a rule “if (cmd & 0×10 == 0×00) { it’s a get_config } else { it’s a set_config }”
Similar for reading the the speed and SPI config.
5) Instead of returning 0×01 for set_config it may be worth returning the previous state.
6) I’m not sure why you retained the nibble-based transfers? The same functionality as for (0×1X 0×2Y) can be achieved in the two bytes with bulk transfer (0×50 0xXY).I’m going to make an avrdude patch now ;-)
-
1)We can mod it all we want :)
2) 0×00 returns to raw bitbang mode (with HiZ pin states). I added command 0b1111 in raw bitbang mode to reset the Bus Pirate and return to the user terminal.
3) Changed it.
4 & 5) Great idea, absolutely, but is it OK to leave it out until SPI2? I need to push the v2.3 firmware to manufacturing and this will take a bit of effort. You can always assume the default settings after moving from raw bitbang mode to raw SPI mode, and your settings take effect if you get 0×01.
6) I wrote a Perls script that programs/dumps/erases EEPROMs and I used that command. To read an EEPROM I load 0xFF in two nibbles, then just hit it with the lower nibble to read bytes until the end. -
@Ian – how about leaving all this binmode stuff out from 2.3 and include it in 2.4 after it settles and shows its strengths and weaknesses? It would be annoying to have two slightly incompatible binmode versions out in the wild.
For now AVRdude is all right with text mode parsing. Today I increased its speed by 75% comparing to the original patch, so it’s actually usable :-) Lets do the binmode right in the next couple of weeks for firmware 2.4.
How does that sound?
-
wow! looks like bus pirate is heading new direction
-
Are 4&5 the only items you’d like to see before a v1 protocol? It’s too much of a pain to remove it prior to the next release, so it’ll be there. The question is how ‘final’ it is.
Here’s the update I’d propose:
# 00000001 – SPI mode/rawSPI version string (SPI1)
# 00000010 – CS low (0)
# 00000011 – CS high (1)
# 0001xxxx – Bulk SPI transfer, send 1-16 bytes (0=1byte!)
# 0010xxxx – Low 4 bits of byte + single byte write/read
# 0011xxxx – High 4 bits of byte
# 0100wxyz – Configure peripherals w=power, x=pullups, y=AUX, z=CS
# 0101wxyz – read peripherals w=power, x=pullups, y=AUX, z=CS
# 01100xxx – Set SPI speed,
# 01110xxx – Read SPI speed,
# 1000wxyz – SPI config, w=output type, x=idle, y=clock edge, z=sample
# 1001wxyz – read SPI config, w=output type, x=idle, y=clock edge, z=sampleEdit: swapped config. peripheral and set SPI speed.
Added three low speed options to SPI:
000=1kHz, 001=5kHz, 010=10khz, 011=30kHz 101=125kHz, 110=250khz, 111=1000kHz
30khz is the lowest possible speed for hardware SPI, we can always use a software library if we need something slower. -
For an official binmode firmware would like to see:
1) Indication what binmode version is supported in the ‘I’ output2) Have an attack plan for I2C, 1W, UART, … support, and also ADC and perhaps Freq probe. Not only SPI. The commands doing similar stuff should have similar semantics for all protocols.
3) Make sure that the BP’s responses to binmode commands are easy to handle. For instance that they have a constant length – at the moment 0×00 response is BBIO1, 0×01 is SPI1 and the rest is one byte. That may make parsing a bit inconvenient (not sure, it just rings the bell. I haven’t implemented binmode for avrdude yet).
4) The two dedicated CS commands are redundant because we can now read peripherals status and set CS from there.
5) I’m still not in favour of 0×2x and 0×3x for sending SPI data. It’s redundant to Bulk spi. This is not about being user friendly because you will always control binmode from a program.
6) Where has bitbanging support gone? IMO we should reserve commands with the MSB set for bitbanging. That is:
if (cmd & 0×80) { set_pins(cmd & 0×7F) } else { process_command(cmd) }7) Regarding speeds – Standard speeds for I2C are 100kHz and 400kHz if I’m not mistaken. SPI should probably support those as well. What’s the max freq the PIC can generate? Perhaps have 1k (for the extreme cases where 30k is too fast), 30k, 100k, 400k, 1MHz, PIC-Max MHz.
I don’t believe in releasing an official firmware with an immature protocol. That’ll just cause pain for the app developers in the long run. Especially since fw2.3 should be the official firmware for BPv3 and therefore with potentially thousands of users. No binmode is better than bad binmode – at least there’ll be only one protocol requiring support from the apps.
How come it’s too much pain to remove it? Simply disable handling of 0×00 in a prompt and you’re done. If there is no way to enter binmode it’s the same as if there is no binmode at all ;-)
-
1+3) I don’t want to add more cruft to user mode, so the version string is announced when you send 0×01 and enter raw SPI mode. It will always be four bytes long, so just expect four bytes.
2+6) Raw bitbang mode is the primary raw mode. Other modes like SPI (and future modes) are accessed with commands from that library. For raw SPI, first you enter raw bitbang mode (0×00), then you choose raw SPI from the raw bitbang mode. Other modes will be the same way. I’ll document this mode tomorrow, but I wanted to get this one out today because it might actually be used.
4) Yes, but it’s nice to be flexible, especially for new developers that want to send a simple byte command and not manage the bits for all peripherals.
7) I’ll handle I2C speeds in an I2C library. Pic can’t generate less than 30kHz SPI, but it can go up to 8mHz.
-
1) What does <fw2.3 respond to 0×00? Syntax error? I already have 2.3-pre so I can't test that without downgrading.
4+5) nothing negative, I just don't like redundancy ;-)
7) 8MHz would be nice. For instance ENC28J60 rev B4 requires SPI at 8MHz or higher (see errata for this revision, corrected in B5+ I guess).
Also – can you document how to get out from binmode? Is it 0xFF?
All right, will see if SPI2 will be needed ;-)
-
Thank you so much for your help. I think it’s becoming a much stronger, more logical protocol.
1) Version prior to 2.3 don’t respond at all. The command prompt ignores all non-ASCII characters. If you don’t see “BBIOx”, then it’s not working.
To reset:
* If you’re in raw spi, exit to raw bitbang with 0×00.
* Send 0×0F(0b1111), the bus pirate resets.Here’s the commands for binmode, if you’re curious:
* 00000000 //Enter binmode, show version string “BBIO1″.
* 00000001 //enter rawSPI mode, responds “SPI1″.
* …. //more protocols
* 00001111 //reset Bus Pirate (returns to user terminal)
* 010xxxxx //set pins as input(1) or output(0), responds with read.
* 1xxxxxxx //set pins high (1) or low (0), responds with read.Bitbang bitmaping:
COMMAND|POWER|PULLUP|AUX|CS|MISO|CLK|MOSI -
I agree, it’s got a good shape. Thanks for your patience with all my whining ;-)
One more feature request for later: in bitbanging mode implementing waiting for a pin change and returning pin status when change happens. AVRs have ‘PCINT’ – Pin Change INTerrupt, I’m sure PICs have something similar. That may be useful for sort of a “logic analyser” app. But that can indeed wait after 2.3 ;-)
-
It looks like there’s a unintended consequence of the protocol. Some terminals seem to send a NULL character (0×00) on startup, which is sending the Bus Pirate into binary mode accidentally. I’ve made a nightly compile which requires that 0×00 be entered 20 times to enter raw binary mode, and this seems to have cleared up any problems. I’ve updated this guide and the bitbang mode guide.
-
There were also two minor bugs in v2.4 raw SPI mode that I found while writing a demo script:
1. The CS set commands (0×02, 0×03) don’t respond ‘0×01′.
2. The CS set bit of the configure peripherals command (0100) was inverted.These problems are corrected in the v2.5 nightly, fixes will be rolled out in v2.5 after a bit more testing:
http://code.google.com/p/the-bus-pirate/source/browse/#svn/trunk/firmware/v2-nightly
-
The unused pull-up bit on the peripheral configure command for v1a hardware toggles the second AUX pin in firmware v3.0 and later. This applies to all protocol modes, not just SPI. They share this function:
http://code.google.com/p/the-bus-pirate/source/browse/trunk/source/binIOhelpers.c#4 -
Hi, i am villamany from Spain, i think that could be a good feature to add commands for bulk read/write up to 256 (1 byte command + 1 byte bulk size), and up to 65536 (1byte command + 2 byte bulk size).
And add commands for bulk reads only(sending always dummy byte 255) and for bulk write only (ignoring all received bytes). This can be very usefull for reduce the amount of data betwen ftdi and pc. And great speed gain for example programing flash memories. Thanks…

19 comments
Comments feed for this article