Применительно к платам Arduino Uno, Mega2560, Leonardo и аналогичным:
- Как работает SPI?
- Как быстро работает SPI?
- Как мне установить связь между хозяином и рабом?
- Как мне сделать SPI рабом?
Пожалуйста, обратите внимание: это задумано как справочный вопрос.
arduino-uno
arduino-mega
c++
arduino-leonardo
spi
Ник Гаммон
источник
источник
Ответы:
Введение в SPI
Интерфейс последовательной периферийной интерфейсной шины (SPI) используется для связи между несколькими устройствами на коротких расстояниях и с высокой скоростью.
Как правило, существует одно «главное» устройство, которое инициирует связь и снабжает часы, которые контролируют скорость передачи данных. Может быть один или несколько рабов. Для более чем одного ведомого, каждый имеет свой собственный сигнал выбора ведомого, описанный ниже.
Сигналы SPI
В полноценной системе SPI у вас будет четыре сигнальные линии:
Когда к ведомому сигналу MISO подключено несколько подчиненных устройств, ожидается, что они будут в трех состояниях (поддерживать на высоком импедансе) эту линию MISO до тех пор, пока они не будут выбраны с помощью выбора ведомого устройства. Обычно Slave Select (SS) понижается, чтобы утверждать это. То есть это активный низкий уровень. Как только конкретный ведомый выбран, он должен сконфигурировать линию MISO в качестве выхода, чтобы он мог отправлять данные ведущему устройству.
Это изображение показывает способ обмена данными при отправке одного байта:
Обратите внимание, что три сигнала являются выходами от мастера (MOSI, SCK, SS), а один является входом (MISO).
тайминг
Последовательность событий:
SS
идет низко, чтобы утвердить его и активировать рабаSCK
Линия переключается , чтобы указать , когда линии данных должны быть выбраныSCK
(используя фазу синхронизации по умолчанию)SCK
(используя фазу синхронизации по умолчанию), изменяяMISO
/MOSI
при необходимостиSS
идет высокий уровень, чтобы де-утверждать этоОбратите внимание, что:
Поскольку данные отправляются и принимаются с одним и тем же тактовым импульсом, ведомое устройство не может немедленно ответить ведущему. Протоколы SPI обычно ожидают, что мастер запросит данные за одну передачу и получит ответ о последующей.
Используя библиотеку SPI на Arduino, выполнение одной передачи выглядит так в коде:
Образец кода
Пример отправки только (игнорируя любые входящие данные):
Проводка только для выхода SPI
Приведенный выше код (только отправляющий) может использоваться для управления выходным последовательным регистром сдвига. Это устройства только для вывода, поэтому нам не нужно беспокоиться о поступающих данных. В их случае вывод SS можно назвать выводом «магазина» или «защелки».
Примерами этого являются последовательный сдвиговый регистр 74HC595 и различные светодиодные полосы, просто чтобы упомянуть пару. Например, этот 64-пиксельный светодиодный дисплей, управляемый чипом MAX7219:
В этом случае вы можете видеть, что производитель плат использовал несколько разные названия сигналов:
Большинство досок будут следовать аналогичной схеме. Иногда DIN это просто DI (Data In).
Вот еще один пример, на этот раз 7-сегментная плата светодиодного дисплея (также основанная на чипе MAX7219):
При этом используются те же имена сигналов, что и на другой плате. В обоих этих случаях вы можете видеть, что плате нужно только 5 проводов к ней, три для SPI, плюс питание и заземление.
Фаза и полярность часов
Существует четыре способа сэмплирования тактового сигнала SPI.
Протокол SPI позволяет изменять полярность тактовых импульсов. CPOL - это полярность часов, а CPHA - фаза часов.
Это показано на этом графике:
Вы должны обратиться к таблице данных для вашего устройства, чтобы получить правильную фазу и полярность. Обычно там будет диаграмма, которая показывает, как сэмплировать часы. Например, из таблицы для чипа 74HC595:
Как вы можете видеть, тактовая частота обычно низкая (CPOL = 0) и она дискретизируется по переднему фронту (CPHA = 0), поэтому это режим SPI 0.
Вы можете изменить полярность и фазу часов в коде следующим образом (конечно, выберите только один):
Этот метод не рекомендуется в версиях 1.6.0 и выше в Arduino IDE. Для последних версий вы меняете режим часов в
SPI.beginTransaction
вызове, например так:Порядок данных
По умолчанию сначала используется старший значащий бит, однако вы можете указать оборудованию сначала обработать младший бит следующим образом:
Опять же, это не рекомендуется в версиях 1.6.0 и более поздних версий Arduino IDE. Для последних версий вы меняете порядок битов в
SPI.beginTransaction
вызове, например так:скорость
По умолчанию для SPI используется системная тактовая частота, деленная на четыре, то есть один тактовый импульс SPI каждые 250 нс при условии тактовой частоты процессора 16 МГц. Вы можете изменить делитель часов, используя
setClockDivider
это:Где «делитель» является одним из:
Самая быстрая частота - это «деление на 2» или один тактовый импульс SPI каждые 125 нс, при условии тактовой частоты процессора 16 МГц. Поэтому для передачи одного байта потребуется 8 * 125 нс или 1 мкс.
Этот метод не рекомендуется в версиях 1.6.0 и выше в Arduino IDE. Для последних версий вы меняете скорость передачи в
SPI.beginTransaction
вызове, например так:Однако эмпирическое тестирование показывает, что необходимо иметь два тактовых импульса между байтами, поэтому максимальная частота, с которой байты могут быть тактированы, составляет 1,125 мкс каждый (с делителем тактовой частоты 2).
Подводя итог, можно сказать, что каждый байт может отправляться с максимальной скоростью один на 1,125 мкс (с тактовой частотой 16 МГц), обеспечивая теоретическую максимальную скорость передачи 1 / 1,125 мкс или 888 888 байт в секунду (исключая издержки, такие как установка низкого уровня SS и т. Д. на).
Подключение к Arduino
Arduino Uno
Подключение через цифровые контакты с 10 по 13:
Подключение через заголовок ICSP:
Arduino Atmega2560
Подключение через цифровые контакты от 50 до 52:
Вы также можете использовать заголовок ICSP, аналогично Uno выше.
Ардуино Леонардо
Леонардо и Микро не выставляют контакты SPI на цифровых выводах, в отличие от Uno и Mega. Единственный вариант - использовать контакты заголовка ICSP, как показано выше для Uno.
Несколько рабов
Мастер может общаться с несколькими ведомыми (но только по одному за раз). Он делает это, утверждая SS для одного раба и отменяя его для всех остальных. Ведомый, у которого установлен SS (обычно это означает НИЗКИЙ), настраивает свой вывод MISO как выходной, чтобы подчиненный и только один ведомый могли ответить ведущему. Другие ведомые устройства игнорируют любые входящие тактовые импульсы, если SS не утвержден. Таким образом, вам нужен один дополнительный сигнал для каждого ведомого, как это:
На этом рисунке вы можете видеть, что MISO, MOSI, SCK совместно используются обоими ведомыми, однако у каждого ведомого есть свой собственный сигнал SS (выбор ведомого).
протоколы
Спецификация SPI не определяет протоколы как таковые, поэтому решение о том, что означают данные, зависит от пары «главный / подчиненный». Хотя вы можете отправлять и получать байты одновременно, полученный байт не может быть прямым ответом на отправленный байт (так как они собираются одновременно).
Таким образом, было бы более логично для одного конца отправить запрос (например, 4 может означать «перечислить каталог диска»), а затем делать передачи (возможно, просто отправляя нули наружу), пока не получит полный ответ. Ответ может заканчиваться символом новой строки или символом 0x00.
Прочитайте таблицу данных для вашего ведомого устройства, чтобы увидеть, какие последовательности протоколов оно ожидает.
Как сделать SPI рабом
В предыдущем примере Arduino показывается как мастер, отправляющий данные на подчиненное устройство. Этот пример показывает, как Arduino может быть рабом.
Настройка оборудования
Соедините два Unix Arduino вместе со следующими контактами, соединенными друг с другом:
13 (SCK)
+ 5В (если требуется)
На Arduino Mega, штыри 50 (MISO), 51 (MOSI), 52 (SCK) и 53 (SS).
В любом случае MOSI на одном конце подключен к MOSI на другом, вы не меняете их местами (то есть у вас нет MOSI <-> MISO). Программное обеспечение конфигурирует один конец MOSI (ведущий конец) в качестве выхода, а другой конец (ведомый конец) в качестве входа.
Мастер пример
Раб пример
Раб полностью управляется прерываниями, поэтому он может делать другие вещи. Поступающие данные SPI собираются в буфере, и флаг устанавливается, когда поступает «значимый байт» (в данном случае символ новой строки). Это говорит о том, что ведомое устройство должно приступить к обработке данных.
Пример подключения мастера к подчиненному с использованием SPI
Как получить ответ от раба
Следуя приведенному выше коду, который отправляет данные от мастера SPI к ведомому устройству, в приведенном ниже примере показано, как отправить данные ведомому устройству, заставить его что-то с ним сделать и вернуть ответ.
Мастер похож на пример выше. Однако важным моментом является то, что нам нужно добавить небольшую задержку (около 20 микросекунд). В противном случае у ведомого не будет возможности отреагировать на поступающие данные и что-то с ними сделать.
Пример показывает отправку «команды». В этом случае «а» (добавить что-то) или «s» (вычесть что-то). Это должно показать, что раб фактически делает что-то с данными.
После утверждения выбора ведомого (SS), чтобы инициировать транзакцию, мастер отправляет команду, после которой следует любое количество байтов, а затем вызывает SS, чтобы завершить транзакцию.
Очень важным моментом является то, что ведомый не может ответить на входящий байт в тот же момент. Ответ должен быть в следующем байте. Это связано с тем, что отправляемые биты и принимаемые биты отправляются одновременно. Таким образом, чтобы добавить что-то к четырем числам, нам нужно пять передач, например:
Сначала мы запрашиваем действие по номеру 10. Но мы не получаем ответа до следующего перевода (тот, что на 17). Однако «а» будет установлен в ответ на 10. Наконец, мы в конечном итоге отправляем «фиктивный» номер 0, чтобы получить ответ для 42.
Мастер (пример)
Код для ведомого в основном делает почти все в подпрограмме прерывания (вызывается, когда поступают входящие данные SPI). Он принимает входящий байт и добавляет или вычитает в соответствии с запомненным «командным байтом». Обратите внимание, что ответ будет «собран» в следующий раз через цикл. Вот почему мастер должен отправить один окончательный «фиктивный» перевод, чтобы получить окончательный ответ.
В моем примере я использую основной цикл, чтобы просто определить, когда SS поднимается высоко, и очистить сохраненную команду. Таким образом, когда SS снова понижается для следующей транзакции, первый байт считается командным байтом.
Более надежно, это будет сделано с прерыванием. То есть вы бы физически подключили SS к одному из входов прерывания (например, на Uno, подключили контакт 10 (SS) к контакту 2 (вход прерывания) или использовали прерывание смены контактов на контакте 10.
Затем прерывание можно использовать, чтобы заметить, когда SS поднимается на низкое или высокое значение.
Раб (пример)
Пример вывода
Выход логического анализатора
Это показывает время между отправкой и получением в приведенном выше коде:
Новая функциональность в IDE 1.6.0 и выше
Версия IDE 1.6.0 в некоторой степени изменила способ работы SPI. Вы все еще должны сделать это
SPI.begin()
перед использованием SPI. Это настраивает оборудование SPI. Однако теперь, когда вы собираетесь начать общение с ведомым вы также сделать ,SPI.beginTransaction()
чтобы настроить SPI (для этого ВУ) с правильным:Когда вы закончите общаться с рабом, вы звоните
SPI.endTransaction()
. Например:Зачем использовать SPI?
Это отличный вопрос. Мои ответы:
Оба метода имеют свое место. I 2 C позволяет подключать множество устройств к одной шине (два провода плюс заземление), так что это будет предпочтительным выбором, если вам необходимо опросить значительное количество устройств, возможно, довольно редко. Однако скорость SPI может быть более релевантной для ситуаций, когда вам нужно быстро выводить (например, светодиодная лента) или вводить быстро (например, АЦП).
Ссылки
Моя страница о SPI - также содержит подробную информацию о SPI с побитовой передачей и использовании USART для получения второго аппаратного SPI на чипе Atmega328.
Шина последовательного периферийного интерфейса - Википедия
Справочные страницы библиотеки Arduino SPI
Документация SPI в PJRC
Протокол SPI - Sparkfun
источник
Are you going to cover the weirdness that is the Due's SPI?
- Я ничего не знаю о SPI Due (кроме предположения, что общий протокол тот же). Вы можете добавить ответ, охватывающий этот аспект.