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 6 device is always the SPI master of an SPI bus and, by default, only can have one SPI slave connected.
The ConnectCore 6 has several SPI interfaces to communicate with other SPI devices using this protocol. In the ConnectCore 6 Hardware Reference Manual you can find information about the available ADC channels.
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.
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 6 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.
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.
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.
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 |
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.
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.
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.
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
Example: SPI |
---|
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. |