Перейти к основному содержимому

SPI

Робот подключает дисплей, память и радиомодуль по SPI

SPI используют там, где нужно быстро передавать много данных на небольшом расстоянии: дисплеи, SD-карты, flash-память, радиомодули, быстрые датчики. Контроллер задаёт такт, выбирает устройство и передаёт байты.

Коротко

В классическом SPI есть SCK для такта, MOSI для данных от контроллера к модулю, MISO для данных от модуля к контроллеру и CS для выбора конкретного устройства. Общий GND обязателен. Если устройств несколько, каждому обычно нужен свой CS.

SPI между контроллером и периферией: SCK, MOSI, MISO, CS и GND подписаны по назначению

Зачем это нужно

Роботу может понадобиться быстро обновлять экран, читать память или получать данные от IMU. I2C часто удобнее для простых датчиков, но SPI лучше подходит для больших блоков данных и высокой частоты обмена на коротких проводах.

SPI сам по себе не говорит, что означает команда. Один дисплей ждёт поток пикселей, память ждёт команду и адрес, а датчик ждёт номер регистра. Поэтому после подключения линий всегда читают документацию конкретного модуля.

Главная идея

Контроллер активирует CS нужного устройства и начинает выдавать импульсы SCK. На каждом такте один бит уходит по MOSI, а другой может возвращаться по MISO.

Если контроллер хочет прочитать данные, он всё равно должен продолжать передавать такты. Часто для этого по MOSI отправляют фиктивные байты-заполнители.

Провода и сигналы

ЛинияНаправлениеЗачем нужна
SCKконтроллер → устройствотактовые импульсы
MOSIконтроллер → устройствокоманды, адреса, передаваемые данные
MISOустройство → контроллерответ, статус, читаемые данные
CS или SSконтроллер → устройствовыбор устройства для текущей транзакции
GNDобщий проводобщий ноль
VCCпитание модулянапряжение зависит от модуля

В новых текстах вместо MOSI/MISO иногда пишут COPI/CIPO, но в Arduino-библиотеках и на большинстве модулей чаще встречаются старые обозначения. Для работы важно не название, а направление сигнала.

Где находятся пины

ПлатаSPI-пиныКомментарий
Arduino UnoD13/SCK, D11/MOSI, D12/MISO, D10/SSлинии также есть на разъёме ICSP
Arduino NanoD13/SCK, D11/MOSI, D12/MISO, D10/SSрасположение другое, номера похожи на Uno
Arduino MegaD52/SCK, D51/MOSI, D50/MISO, D53/SSне совпадает с Uno
ESP32 DevKitчасто VSPI: GPIO18/SCK, GPIO23/MOSI, GPIO19/MISO, GPIO5/SSArduino-ESP32 позволяет задавать другие пины
ESP8266обычно аппаратный SPI занят flash-памятью; для внешних модулей используют доступные SPI-пины платызависит от конкретной платы

Пин CS можно выбрать почти любым свободным цифровым выводом, если библиотека модуля это поддерживает. Но аппаратный SS на некоторых микроконтроллерах влияет на режим SPI, поэтому его поведение проверяют отдельно.

Подключение устройства к Arduino Uno: TFT-дисплей

TFT-дисплей подключён к Arduino Uno по SPI

Контакт TFT-модуляArduino UnoЗачем
SCKD13такт SPI
DIN, SDA или MOSID11/MOSIданные к дисплею
SDO или MISO, если естьD12/MISOчтение ответа от дисплея
CSD10выбор дисплея
GNDGNDобщий ноль
VCCпо документации модулячасто дисплей требует 3,3 В логики

У многих TFT-дисплеев есть дополнительные выводы DC или A0 и RST. Они не являются базовыми линиями SPI, но нужны конкретному дисплею: DC различает команду и данные, RST сбрасывает контроллер дисплея.

Несколько устройств на одной SPI-шине

Несколько SPI-устройств на одной шине

SCK, MOSI и MISO можно сделать общими для нескольких устройств, но CS обычно отдельный для каждого:

ЛинияДисплейПамятьIMU
SCKобщийобщийобщий
MOSIобщийобщийобщий
MISOобщий, если используетсяобщийобщий
CSсвой пинсвой пинсвой пин

Перед транзакцией контроллер активирует только один CS. Невыбранные устройства должны отпускать линию MISO. Если модуль этого не делает, несколько устройств начнут одновременно управлять одним проводом.

