Библиотека SPI позволяет Ардуино взаимодействовать с различными SPI-устройствами, выступая при этом в роли ведущего устройства.

Краткое введение в интерфейс SPI (Serial Peripheral Interface)

Последовательный периферийный интерфейс (SPI) - это синхронный протокол последовательной передачи данных, используемый для связи микроконтроллера с одним или несколькими периферийными устройствами. Интерфейс SPI отличается относительно высокой скоростью и предназначен для связи близко расположенных устройств. Он также может использоваться для взаимодействия двух микроконтроллеров.

Согласно протоколу SPI, одно из взаимодействующих устройств (обычно микроконтроллер) всегда является ведущим и контролирует ведомые периферийные устройства. Как правило, все взаимодействющие устройства объединены тремя общими линиями:

  • MISO (Master In Slave Out) - линия для передачи данных от ведомого устройства (Slave) к ведущему (Master),
  • MOSI (Master Out Slave In) - линия для передачи данных от ведущего устройства (Master) к ведомым (Slave),
  • SCK (Serial Clock) - тактовые импульсы, генерируемые ведущим устройством (Master) для синхронизации процесса передачи данных.

Помимо перечисленных, на каждое устройство отводится отдельная линия:

  • SS (Slave Select) - вывод, присутствующий на каждом ведомом устройстве. Он предназначен для активизации Мастером того или иного периферийного устройства.

Периферийное устройство (Slave) взаимодействует с ведущим (Master) тогда, когда на выводе SS присутствует низкий уровень сигнала. В противном случае данные от Master-устройства будут игнорироваться. Такая архитектура позволяет взаимодействовать с несколькими SPI-устройствами, подключенными к одной и той же шине: MISO, MOSI и SCK.

Перед тем, как отправлять данные новому SPI-устройству, необходимо выяснить о нем несколько основных моментов:

  • Сдвиг данных должен осуществляться, начиная со старшего бита (MSB) или с младшего бита (LSB)? Порядок следования данных контролируется функцией SPI.setBitOrder().
  • При отсутствии тактовых импульсов линия SCK должна находиться в высоком или низком уровне? Считывание данных происходит по фронту или по спаду тактового импульса? Эти режимы работы контролируются функцией SPI.setDataMode().
  • Какова должна быть скорость передачи данных по SPI? Этот параметр контролируется функцией SPI.setClockDivider().

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

Грубо говоря, существует четыре режима передачи данных, отличающиеся условием сдвига данных (по фронту или по спаду синхро-импульсов - так называемая фаза), а также уровнем сигнала, в котором должна находится линия SCK при отсутствии синхро-импульсов (полярность). Различные комбинации фазы и полярности, формирующие четыре режима передачи данных, сведены в таблицу:

Режим Полярность (CPOL) Фаза (CPHA)
SPI_MODE0 0 0
SPI_MODE1 0 1
SPI_MODE2 1 0
SPI_MODE3 1 1

Для изменения режима передачи данных служит функция SPI.setDataMode().

Каждое SPI-устройство налагает определенные ограничения на максимальную скорость SPI-шины. Для корректной работы периферийных устройств в библиотеке предусмотрена функция SPI.setClockDivider(), позволяющая изменять тактовую частоту шины (по умолчанию 4 МГц).

После правильной настройки всех параметров SPI, останется только выяснить, какие регистры периферийного устройства отвечают за те или иные его функции. Как правило, это описано в даташите устройства.

Для получения дополнительной информации об интерфейсе SPI, см. страницу Википедии.

Соединения

Ниже в таблице приведены номера выводов, использующиеся шиной SPI в тех или иных моделях Ардуино:

Плата Arduino MOSI MISO SCK SS (slave) SS (master)
Uno или Duemilanove 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3 10 -
Mega1280 или Mega2560 51 или ICSP-4 50 или ICSP-1 52 или ICSP-3 53 -
Leonardo ICSP-4 ICSP-1 ICSP-3 - -
Due ICSP-4 ICSP-1 ICSP-3 - 4, 10, 52

Обратите внимание, что на всех платах выводы MISO, MOSI и SCK соединены с одними и теми же контактами разъема ICSP. Такое расположение может быть удобно при создании универсальных плат расширения, работающих на всех моделях Ардуино.

Особенности работы вывода SS в Ардуино на базе AVR

У всех моделей Ардуино на основе микроконтроллеров AVR есть вывод SS, который используется в режиме работы Slave (например, при управлении Ардуино внешним ведущим устройством). Однако, в библиотеке реализован только режим работы Master, поэтому в этом режиме вывод SS должен быть сконфигурирован как выход. В противном случае SPI может аппаратно переключиться в режим Slave, что приведет к неработоспособности функций библиотеки.

Для управления выводом SS периферийных устройств можно использовать любой из доступных выводов. Например, на плате расширения Arduino Ethernet для взаимодействия со встроенной SD-картой и контроллером Ethernet по SPI используются выводы 4 и 10 соответственно.

Расширенные возможности SPI на Arduino Due

