SPI (англ. Serial Peripheral Interface, SPI bus — последовательный периферийный интерфейс, шина SPI) — последовательный синхронный стандарт передачи данных в режиме полного дуплекса, предназначенный для обеспечения простого и недорогого высокоскоростного сопряжения микроконтроллеров и периферии. Например, в качестве периферии может быть: дисплей, различные датчики, FLASH память, SD карта и т.д. SPI также иногда называют четырёхпроводным (англ. four-wire) интерфейсом, так как используются четыре линии связи:
- MOSI или SI — выход ведущего, вход ведомого (англ. MasterOutSlaveIn). Служит для передачи данных от ведущего устройства ведомому.
- MISO или SO — вход ведущего, выход ведомого (англ. MasterInSlaveOut). Служит для передачи данных от ведомого устройства ведущему.
- SCLK или SCK — последовательный тактовый сигнал (англ. SerialClock). Служит для передачи тактового сигнала для ведомых устройств.
- CS или SS — выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).
В отличие от стандартного последовательного порта (англ. standard serial port), SPI является синхронным интерфейсом, в котором любая передача синхронизирована с общим тактовым сигналом, генерируемым ведущим устройством (процессором). Принимающая (ведомая) периферия синхронизирует получение битовой последовательности с тактовым сигналом. К одному последовательному периферийному интерфейсу ведущего устройства-микросхемы может присоединяться несколько микросхем. Ведущее устройство выбирает ведомое для передачи, активируя сигнал «выбор кристалла» (англ. chip select) на ведомой микросхеме. Периферия, не выбранная процессором, не принимает участия в передаче по SPI.
На этом видео наглядно показана работа интерфейса SPI.
О том что такое SPI читайте в статьях википедии на русском или на английском.
Pi4J предоставляет возможность работы с последовательной шиной SPI из Java на Raspberry Pi, Banana Pi, Orange Pi, Nano Pi и Odroid. Все классы и интерфейсы для инициализации и работы с шиной находятся в пакете com.pi4j.io.spi.*;.
Ниже представлены описания интерфейсов/классов и их методов.
Класс SpiFactory
Возвращает экземпляры интерфейса com.pi4j.io.spi.SpiDevice.
getInstance(SpiChannel)
Создает новый экземпляр SpiDevice со скоростью SPI по умолчанию 1 МГц.
public static SpiDevice getInstance(SpiChannel channel) throws IOException
Параметры:
channel — канал SPI для использования
Возвращает:
новый экземпляр SpiDeviceImpl
Бросает:
java.io.IOException
getInstance(SpiChannel, SpiMode)
Создает новый экземпляр SpiDevice
public static SpiDevice getInstance(SpiChannel channel, SpiMode mode) throws IOException
Параметры:
channel — канал SPI для использования
mode — SPI режим
Возвращает:
новый экземпляр SpiDeviceImpl
Бросает:
java.io.IOException
getInstance(SpiChannel, int)
Создает новый экземпляр SpiDevice
public static SpiDevice getInstance(SpiChannel channel, int speed) throws IOException
Параметры:
channel — канал SPI для использования
speed — скорость / частота тактового сигнала в герцах (диапазон 500 кГц — 32 МГц)
Возвращает:
новый экземпляр SpiDeviceImpl
Бросает:
java.io.IOException
getInstance(SpiChannel, int, SpiMode)
Создает новый экземпляр SpiDevice
public static SpiDevice getInstance(SpiChannel channel, int speed, SpiMode mode)
Параметры:
channel — канал SPI для использования
speed — скорость / частота тактового сигнала в герцах (диапазон 500 кГц — 32 МГц)
mode — SPI режим
Возвращает:
новый экземпляр SpiDeviceImpl
Бросает:
java.io.IOException
Интерфейс SpiDevice
Это абстракция устройства SPI. Он позволяет записи/чтения данные на устройство.
write(String, Charset)
Чтение/запись данных через SPI
public String write(String data, Charset charset) throws IOException;
Параметры:
data — байты (закодированные в строке) для записи на устройство SPI
charset — кодировка символов для байтов в строке
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(String, String)
Чтение/запись данных через SPI
public String write(String data, String charset) throws IOException;
Параметры:
data — байты (закодированные в строке) для записи на устройство SPI
charset — кодировка символов для байтов в строке
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(ByteBuffe)
Чтение/запись данных через SPI
public ByteBuffer write(ByteBuffer data) throws IOException;
Параметры:
data — байты для записи на устройство SPI
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(InputStream)
Чтение/запись данных через SPI
public byte[] write(InputStream input) throws IOException;
Параметры:
input — входной поток для чтения, чтобы получить байты для записи на устройство SPI
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(InputStream, OutputStream)
Чтение/запись данных через SPI
public int write(InputStream input, OutputStream output) throws IOException;
Параметры:
input — входной поток для чтения, чтобы получить байты для записи на устройство SPI
output — выходной поток для записи байтов, считанных с устройства SPI
Возвращает:
количество байтов считанных с устройства SPI и записываемых в выходной поток
Бросает:
java.io.IOException
write(byte[], int, int)
Чтение/запись данных через SPI
public byte[] write(byte[] data, int start, int length) throws IOException;
Параметры:
data — байты для записи на устройство SPI
start — стартовая позиция в буфере данных для начала записи
length — длина байтов для записи из буфера данных
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(byte …)
Чтение/запись данных через SPI
public byte[] write(byte ... data) throws IOException;
Параметры:
data — байты для записи на устройство SPI
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(short[], int, int)
Чтение/запись данных через SPI
public short[] write(short[] data, int start, int length) throws IOException;
Параметры:
data — байты для записи на устройство SPI
start — стартовая позиция в буфере данных для начала записи
length — длина байтов для записи из буфера данных
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
write(short …)
Чтение/запись данных через SPI
public short[] write(short ... data) throws IOException;
Параметры:
data — байты для записи на устройство SPI
Возвращает:
полученные байты, считанные с устройства SPI после операции записи
Бросает:
java.io.IOException
Перечисление SpiChannel
SPI каналы:
SpiChannel.CS0
SpiChannel.CS1
Перечисление SpiMode
Это режимы работы интерфейса SPI. Возможны четыре комбинации фазы (CPHA) и полярности (CPOL) сигнала SCLK по отношению к сигналам данных. Режимы работы определяются комбинацией бит CPHA и CPOL:
- CPOL = 0 — сигнал синхронизации начинается с низкого уровня;
- CPOL = 1 — сигнал синхронизации начинается с высокого уровня;
- CPHA = 0 — выборка данных производится по переднему фронту сигнала синхронизации;
- CPHA = 1 — выборка данных производится по заднему фронту сигнала синхронизации.
Для обозначения режимов работы интерфейса SPI принято следующее соглашение:
| Режим | Уровень сигнала (CPOL) | Фаза (CPHA) | SpiMode |
|---|---|---|---|
| 0 | 0 | 0 | SpiMode.MODE_0 |
| 1 | 0 | 1 | SpiMode.MODE_1 |
| 2 | 1 | 0 | SpiMode.MODE_2 |
| 3 | 1 | 1 | SpiMode.MODE_3 |
Включение аппаратного интерфейса SPI на Raspberry Pi
Raspberry Pi оснащён одной шиной SPI и двумя линиями CS или SS. Драйвер SPI по умолчанию отключен на Raspbian. Чтобы включить его, используйте raspi-config или убедитесь, что строка dtparam=spi=on не закомментирована в /boot/config.txt. Также нужно в файле /etc/modprobe.d/raspi-blacklist.conf закомментировать строку #blacklist spi-bcm2708, после чего нужно перезагрузить Raspberry Pi. Если драйвер SPI был загружен, вы должны увидеть устройство /dev/spidev0.0.
Подключение Orange Pi PC к Arduino по SPI
Для проверки работоспособности я взял Arduino Pro Mini 5V 16MHz и компьютер Orange Pi PC. Arduino будет в качестве ведомого устройства (Slave), а Orange Pi — ведущего (Master).
Схема подключения
Так как Arduino Pro Mini работает на 5 В, а Orange Pi на 3.3 В, соединить эти два устройства нужно через преобразователь логических уровней 5-3.3 В. Если у вас версия Arduino на 3.3 В, тогда можете подключить напрямую.
| Arduino | Преобразователь | Orange Pi (wPi) | |||
|---|---|---|---|---|---|
| SS | 10 | HV1 | LV1 | 10 | CE0 |
| MOSI | 11 | HV2 | LV2 | 12 | MOSI |
| VCC (5.0 В) | HV | LV | VCC (3.3 В) | ||
| GND | GND | GND | GND | ||
| MISO | 12 | HV3 | LV3 | 13 | MISO |
| SCK | 13 | HV4 | LV4 | 14 | SCLK |
Пример программы
Для проверки нужно написать две программы: одна для Arduino на C/C++, а вторая для Orange Pi на Java используя библиотеки Pi4J.
Arduino
Arduino получает по SPI данные от Orange Pi и добавляет их в буфер buf до тех пор, пока не получит новую строку '\n'. После этого флаг processIt устанавливается в true и данные отправляются по UART.
#include <SPI.h>
char buf [100];
volatile byte pos;
volatile boolean processIt;
void setup() {
/* отладка */
Serial.begin (115200);
/* необходимо отправить мастер в "slave выход" */
pinMode(MISO, OUTPUT);
/* включение SPI в режиме "slave" */
SPCR |= _BV(SPE);
/* готовность к прерыванию */
pos = 0; // buffer empty
processIt = false;
/* включение прерываний */
SPI.attachInterrupt();
Serial.println ("I'm in slave mode!");
}
/* Процедура прерывания SPI */
ISR (SPI_STC_vect) {
/* захват байта из регистра данных SPI */
byte c = SPDR;
/* добавление в буфер */
if (pos < sizeof buf) {
buf [pos++] = c;
/* новая строка означает время для обработки буфера */
if (c == '\n') {
processIt = true;
}
}
}
/* Основной цикл - ожидание установки флага в процедуре прерывания */
void loop (void) {
if (processIt) {
buf [pos] = 0;
Serial.print(buf);
pos = 0;
processIt = false;
}
}
Orange Pi PC
Orange Pi отправляет по SPI сообщение "Hello Arduino! I'm Orange Pi PC\n". Строка обязательно должна заканчиваться на '\n'.
import java.nio.charset.Charset;
import com.pi4j.io.spi.SpiChannel;
import com.pi4j.io.spi.SpiDevice;
import com.pi4j.io.spi.SpiFactory;
import com.pi4j.platform.Platform;
import com.pi4j.platform.PlatformManager;
public class SpiOrangePiArduino {
public static void main(String args[]) throws Exception {
PlatformManager.setPlatform(Platform.ORANGEPI);
SpiDevice spi = SpiFactory.getInstance(
SpiChannel.CS0,
SpiDevice.DEFAULT_SPI_SPEED,
SpiDevice.DEFAULT_SPI_MODE);
spi.write("Hello Arduino! I'm Orange Pi PC\n", Charset.defaultCharset());
}
}
Проверяем код:
- создаём java файл и вставляем код;
nano SpiOrangePiArduino.java
- компилируем файл;
javac -classpath .:classes:/opt/pi4j/lib/'*' SpiOrangePiArduino.java
- запускаем программу.
sudo java -classpath .:classes:/opt/pi4j/lib/'*' SpiOrangePiArduino
Результат
В мониторе порта мы сможем наблюдать строку «Hello Arduino! I’m Orange Pi PC».