Пример с несколькими Arduino

Две Arduino соединены по SPI

Две Arduino Uno можно соединить так, чтобы одна была контроллером SPI, а другая отвечала как периферия.

Arduino-контроллерArduino-периферия
D13/SCKD13/SCK
D11/MOSID11/MOSI
D12/MISOD12/MISO
D10/SSD10/SS
GNDGND

Здесь линии не «перекрещивают» по названию, как в UART. Современные обозначения COPI и CIPO прямо показывают направление: от контроллера к периферии и обратно. В старой документации им обычно соответствуют названия MOSI и MISO. Роль платы определяет направление.

Минимальная идея для платы-контроллера:

#include <SPI.h>

const byte DEVICE_SELECT = 10;

void setup() {
SPI.begin();
pinMode(DEVICE_SELECT, OUTPUT);
digitalWrite(DEVICE_SELECT, HIGH);
}

void loop() {
digitalWrite(DEVICE_SELECT, LOW);
byte answer = SPI.transfer(0x55);
digitalWrite(DEVICE_SELECT, HIGH);
delay(1000);
}

Скетч платы-периферии сложнее, потому что нужно правильно обслуживать аппаратный SPI и момент выбора SS. Для первого знакомства достаточно собрать схему, увидеть такт SCK и байт 0x55 на логическом анализаторе.

Режимы SPI

У SPI есть четыре режима, которые задают положение такта относительно данных:

РежимCPOLCPHAЧто меняется
MODE000такт в покое низкий, выборка на первом фронте
MODE101такт в покое низкий, выборка на втором фронте
MODE210такт в покое высокий, выборка на первом фронте
MODE311такт в покое высокий, выборка на втором фронте

Если режим выбран неверно, байты могут выглядеть почти правильными, но быть сдвинутыми. Режим, максимальную частоту и порядок битов берут из datasheet устройства.

Частые ошибки

ОшибкаЧто произойдёт
забыли GNDуровни не имеют общего отсчёта
перепутали MOSI и MISOустройство не получает команду или контроллер не видит ответ
не управляют CSмодуль не понимает границы команды
выбрали неверный CPOL/CPHAбайты читаются со сдвигом
подали 5 В на 3,3-вольтовый модульможно повредить входы
сделали длинные провода на высокой частотепоявляются искажения и ошибки

Что запомнить про SPI

  • SPI использует отдельный такт SCK.
  • MOSI идёт от контроллера к устройству, MISO — обратно.
  • Каждому устройству обычно нужен свой CS.
  • Для чтения контроллер всё равно должен выдавать такт.
  • Режим SPI и частоту выбирают по datasheet конкретного модуля.

Практика

  1. Найдите на Arduino Uno пины D13, D11, D12, D10.
  2. Нарисуйте подключение TFT-дисплея и подпишите все провода.
  3. Добавьте на схему второй SPI-модуль и отдельный CS.
  4. Снимите логическим анализатором SCK, MOSI, MISO и CS.

Проверьте себя

  1. Чем SPI отличается от UART по тактированию?
  2. Почему у нескольких SPI-устройств обычно разные CS?
  3. В каких направлениях передают данные COPI и CIPO и как эти линии называются в старых обозначениях?
  4. Почему чтение по SPI требует передачи байтов-заполнителей?
Ориентиры для самопроверки

Сначала ответьте без подсказки. Ответ можно считать полным, если вы:

  • формулируете основную мысль своими словами;
  • называете важные условия, ограничения или меры безопасности;
  • для схемы, кода или расчёта показываете ход решения и ожидаемый результат.

Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.

Словарь статьи

  • SPI — синхронный интерфейс с общей линией такта и отдельным выбором периферии.
  • SCK — тактовый сигнал от контроллера.
  • COPI — данные от контроллера к периферийному устройству; старое обозначение — MOSI.
  • CIPO — данные от периферийного устройства к контроллеру; старое обозначение — MISO.
  • CS/SS — сигнал выбора конкретного периферийного устройства.
  • CPOL/CPHA — параметры уровня покоя такта и фронта выборки данных.

Связанные темы

  • UART — асинхронная связь без отдельного такта.
  • I2C — адресная шина с двумя сигнальными линиями.
  • 1-Wire — одна линия данных и ROM-коды.
  • Сравнение протоколов — как выбирать интерфейс.
  • Отладка обмена — как проверять режим, уровни и сигналы.

Источники