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».