The Serial Peripheral Interface Bus (SPI) is a synchronous serial data link standard, named by Motorola, which operates in full duplex mode. Devices communicate in master/slave mode, where the master device initiates the data frame.

The SPI bus can operate with a single master device and with one or more slave devices. The ConnectCore 8M Mini device is always the SPI master of an SPI bus and, by default, only can have one SPI slave connected.

The ConnectCore 8M Mini has several SPI interfaces to communicate with other SPI devices using this protocol. In the ConnectCore 8M Mini Hardware Reference Manual you can find information about the available SPI interfaces.

Digi adds to Android an API to manage these SPI interfaces. You can configure the SS (Slave Select) behavior, write, transfer, and read among other things. In the Digi APIx javadoc you can find a complete list of the available methods in this API.

Unless noted, all SPI API methods require the com.digi.android.permission.SPI permission.

If your application does not have the com.digi.android.permission.SPI permission it will not have access to any SPI service feature.

First, a new SPIManager object must be instantiated by passing the Android Application Context.

Instantiate the SPIManager
import android.app.Activity;
import android.os.Bundle;

import com.digi.android.spi.SPIManager;

public class SPISampleActivity extends Activity {

    SPIManager spiManager;

    [...]

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Instantiate the SPI manager object.
        spiManager= new SPIManager(this);

        [...]
    }

    [...]
}

Instantiate an SPI interface

The SPIManager allows you to create an SPI interface object to communicate with a slave device connected to a physical interface. For that purpose you need to provide the SPI interface number and SPI slave device ID number as parameters. You can use the SPIManager to list all the SPI interfaces of your ConnectCore 8M Mini as well as the slave device IDs connected to each SPI interface.

Method Description

createSPI(int, int)

Creates and returns an SPI object with the given interface and slave device

listInterfaces()

Lists all the available SPI interface numbers

listSlaveDevices(int)

Lists all the available slave devices of the given SPI interface number

The createSPI(int, int) method may fail if the interface number or slave device ID are 0 or lower than 0, throwing an IllegalArgumentException.

Getting an SPI interfaces
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIManager;

import java.util.ArrayList;

[...]

SPIManager spiManager = ...;

// Create an SPI object for each available SPI interface and connected slave.
int[] nInterfaces = spiManager.listInterfaces();
ArrayList<SPI> interfaces = new ArrayList<SPI>();

for (int i = 0; i < nInterfaces.length; i++) {
    int spiInterface = nInterfaces[i];
    int[] nSlaves = spiManager.listSlaveDevices(spiInterface);
    for (int j = 0; j < nSlaves.length; j++)
        interfaces.add(spiManager.createSPI(spiInterface, nSlaves[j]));
}

[...]

Manage the SPI interface

The next step is to open the SPI interface. To do so, you just need to call the open(SPIConfig) method. Prior to opening the interface you can get its interface and slave number and check its current status (open or closed). When you are done with the interface, you must close it. All this management can be performed using the following methods:

Method Description

getInterface()

Gets the SPI interface number

getSlaveDevice()

Gets the SPI slave device number

isInterfaceOpen()

Gets the status of the SPI interface

open(SPIConfig)

Opens the SPI interface with the given configuration. See Configure an SPI interface.

close()

Attempts to close the SPI interface

The open(SPIConfig) method may fail for the following reasons:

  • There is an error opening the SPI interface, throwing an IOException.

  • The configured SPI interface does not exist, throwing NoSuchInterfaceException.

  • The provided SPI configuration object is null, throwing a NullPointerException.

The close() method may fail if there is an error closing the SPI interface, throwing an IOException.

Managing the SPI interface
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIManager;

[...]

SPIManager spiManager = ...;

SPI spiInterface = ...;

// Print interface and slave number.
System.out.println("Created SPI interface " + spiInterface.getInterface() + " at slave " + spiInterface.getSlaveDevice());

[...]

// Check if the interface is open, if not, open it.
if (!spiInterface.isInterfaceOpen()) {
    SPIConfig spiConfig = ...;
    spiInterface.open(spiConfig);
}

[...]

// Close the SPI interface.
spiInterface.close();

Configure an SPI interface

The open(SPIConfig) method of an SPI interface requires an object that represents the configuration of the SPI interface as parameter. This object is an instance of the SPIConfig class. The SPIConfig object can be instantiated providing the SPI clock mode, bit order, chip select, clock frequency and word length. If the chip select and bit order parameters are not provided, the constructor will use the SPIChipSelect.ACTIVE_LOW and SPIBitOrder.MSB_FIRST default values.

Creating an SPIConfig object
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIBitOrder;
import com.digi.android.spi.SPIChipSelect;
import com.digi.android.spi.SPIClockMode;
import com.digi.android.spi.SPIConfig;
import com.digi.android.spi.SPIManager;

[...]

SPIManager spiManager = ...;

SPI spiInterface = ...;

[...]

// Create the SPIConfig object with the following configuration:
//  - Clock mode: CPOL_1_CPHA_0
//  - Chip select: ACTIVE_LOW
//  - Bit order: MSB_FIRST
//  - Clock frequency: 50 KHz
//  - Word length: 8 bits per word
SPIConfig spiConfig = new SPIConfig(SPIClockMode.CPOL_1_CPHA_0, SPIChipSelect.ACTIVE_LOW, SPIBitOrder.MSB_FIRST, 50000, 8);

// Open the interface with the configuration specified in spiConfig.
spiInterface.open(spiConfig);

The values used for the clock mode, chip select and bit order are constants that can be found in the SPIClockMode, SPIBitOrder, and SPIChipSelect enumerator classes.

Once the SPIConfig object has been declared, you can take the values of the different customization parameters with their corresponding get methods.

Method Description

getBitOrder()

Gets the configured bit ordering

getChipSelect()

Gets the configured chip select active level

getClockFrequency()

Gets the clock frequency in Hz

getClockMode()

Gets the configured clock mode

getWordLength()

Gets the word length

Getting SPIConfig parameters
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIConfig;
import com.digi.android.spi.SPIManager;

[...]

SPIManager spiManager = ...;

SPI spiInterface = ...;

SPIConfig spiConfig = ...;
spiInterface.open(spiConfig);

// Print configuration values.
System.out.println("Open SPI interface with the following configuration:");
System.out.println(" - Clock mode: " + spiConfig.getClockMode().name());
System.out.println(" - Chip select: " + spiConfig.getChipSelect().name());
System.out.println(" - Bit order: " + spiConfig.getBitOrder().name());
System.out.println(" - Clock frequency: " + spiConfig.getClockFrequency() + " Hz");
System.out.println(" - Word length: " + spiConfig.getWordLength() + " bits per word");

SPIClockMode

This is the list of the available SPI clock modes to be used when declaring the SPIConfig object.

Value Description

CPOL_0_CPHA_0

Data captured on the clock’s rising edge and propagated on a falling edge

CPOL_0_CPHA_1

Data captured on the clock’s falling edge and propagated on a rising edge

CPOL_1_CPHA_0

Data captured on clock’s falling edge and propagated on a rising edge

CPOL_1_CPHA_1

Data captured on clock’s rising edge and propagated on a falling edge

SPIBitOrder

This is the list of the available SPI bit order values to be used when declaring the SPIConfig object.

Value Description

MSB_FIRST

The most significant bit is transferred in first place

LSB_FIRST

The less significant bit is transferred in first place

SPIChipSelect

This is the list of the available SPI chip select configurations to be used when declaring the SPIConfig object.

Value Description

ACTIVE_LOW

Chip select line active low

ACTIVE_HIGH

Chip select line active high

NOT_CONTROLLED

Chip select not controlled by driver

Communicate with the SPI interface

When the SPI object connection is open you can communicate with the slave device corresponding to that object using the following actions:

Read data

To read data from an SPI interface you only need to use the read(int) method providing the number of bytes to read as parameter.

Method Description

read(int)

Reads the specified number of bytes from the SPI slave device

The read(int) method may fail for the following reasons:

  • The number of bytes to read is lower than 0, throwing an IllegalArgumentException.

  • The SPI interface is closed or there is an error reading from the SPI interface, throwing an IOException.

Reading data from the SPI interface
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIManager;

[...]

SPIManager spiManager = ...;

SPI spiInterface = ...;

[...]

// Read 8 bytes of data.
byte[] readData = spiInterface.read(8);

[...]
When you are done with the SPI interface, you need to close it by calling the close() method.

Write data

The SPI API allows you to write data to the SPI slave device associated to the SPI interface object. For that purpose you need to call the write(byte[]) method providing the array of bytes to write as parameter.

Method Description

write(byte[])

Writes the given bytes in the SPI slave device

The write(byte[]) method may fail for the following reasons:

  • The SPI interface is closed or there is an error writing in the SPI slave device, throwing an IOException.

  • The array of bytes to write in the SPI interface is null, throwing a NullPointerException.

Writing data to the SPI interface
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIManager;

[...]

SPIManager spiManager = ...;

SPI spiInterface = ...;

[...]

// Write "Hello SPI".
spiInterface.write("Hello SPI".getBytes());

[...]
When you are done with the SPI interface you need to close it by calling the close() method.

Transfer data

The third communication method provided by the SPI interface object allows you to read and write data simultaneously in one operation. There are two methods for such operation, both of them behave the same way, but in one method you can also specify the clock frequency and word length. If they are not specified, the operation will use the values of the SPIConfig object provided in the open(SPIConfig) method.

Method Description

transfer(byte[])

Simultaneous write (of the given bytes) and read (of the same number of bytes) using the default clock frequency and word length parameters

transfer(byte[], int, int)

Simultaneous write (of the given bytes) and read (of the same number of bytes) using the given clock frequency and word length parameters (these parameters are only used for this transfer, but their default values remain the same)

Previous methods may fail for the following reasons:

  • The SPI interface is closed or there is an error transferring data, throwing an IOException.

  • The byte array of data to transfer is null, throwing a NullPointerException.

In addition, the transfer(byte[], int, int) method may fail if the clock frequency or word length provided are lower than one, throwing an IllegalArgumentException.

Transferring data to the SPI interface
import com.digi.android.spi.SPI;
import com.digi.android.spi.SPIManager;

[...]

SPIManager spiManager = ...;

SPI spiInterface = ...;

[...]

// Transfer "Hello SPI" reading the same amount of bytes (9) in the same operation.
byte[] readData = spiInterface.transfer("Hello SPI".getBytes());

// Transfer "Hello SPI" reading the same amount of bytes (9) and configure the clock
// frequency with 500KHz and word length with 8bits per word.
byte[] readData = spiInterface.transfer("Hello SPI".getBytes(), 500000, 8);

[...]
When you are done with the SPI interface you need to close it by calling the close() method.

SPI example

The SPI Sample Application demonstrates the usage of the SPI API by monitoring the communication with a slave device. The application allows reading, writing and transferring data to the slave device.

You can import the example using Digi’s Android Studio plugin. For more information, see Import a Digi sample application. To look at the application source code, go to the GitHub repository.