SPI(Serial Peripheral Bus) — последовательный периферийный протокол обмена. Этот прокол был разработан компанией Motorola, но в настоящее время используется многими производителями. Он предназначен для связи микроконтроллеров между собой, а также со всевозможной периферией: датчиками, AЦП, микросхемами памяти, часами.
Но все же наиболее частое применение SPI – это запись программы в память микроконтроллера. В микроконтроллерах AVR c помощью SPI можно прошить микроконтроллер не выпаивая из платы, такой способ прошивки называется ISP(In System Programming ). Хотя названия SPI и ISP очень созвучны, это не одно и то же, в AVR SPI используется как физический уровень ISP, то есть используются линии SPI для передачи данных, но сам протокол(программный уровень) отличается.
Для передачи данных в SPI используется три линии:
MISO(Master Input Slave Output) – по этой линии Master(ведущий) принимает данные от Slave(ведомого).
MOSI(Master Output Slave Input) – по этой линии Master отправляет данные Slave.
AVR 38# Последовательный интерфейс SPI
SCK(Serial Clock ) – служит для передачи тактового сигнала ведомому устройству.
Также используется линия SS(Slave Select), которая определяет устройство с которым Master будет обмениваться данными.
По причине того, что многие производители в своих устройствах используют SPI, названия выводов могут несколько отличаться. Ниже приведена таблица с альтернативными названиями.
SPI бывает двух видов аппаратный и программный. При реализации программного SPI, мы вручную должны устанавливать сигнал на ножках соответствующих MISO, MOSI, SS при этом дёргать за SCK. При аппаратной реализации SPI мы передаём данные в специальный регистр, а микроконтроллер сам проделывает вышеописанные манипуляции, по предварительным настройкам.
Физическая реализацию SPI, представляет собой два соединённых вместе сдвиговых регистра.
В зависимости от того по какому логическому уровню сигнала SCK, происходит синхронизация Master и Slave и по какому фронту происходит захват и сдвиг данных, возможны 4 режима SPI.
- CPOL = 0 — сигнал синхронизации начинается с низкого уровня;
- CPOL = 1 — сигнал синхронизации начинается с высокого уровня;
- CPHA = 0 — выборка данных производится по переднему фронту сигнала синхронизации;
- CPHA = 1 — выборка данных производится по заднему фронту сигнала синхронизации.
Видеоуроки по Arduino. Интерфейсы SPI (8-я серия, ч1)
CPOL = 1 CPHA = 0
CPOL = 0 CPHA = 1
CPOL = 1 CPHA = 1
SPI — синхронный интерфейс, то есть для того чтобы получить какие-нибудь данные от Slave, Master должен что-нибудь отправить. Вроде всё понятно, но что если Master отправляет один байт, а Slave должен вернуть ему два? В таком случае Master должен отправить ему что-нибудь 2 раза, например 0х00.
//отправляем команду, в ответ должно прийти два байта Spi_Master_Transmit(chx); //отправляем что-нибудь для того чтобы принять первый байт Spi_Master_Transmit(0X00); touch_x = SPDR; touch_x >= 3;
Источник: hubstub.ru
Использование SPI в высокоуровневом приложении
Azure Sphere поддерживает последовательный периферийный интерфейс (SPI) в главном режиме. SPI — это последовательный интерфейс, используемый для обмена данными между периферийными устройствами и интегрированными каналами. SPI использует главную или подчиненную модель, в которой основное устройство управляет набором подчиненных устройств. В отличие от I2C, SPI можно использовать с более сложными периферийными устройствами с более высокой скоростью.
Приложения могут получать доступ к периферийным устройствам через SPI, вызывая API-интерфейсы Applibs SPI для выполнения операций с главным интерфейсом SPI. В примере SPI LSM6DS3 описывается настройка оборудования для SPI на устройстве MT3620 и использование SPI в приложении.
Выбор микросхемы
Выбор микросхемы управляет подключением между главным интерфейсом SPI и набором подчиненных устройств; и позволяет главному интерфейсу отправлять и получать данные на каждое подчиненное устройство независимо друг от друга. Azure Sphere поддерживает параметры «активный — низкий» и «активный — высокий» для выбора микросхемы с активным и низким значением по умолчанию. Каждый главный интерфейс SPI может использоваться только одним приложением. Перед выполнением операций чтения и записи в интерфейсе приложение должно открыть главный интерфейс SPI и определить каждое подключенное подчиненное устройство. Операции чтения и записи SPI в Azure Sphere используют блокирующие API.
Требования SPI
Приложения, использующие SPI, должны включать соответствующие файлы заголовков для SPI и добавлять параметры SPI в манифест приложения.
Все приложения должны задать целевое оборудование и включить соответствующий файл заголовка определения оборудования.
Файлы заголовков
#define SPI_STRUCTS_VERSION 1 #include #include «path-to-your-target-hardware.h»
Объявите SPI_STRUCTS_VERSION определение препроцессора перед включением файла заголовка. Указывает версию структуры, используемую приложением.
Замените path-to-your-target-hardware.h путем к файлу заголовка для оборудования.
Параметры манифеста приложения
Чтобы использовать API SPI, SpiMaster необходимо добавить эту возможность в манифест приложения, а затем добавить в нее каждый главный контроллер SPI. Это позволяет приложению получить доступ к контроллеру. Манифест приложения Azure Sphere содержит дополнительные сведения о манифесте приложения.
В коде используйте константы, определенные для оборудования, для идентификации главных интерфейсов SPI. Компилятор преобразует эти значения в необработанные значения при сборке приложения.
Например, ниже приведен фрагмент манифеста приложения, который предназначен для эталонной платы разработки MT3620 (RDB) и настраивает два главных интерфейса SPI:
«SpiMaster»: [ «$MT3620_RDB_HEADER2_ISU0_SPI», «$MT3620_RDB_HEADER4_ISU1_SPI» ],
В следующем фрагменте показано, как указать те же главные интерфейсы SPI в приложении, предназначенном для начального набора Avnet MT3620:
«SpiMaster»: [ «$AVNET_MT3620_SK_ISU0_SPI», «$AVNET_MT3620_SK_ISU1_SPI» ]
Настройка выбора микросхемы и открытие главного интерфейса SPI
Перед выполнением операций с главным интерфейсом SPI необходимо настроить выбор микросхемы и открыть интерфейс. Чтобы настроить выбор микросхемы, вызовите функцию SPIMaster_InitConfig для инициализации SPIMaster_Config структуры. После инициализации SPIMaster_Config обновите csPolarity поле, указав SPI_ChipSelectPolarity_ActiveLow или SPI_ChipSelectPolarity_ActiveHigh.
Чтобы открыть главный интерфейс SPI, вызовите функцию SPIMaster_Open . При этом к интерфейсу будут применены параметры по умолчанию и параметры выбора микросхемы:
- SPI_Mode_0 для битового порядка SPI
- SPI_BitOrder_MsbFirst для режима связи
Обновление параметров главного интерфейса SPI
После инициализации можно изменить параметры интерфейса:
- Чтобы изменить разрядный порядок, вызовите SPIMaster_SetBitOrder
- Чтобы изменить скорость шины SPI, вызовите SPIMaster_SetBusSpeed
- Чтобы изменить режим связи, вызовите SPIMaster_SetMode
Выполнение операций чтения и записи в главном интерфейсе SPI
Azure Sphere поддерживает несколько вариантов выполнения операций чтения и записи с помощью SPI. Для односторонних операций чтения и записи, а также для поддержания взаимодействия с некоторыми API POSIX можно вызывать функции POSIX read(2) и write(2).
Вы можете вызвать функцию SPIMaster_WriteThenRead для выполнения объединенной операции записи и чтения в одной транзакции шины без прерывания выполнения другой транзакции.
Вызовите функцию SPIMaster_TransferSequential , если требуется более точный контроль над временем между операциями чтения или записи. Это позволяет выполнять несколько операций чтения и записи между парой состояний включения и отключения CS.
Закрытие интерфейса SPI
Чтобы закрыть интерфейс, вызовите стандартную функцию POSIX close().
Поддержка MT3620
В этом разделе описываются параметры SPI, которые применяются только при запуске Azure Sphere на плате разработки MT3620.
Спецификации SPI для MT3620 перечислены в разделе «Состояние поддержки MT3620». В руководстве пользователя по плате разработки MT3620 описывается макет контактов и функции для подключения.
Папка HardwareDefinitions в каталоге установки пакета SDK microsoft Azure Sphere содержит определения общих до плат разработки, модулей и микросхем Azure Sphere. Он содержит файлы заголовков и JSON, которые определяют главные интерфейсы для MT3620, MT3620 RDB, а также другое оборудование MT3620. По умолчанию папка HardwareDefinitions находится в C:Program Files (x86)Microsoft Azure Sphere SDKHardware Definitions Windows и /opt/azurespheresdk/HardwareDefinitions Linux.
- При настройке платы разработки MT3620 в качестве главного интерфейса SPI можно использовать любой порт ISU . К каждому ISU можно подключить до двух подчиненных устройств. При использовании порта ISU в качестве главного интерфейса SPI нельзя использовать тот же порт, что и интерфейс I2C или UART.
- MT3620 поддерживает транзакции SPI с частотой до 40 МГц.
- MT3620 не поддерживает одновременные двунаправленные операции чтения и записи (полнодуплексный) SPI в рамках одной транзакции шины.
Источник: learn.microsoft.com
Интерфейс SPI и Arduino