Существуют некоторые особенности работы с интерфейсом SPI на платах Arduino Due. Помимо основных функций и методов, применимых ко всем платам Ардуино, в библиотеке SPI предусмотрено несколько дополнительных методов. Эти методы реализовывают аппаратные возможности микроконтроллеров SAM3X и предоставляют разработчику расширенные возможности:

  • автоматический управление процессом выбора ведомого устройства;
  • автоматическое управление конфигурациями интерфейса SPI для различных устройств (тактовая частота, режим передачи данных и т.д.). Благодаря этому каждое из ведомых устройств может иметь собственный набор настроек, автоматически применяемых в начале передачи.

В Arduino Due есть три отдельных вывода (4, 10 и 52) для управления линиями SS периферийных устройств.

Функции

  • begin()
  • end()
  • setBitOrder()
  • setClockDivider()
  • setDataMode()
  • transfer()

Примеры

  • BarometricPressureSensor: Считывание показаний датчика об атмосферном давлении и температуре через SPI
  • SPIDigitalPot: Управление цифровым потенциометром через SPI

Смотрите также

Использование расширенных возможностей SPI на Arduino Due

Микроконтроллер SAM3X на Arduino Due предоставляет разработчику расширенные возможности по работе с интерфейсом SPI.

При этом можно использовать как расширенное API, так и традиционный подходы, характерные платам на базе AVR-микроконтроллеров.

Расширенное API в качестве линий CS позволяет использовать выводы 4, 10 и 52.

Как пользоваться?

Вначале необходимо указать выводы, которые будут использоваться в качестве линий CS для каждого SPI-устройства.

Arduino Due может автоматически управлять этими выводами, распределяя доступ к шине SPI между ведомыми устройствами. При этом каждое устройство может иметь индивидуальные настройки SPI-интерфейса, такие, как режим работы и скорость передачи данных.

Таким образом, для управления несколькими ведомыми устройствами необходимо объявить соответствующие им выводы CS в функции setup(). Ниже показан пример работы с двумя устройствами, расположенными на одной SPI-шине. Вывод CS одного устройства подключен к выводу 4, другого - к выводу 10.

void setup(){
  // инициализируем шину для устройства, подключенного к выводу 4
  SPI.begin(4);
  // инициализируем шину для устройства, подключенного к выводу 10
  SPI.begin(10);
}

После объявления выводов CS, каждому ведомому устройству можно задать индивидуальные настройки интерфейса SPI. Например, если устройства работают на разной тактовой частоте, функция setup() будет выглядеть следующим образом:

void setup(){
  // инициализируем шину для устройства, подключенного к выводу 4
  SPI.begin(4);
  // устанавливаем для этого устройства коэффициент деления тактовой частоты 21
  SPI.setClockDivider(4, 21); 
  // инициализируем шину для устройства, подключенного к выводу 10
  SPI.begin(10);
  // устанавливаем для этого устройства коэффициент деления тактовой частоты 84
  SPI.setClockDivider(10, 84);
}

Простая передача байта ведомому устройству, подключенному к выводу 4, будет выглядеть так:

void loop(){
  byte response = SPI.transfer(4, 0xFF);
}

В результате выполнения этого кода, значение "0xFF" будет отправлено SPI-устройству, подключенному к выводу 4, а ответные данные, пришедшие от устройства по линии MISO, будут помещены в переменную response. Управление линией CS осуществляется контроллером интерфейса SPI автоматически. Таким образом, команда transfer выполняет следующие операции:

  • активизирует ведомое устройство, формируя на выводе 4 низкий уровень сигнала (LOW)
  • отправляет значение 0xFF по шине SPI и возвращает полученный байт
  • отключает ведомое устройство от шины SPI, формируя на выводе 4 высокий уровень сигнала (HIGH)

Также возможна отправка нескольких байт за одну транзакцию. Для этого команде transfer необходимо указать параметр, который заставит ее не отключать ведомое устройство после передачи байта:

void loop(){
//передаем 0x0F устройству, подключенному к выводу 10, оставляя его активным
SPI.transfer(10, 0xF0, SPI_CONTINUE);
 
//передаем 0x00 устройству, подключенному к выводу 10, оставляя его активным
SPI.transfer(10, 0x00, SPI_CONTINUE);
 
//передаем 0x00 устройству, подключенному к выводу 10, и сохраняем полученный
//байт в переменной response1. По прежнему оставляем устройство активным
byte response1 = SPI.transfer(10, 0x00, SPI_CONTINUE);
 
//передаем 0x00 устройству, подключенному к выводу 10, и сохраняем полученный
//байт в переменной response2, отключая устройство.
byte response2 = SPI.transfer(10, 0x00);
}

Параметр SPI_CONTINUE заставляет ведомое устройство быть активным между передачами. При передаче последнего байта этот параметр не указывается.

См. справку по функциям setClockDivider(), setDataMode(), transfer(), setBitOrder() для получения дополнительной информации об их синтаксисе при использовании расширенного API.

Примечание: после вызова функции SPI.begin(), вывод, переданный ей в качестве параметра, нельзя использовать в качестве вывода общего назначения.