SPI (Serial Peripheral Interface) is a synchronous 4-wire interface often used commonly used for short-distance communication, e.g. between different ICs on a same board.

Black Swift uses hardware SPI interface to communicate with its own NOR flash memory, and software SPI can be used to communicate with external SPI-compatible devices. With Black Swift, it can be used to connect such devices as DAC, ADC, or peripheral microcontrollers.

Activating SPI master interface

Software SPI interface (as master) can be activated on any GPIO pins not used for other means. It is provided by the standard spi-gpio-custom kernel module.

To install the module, run (in the standard Black Swift firmware, module is installed already):

opkg install kmod-spi-gpio-custom

To activate the module, run:

insmod spi-gpio-custom BUS=ID,SCK,MOSI,MISO,MODE,FREQ,CS

Where:

BUS — SPI bus number, can be bus0, bus1, bus2, bus3

ID — SPI device ID (integer number)

SCK, MOSI, MISO — GPIO numbers for the corresponding SPI signals

MODE — SPI mode (0, 1, 2 or 3)

FREQ — max SPI frequency (Hz)

CS — GPIO number for the CS signal (optional)

After successfully loading the module, /dev/spidev<BUS>.<ID> device will be created.

For example, let's create SPI interface with bus = 1, ID = 1, SCK = GPIO18, MOSI = GPIO19, MISO = GPIO 20, SPI mode 0, max frequency 100 kHz, and CS = GPIO23:

insmod spi-gpio-custom bus1=1,18,19,20,0,100000,23

CS pin can be omitted if you have a single slave on a bus and it doesn't need CS signal to operate properly — or if you want to control CS signal independently.

To create SPI interfaces automatically, you may want to add insmod command line with corresponding parameters to the /etc/rc.local file.

Simplex data transfers

SPI is a duplex interface by its nature, but without a bit of C programming you can use it in simplex mode only by writing to and reading from /dev/spidev devices.

For example, to send word "hello" to the slave device from bash script, run:

echo "hello" > /dev/spidev1.1

Duplex data transfers

Full duplex operation can be implemented in C/C++ using ioctl calls. For example, to transfer some data between Black Swift and a slave device, one can use:

#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

int spiTransfer(unsigned char *sendBuffer, unsigned char *receiveBuffer, int bytes)
{
    int spiDev;
    if ((spiDev = open("/dev/spidev1.1", O_RDWR)) < 0)
        return -1;

    struct spi_ioc_transfer xfer;
    memset(&xfer, 0, sizeof(xfer));
    xfer.tx_buf = (unsigned long)sendBuffer;
    xfer.rx_buf = (unsigned long)receiveBuffer;
    xfer.len = bytes;

    int res = ioctl(spiDev, SPI_IOC_MESSAGE(1), &xfer);
    
    return res;
}

sendBuffer and receiveBuffer must be at least bytes in size. Data to send should be put in sendBuffer before calling the function, and received data will be in receiveBuffer afterwards. Function returns negative value if ioctl call fails or SPI device is inaccessible.