Интерфейс SPI предусматривает несколько вариантов подключения ведомых устройств: независимое и каскадное. При независимом подключении к шине SPI ведущее устройство обращается к каждому ведомому устройству индивидуально. При каскадном подключении ведомые устройства срабатывают поочерёдно, как бы каскадом.
2 Реализация интерфейса SPI на платах семейства Arduino
В Arduino шины интерфейса SPI находятся на определённых портах. У каждой платы своё соответствие выводов. Для удобства выводы продублированы и вынесены также на отдельный разъём ICSP (In Circuit Serial Programming, программирование устройства, включённого в цепь, по последовательному протоколу). Обратите внимание, что на разъёме ICSP отсутствует пин выбора ведомого – SS, т.к. подразумевается, что Arduino будет использоваться как ведущее устройство в сети. Но при необходимости вы можете назначить любой цифровой вывод Ардуино в качестве SS.
На рисунке приведено стандартное соответствие выводов шинам SPI для Arduino UNO и Nano.
3 Стандартная библиотека для работы по интерфейсу SPI
Для Arduino написана специальная библиотека, которая реализует протокол SPI . Она устанавливается вместе со средой разработки Arduino IDE. Подключается она так: в начале программы добавляем #include SPI.h.
Чтобы начать работу по протоколу SPI , нужно задать настройки и затем инициализировать протокол с помощью процедуры SPI.beginTransaction(). Можно выполнить это одной инструкцией: SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0))
Это значит, что мы инициализируем протокол SPI на частоте 14 МГц, передача данных идёт, начиная с MSB (наиболее значимого бита), в режиме SPI_MODE0.
После инициализации выбираем ведомое устройство, переводя соответствующий пин SS в состояние LOW. Затем передаём ведомому устройству данные командой SPI.transfer(). После передачи возвращаем SS в состояние HIGH.
Работа с протоколом завершается командой SPI.endTransaction().
Желательно минимизировать время выполнения передачи между инструкциями SPI.beginTransaction() и SPI.endTransaction(), чтобы не возникло накладок, если другое устройство попробует инициализировать передачу данных, используя другие настройки.
Если вы планируете в своём скетче использовать стандартные пины Arduino, можно не описывать их в начале программы, т.к. они уже определены в самой библиотеке и имеют следующие имена:
#define PIN_SPI_SS (10) #define PIN_SPI_MOSI (11) #define PIN_SPI_MISO (12) #define PIN_SPI_SCK (13)
Данные пины определены в файле pins_arduino.h , который находится по пути %programfiles%arduino-(версия)hardwarearduinoavrvariants (если вы устанавливали программу в стандартное расположение). То есть, например, чтобы опустить пин выбора ведомого в состояние «0», можно написать:
digitalWrite(PIN_SPI_SS, LOW);
4 Подключение сдвигового регистра к Arduino
Рассмотрим практическое применение интерфейса SPI . Будем зажигать светодиоды, управляя 8-битным сдвиговым регистром по шине SPI . Подключим к Arduino сдвиговый регистр 74HC595. К каждому из 8-ми выходов регистра через ограничительный резистор подключим по светодиоду номиналом 220 Ом. Схема приводится на рисунке.
5 Скетч для управления сдвиговым регистром по интерфейсу SPI
Напишем скетч, реализующий «бегущую волну», последовательно зажигая светодиоды, подключённые к выходам сдвигового регистра.
#include const int pinSelect = 8; // пин выбора регистра void setup() SPI.begin(); // инициализация интерфейса SPI pinMode(pinSelect, OUTPUT); // digitalWrite(pinSelect, LOW); // выбор ведомого устройств (регистра) SPI.transfer(0); // очищаем содержимое регистра digitalWrite(pinSelect, HIGH); // конец передачи Serial.begin(9600); > void loop() for (int i=0; i Serial.println(«———«); >
Сначала подключим библиотеку SPI и инициализируем интерфейс SPI . Определим пин 8 как пин выбора ведомого устройства SS . Очистим сдвиговый регистр, послав в него значение «0». Инициализируем последовательный порт.
Чтобы зажечь определённый светодиод с помощью сдвигового регистра, нужно подать на его вход 8-разрядное число. Например, чтобы загорелся первый светодиод – подаём двоичное число 00000001, чтобы второй – 00000010, чтобы третий – 00000100, и т.д. Эти двоичные числа при переводе в десятичную систему счисления образуют такую последовательность: 1, 2, 4, 8, 16, 32, 64, 128 и являются степенями двойки от 0 до 7.
Соответственно, в цикле loop() по количеству светодиодов делаем пересчёт от 0 до 7. Функция pow(основание, степень) возводит 2 в степень счётчика цикла. Микроконтроллеры не очень точно работают с числами типа «double», поэтому для преобразования результата в целое число используем функцию округления round(). И передаём получившееся число в сдвиговый регистр. Для наглядности в монитор последовательного порта выводятся значения, которые получаются при этой операции: единичка «бежит» по разрядам – светодиоды загораются волной.
6 «Бегущая волна» из светодиодов
Светодиоды загораются по очереди, и мы наблюдаем бегущую «волну» из огоньков. Управление светодиодами осуществляется с помощью сдвигового регистра, к которому мы подключились по интерфейсу SPI . В результате для управления 8-ю светодиодами задействованы всего 3 вывода Arduino. Если бы мы подключали светодиоды напрямую к цифровым портам Arduino, нам бы потребовалось для каждого светодиода использовать отдельный порт.