Raspberry Pi и Pi4J. Урок 6. Последовательный периферийный интерфейс — SPI

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 (SPI bus timing)

Включение аппаратного интерфейса 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 pinout (распиновка)Orange Pi (H3 Soc) GPIO - pinout

Схема подключения

Так как 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

Raspberry Pi и Pi4J. Урок 6. SPI - Подключение Orange Pi One к Arduino по SPI

Пример программы

Для проверки нужно написать две программы: одна для 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());
  }
}

Проверяем код:

  1. создаём java файл и вставляем код;
    nano SpiOrangePiArduino.java
  2. компилируем файл;
    javac -classpath .:classes:/opt/pi4j/lib/'*' SpiOrangePiArduino.java
  3. запускаем программу.
    sudo java -classpath .:classes:/opt/pi4j/lib/'*' SpiOrangePiArduino

Результат

Raspberry Pi и Pi4J. Урок 6. SPI - Результат отправки сообщения с Orange Pi One на Arduino по SPIВ мониторе порта мы сможем наблюдать строку «Hello Arduino! I’m Orange Pi PC».

Похожие записи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *