Let’s talk a bit about porting firmware to the Bus Pirate, in case anyone else wants to try it.
copy pirate-lib
There is an evolving library of low level drivers for the Bus Pirate hardware I’m calling pirate-lib. It is not a stand alone submodule yet because it is still rapidly evolving.
- Copy the pirate folder to the firmware source
copy pirate_config.h
Each project is customized with a pirate_config.h in the root directory of the source.
customize pirate_config.h
const char *hw_pin_label_ordered[] = {
"3.3V",
"IO0",
...
"GND"
};
const char *func_pin_label_ordered[] = {
"PicoProbe",
"SCLK",
...
"GND"
};
const char *direction_pin_label_ordered[]={
"->",
"->",
...
};
The three arrays contain text for the three columns on the display.
- First column is 10 pin names on the left of the display. The first member might be customized if a power supply is active or if the target must provide the power. The rest are generally IO0…7+GND
- Second column describes the pin use in this particular firmware. The first member of the second column is the firmware name and is printed at the top.
- Third column I use for direction indication, but could be up to four letters of your choice
static inline void pirate_options_init(void){
#include "pirate/psu.h"
#include "pirate/button.h"
if(!button_get(0)){
ui_lcd_update(hw_pin_label_ordered_3v3, func_pin_label_ordered, direction_pin_label_ordered);
psu_enable(3.3, 0, true);
}else{
ui_lcd_update(hw_pin_label_ordered_vin, func_pin_label_ordered, direction_pin_label_ordered);
}
#include "pirate/pirate.h"
#include "pirate/bio.h"
#include "board_buspirate5_config.h"
//configure buffer directions
bio_set_buffer_dir(PROBE_UART_TX, true);
bio_set_buffer_dir(PROBE_UART_RX, false);
}
pirate_options_init()
is called at the end of the pirate-lib initialization. This is a good place to put any customized startup code for the firmware port. Here we:
- Check if button is pressed. Enable the power supply and draw the correct labels on the LCD
- Use the pirate-lib bio (buffered io) functions to set the uart_tx buffer to output and the rx buffer to input
Keeping the Bus Pirate init code here instead of inside the ported firmware makes it a LOT easier to merge in updates from the original project later.
initialize Bus Pirate hardware
int main(void) {
// Declare pins in binary information
bi_decl_config();
#ifdef BOARD_BUSPIRATE
pirate_init();
#endif
board_init();
usb_serial_init();
cdc_uart_init();
tusb_init();
stdio_uart_init();
Include pirate/pirate.h in the main file of the firmware. Call pirate_init()
near the beginning of the firmware. This will configure all the hardware to a safe state and call pirate_options_init()
at the end.
configure and use buffered IO pins
// Buffer IO defines
#define BUFIO0 8
#define BUFIO1 9
#define BUFIO2 10
#define BUFIO3 11
#define BUFIO4 12
#define BUFIO5 13
#define BUFIO6 14
#define BUFIO7 15
The Bus Pirate IO pins have a bidirectional buffer. gpio0-7 control the direction of the buffer, gpio8…15 control the level of the buffer. You can find the gpios defined in pirate/pirate.h.
Probably the most commonly used part of pirate-lib are the buffered io pin functions in pirate/bio.h. Depending on how you use IO pin it will be easy or slightly annoying.
unidirectional io pins
void bio_set_buffer_dir(uint8_t bio, bool dir) {
gpio_put(bio-8, dir);
}
For pins that don’t change direction (UART RX/TX, SPI, etc) you can simply use bio_set_buffer_dir(BUFIOn, false/true)
to set the buffer to an input or output and then use the gpio as normal.
bidirectional pins
void bio_set_dir(uint8_t bio, bool dir) {
...
if(dir) {
// first set the buffer to output
gpio_put(bio-8, BUFDIR_OUTPUT);
// now set pin to output
gpio_set_dir(bio, GPIO_OUT);
} else {
// first set the pin to input
gpio_set_dir(bio, GPIO_IN);
// now set buffer to input
gpio_put(bio-8, BUFDIR_INPUT);
}
Pins that change direction, such as I2C data pins, need to be carefully managed. bio_set_dir(BUFIOn, false/true)
sets both the buffer and the pin directions in a single function.
To use this for open drain IO, such as pulling a jtag reset line low, set the gpio level to 0/ground. Then use bio_set_dir() to alternate between input (high) and output (low).