Arduino и Serial Peripheral Interface (SPI)
Serial Peripheral Interface (SPI) — это синхронный последовательный протокол передачи данных, используемый микроконтроллерами для быстрой связи с одним или несколькими периферийными устройствами на коротких расстояниях.
Примечание
Эта статья была пересмотрена 18.11.2021 Карлом Сёдербю (Karl Söderby).
Важно
Терминология Controller/Peripheral ранее называлась master/slave. Arduino больше не поддерживает использование этой терминологии. См. таблицу ниже, чтобы понять новую терминологию:
Master/Slave (СТАРОЕ) |
Controller/Peripheral (НОВОЕ) |
|---|---|
Master In Slave Out (MISO) |
Controller In, Peripheral Out (CIPO) |
Master Out Slave In (MOSI) |
Controller Out Peripheral In (COPI) |
Slave Select pin (SS) |
Chip Select Pin (CS) |
Библиотека SPI
Библиотека SPI включена в каждое ядро/платформу Arduino, поэтому её не нужно устанавливать отдельно. Подробнее о функциях SPI можно прочитать по ссылкам ниже:
Serial Peripheral Interface (SPI)
При SPI-соединении всегда есть одно устройство-Контроллер (обычно микроконтроллер), которое управляет периферийными устройствами. Как правило, существуют три линии, общие для всех устройств:
CIPO (Controller In Peripheral Out) — линия Периферии для отправки данных Контроллеру
COPI (Controller Out Peripheral In) — линия Контроллера для отправки данных периферийным устройствам
SCK (Serial Clock) — тактовые импульсы, которые синхронизируют передачу данных, генерируемые Контроллером
и одна линия, специфичная для каждого устройства:
CS (Chip Select) — пин на каждом устройстве, который Контроллер может использовать для включения и отключения конкретных устройств.
Когда пин Chip Select устройства имеет низкий уровень, оно общается с Контроллером. Когда уровень высокий — оно игнорирует Контроллер. Это позволяет иметь несколько SPI-устройств, использующих общие линии CIPO, COPI и SCK.
Чтобы написать код для нового SPI-устройства, нужно учесть несколько моментов:
Какова максимальная скорость SPI, которую может использовать ваше устройство? Это контролируется первым параметром в SPISettings. Если вы используете чип, рассчитанный на 15 МГц, используйте значение 15000000. Arduino автоматически выберет наилучшую скорость, равную или меньшую указанному значению в SPISettings.
Сдвигаются ли данные первым старшим битом (Most Significant Bit, MSB) или младшим битом (Least Significant Bit, LSB)? Это контролируется вторым параметром SPISettings: либо
MSBFIRST, либоLSBFIRST. Большинство чипов SPI используют порядок данных MSB first.Находится ли тактовый сигнал данных в покое в высоком или низком состоянии? Происходит ли выборка по нарастающему или спадающему фронту тактовых импульсов? Эти режимы контролируются третьим параметром в SPISettings.
Стандарт SPI довольно свободный, и каждое устройство реализует его немного по-своему. Это означает, что нужно особенно внимательно изучать datasheet устройства при написании кода.
Вообще говоря, существует четыре режима передачи. Эти режимы определяют, сдвигаются ли данные на нарастающем или спадающем фронте тактового сигнала (это называется фазой тактирования, clock phase), и находится ли тактовый сигнал в покое в высоком или низком состоянии (это называется полярностью тактирования, clock polarity). Четыре режима комбинируют полярность и фазу согласно этой таблице:
Режим |
Полярность тактирования (CPOL) |
Фаза тактирования (CPHA) |
Фронт вывода |
Захват данных |
|---|---|---|---|---|
SPI_MODE0 |
0 |
0 |
Спадающий |
Нарастающий |
SPI_MODE1 |
0 |
1 |
Нарастающий |
Спадающий |
SPI_MODE2 |
1 |
0 |
Нарастающий |
Спадающий |
SPI_MODE3 |
1 |
1 |
Спадающий |
Нарастающий |
Получив параметры SPI, используйте
SPI.beginTransaction()
чтобы начать использование порта SPI. Порт SPI будет настроен со всеми вашими параметрами. Самый простой и эффективный способ использования SPISettings — прямо внутри
SPI.beginTransaction()
Например:
SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
Если другие библиотеки используют SPI из прерываний, им будет запрещён доступ к SPI до тех пор, пока вы не вызовете
SPI.endTransaction()
Настройки SPI применяются в начале транзакции, и
SPI.endTransaction()
не изменяет настройки SPI. Если вы (или какая-то библиотека) не вызовете beginTransaction второй раз, настройки сохраняются. Следует стараться минимизировать время до вызова
SPI.endTransaction()
для лучшей совместимости, если ваша программа используется вместе с другими библиотеками, которые работают с SPI.
С большинством SPI-устройств после
SPI.beginTransaction()
вы устанавливаете пин Chip Select в LOW, вызываете
SPI.transfer()
любое количество раз для передачи данных, затем устанавливаете пин CS в HIGH и, наконец, вызываете
SPI.endTransaction()
Совет
Подробнее об SPI см. страницу SPI на Wikipedia.