Menu

UseLibrary

Bruno Quoitin

This page briefly describes how to develop with the library. First a minimal example shows how to connect to the bus pirate and obtain its version number. Second a more complete example is provided that shows how to interact with an I2C device.


Minimal example

The first example just shows how to connect to the Bus Pirate, obtain the firmware version and disconnect.

To connect to the Bus Pirate, the bp_open function is used. It takes a single parameter : the name of the serial driver associated to the Bus Pirate. In the example, this name is obtained from the command line (argument argv). The function returns a pointer to a data structure of type BP. This data structure is used during subsequent API functions. If a NULL pointer is returned, this means the connection failed.

To disconnect from the Bus Pirate, the bp_close function is used. This function takes a single argument : the connection handle (pointer to BP structure).

To obtain the firmware version, the functions bp_firmware_version_high and bp_firmware_version_low can be used. Those functions take the connection handle as argument and return an integer that corresponds to the high (major) or low (minor) version.

:::C
#include <stdlib.h>
#include <stdio.h>
#include "buspirate.h"

void error(const char * msg)
{
  fprintf(stderr, "Error: %s\n", msg);
  fflush(stderr);
  exit(EXIT_FAILURE);
}

int main(int argc, char ** argv)
{
  BP * bp;

  if (argc < 2)
    error("Not enough arguments : Bus Pirate device name required.");

  printf("Connecting to Bus Pirate.\n  device = %s...\n", argv[1]);
  bp= bp_open(argv[1]);
  if (bp == NULL)
    error("Could not connect to Bus Pirate.");

  printf("Firmware version : %d.%d\n",
     bp_firmware_version_high(bp),
     bp_firmware_version_low(bp));

  printf("Closing connection.\n");
  bp_close(bp);
  exit(EXIT_SUCCESS);
}

To compile this example, just use the following commands. We assume the above example has been written in a file named example.c and the library has been installed under /usr/local.

host:example user$ gcc -o example -L/usr/local/lib -I/usr/local/include/buspirate example.c -lbuspirate

You can then run the example. You should obtain something similar to the output shown below.

host:example user$ ./example /dev/ttyUSB0
Connecting to Bus Pirate.
  device = /dev/ttyUSB0...
-->Firmware=[5.10]
Firmware version : 5.10
Closing connection.
host:example user$

I2C example - Silicon Labs Si5351

In this example, we show how to setup the bus pirate for I2C communication with a Si5351 clock generator from Silicon Labs (datasheet here). We assume the program connects to the bus pirate using the bp_open primitive presented in the above example. We also assume the availability of an error function, that we can call to report an error message and exit the program when things go wrong.

In our test setup, the Si5351 device is connected to the bus pirate as follows (we use a breakout board from Adafruit):

Si5351 Bus pirate
Vss 3.3V
Gnd Gnd
SCL SCK
SDA MOSI
Vpu is connected to 3.3V

To use the bus pirate I2C peripheral, we first switch the bus pirate firmware to "binary mode" using the bp_bin_init function. Then, we select the I2C binary mode using the bp_bin_mode_i2c function.

The last step to have I2C working consists in selecting the bus speed using the bp_bin_i2c_set_speed function. In the example above, the clock "speed" is set to 5kHz using the BP_BIN_I2C_SPEED_5K constant. Since we power up the Si5351 device from the bus pirate 3.3V output, we also need to enable the bus pirate internal power supply using the bp_bin_i2c_set_periph function and the BP_BIN_I2C_PERIPH_POWER constant. In order for the I2C bus to work properly (devices only pull the lines down), pull-up resistors need to be connected on the SCL and SDA lines. In our setup, we didn't use external resistor but we used the bus pirate internal pull-ups. They are enabled by passing the additional constant BP_BIN_I2C_PERIPH_PULLUPS to the bp_bin_i2c_set_periph function.

:::C
int main()
{
  unsigned char version;

  // open bus pirate (not shown)

  /* switch to binary mode */
  if (bp_bin_init(bp, &version) != BP_SUCCESS)
    error("could not switch to binary mode");

  /* select I2C binary mode */
  if (bp_bin_mode_i2c(bp, &version) != BP_SUCCESS)
    error("could not initialize I2C mode");

  /* configure I2C speed (5KHz) */
  if (bp_bin_i2c_set_speed(bp, BP_BIN_I2C_SPEED_5K) != BP_SUCCESS)
    error("could not setup I2C speed");

  /* enable internal power (3.3V/5V) and pull-up resistors */ 
  if (bp_bin_i2c_set_periph(bp, BP_BIN_I2C_PERIPH_POWER | BP_BIN_I2C_PERIPH_PULLUPS) != BP_SUCCESS)
    error("could not enable power and pull-ups");


  /* --> you can interact with device using I2C here <-- */


  /* quit binary mode */
  if (bp_reset(bp) != BP_SUCCESS)
    error("could not reset bus pirate to terminal mode");

  // close bus pirate (not shown)
}

Once I2C binary mode is selected and I2C parameters and peripherals are configured it is possible to interact with a device connected on the bus. In the following code excerpt we show how it is possible to read the value of a Si5351 register. The Si5351 datasheet explains that I2C accesses have the following structure : the first byte contains the device address (0x60 or 0x61) in the 7 most significant bits and a read (1) or write (0) command in the least significant bit.

The procedure to write to a register is done in a single I2C transaction where 3 bytes are written as follows

  1. write device address + write command (0) ; device sends ACK
  2. write register address ; device sends ACK
  3. write register value ; device sends ACK

The procedure to read a register is done in two I2C transactions. The first one writes the register address while the second one reads the register value. In the first transaction, 2 bytes are written as follows

  1. write device address + write command (0) ; device sends ACK
  2. write register address ; device sends ACK

In the second transaction, 1 byte is written and 1 is read, as follows

  1. write device address + read command (1) ; device sends ACK
  2. read register value ; device sends no ACK

In the following example, we show how to implement a read from the Si5351 device. The START of an I2C transaction is signaled with the bp_bin_i2c_start function. The end of an I2C transaction (STOP), is signaled with the bp_bin_i2c_stop function. Function bp_bin_i2c_write writes a single byte on the bus. The function also allows to check if the byte was followed by an ACK of the device. Function bp_bin_i2c_read reads a single byte from the bus.

:::C
int si5351_read(BP * bp,
                unsigned char dev_addr,
                unsigned char reg_addr,
                unsigned char * reg_value)
{
  unsigned char ack;

  /* First transaction : write register address */
  if (bp_bin_i2c_start(bp) != BP_SUCCESS)
    return -1;
  if (bp_bin_i2c_write(bp, (dev_addr << 1), &ack) != BP_SUCCESS)
    return -1;
  if (ack != BP_BIN_I2C_ACK)
    return -1;
  if (bp_bin_i2c_write(bp, reg_addr, &ack) != BP_SUCCESS)
    return -1;
  if (ack != BP_BIN_I2C_ACK)
    return -1;
  if (bp_bin_i2c_stop(bp) != BP_SUCCESS)
    return -1;

  /* Second transaction : read register value */
  if (bp_bin_i2c_start(bp) != BP_SUCCESS)
    return -1;
  if (bp_bin_i2c_write(bp, (dev_addr << 1) | 1, &ack) != BP_SUCCESS)
    return -1;
  if (ack != BP_BIN_I2C_ACK)
    return -1;
  if (bp_bin_i2c_read(bp, reg_value) != BP_SUCCESS)
    return -1;
  if (bp_bin_i2c_stop(bp) != BP_SUCCESS)
    return -1;
  return 0;
}

Related

Wiki: Home

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.