Spi память что это

Обновлено: 07.07.2024


SPI (англ. Serial Peripheral Interface, SPI bus — последовательный периферийный интерфейс, шина SPI) — последовательный периферийный интерфейс, служит для связи периферии и микроконтроллера. Например, в качестве периферии может быть: дисплей, различные датчики, FLASH память, SD карта (да, да, SD карта или «флешка» которую вы используете в телефонах и фотоаппаратах общается с внешним миром с помощью интерфейса SPI) и т.д.Интерфейс SPI, наряду с I2C, относится к самым широко-используемым интерфейсам для соединения микросхем. Изначально он был придуман компанией Motorola, а в настоящее время используется в продукции многих производителей. Его наименование является аббревиатурой от 'Serial Peripheral Bus', что отражает его предназначение - шина для подключения внешних устройств. Шина SPI организована по принципу 'ведущий-подчиненный'. В качестве ведущего шины обычно выступает микроконтроллер, но им также может быть программируемая логика, DSP-контроллер или специализированная ИС. Подключенные к ведущему шины внешние устройства образуют подчиненных шины. В их роли выступают различного рода микросхемы, в т.ч. запоминающие устройства (EEPROM, Flash-память, SRAM), часы реального времени (RTC), АЦП/ЦАП, цифровые потенциометры, специализированные контроллеры и др. Устройства SPI взаимодействуют в полнодуплексном режиме, используя архитектуру master-slave с одним ведущим устройством. Главное устройство инициирует кадр для чтения и записи. Иногда SPI называют четырехпроводной последовательной шиной, контрастирующей с трех-, двух-и однопроводными последовательными шинами. SPI может рассматриваться, как синхронный последовательный интерфейс, но он отличается от протокола синхронного последовательного интерфейса (SSI), который также является четырехпроводным синхронным последовательным протоколом связи. Протокол SSI использует дифференциальную сигнализацию и предоставляет только один симплексный канал связи. [Источник 1] .

Содержание

Интерфейс

В SPI используются четыре цифровых сигнала:

  • MOSI или SI – выход ведущего, вход ведомого (англ. Master Out Slave In). Служит для передачи данных от ведущего устройства ведомому;
  • MISO или SO – вход ведущего, выход ведомого (англ. Master In Slave Out). Служит для передачи данных от ведомого устройства ведущему.
  • SCK или SCLK – последовательный тактовый сигнал (англ. Serial CLocK). Служит для передачи тактового сигнала для ведомых устройств.
  • CS или SS – выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).Как правило, выбор микросхемы производится низким логическим уровнем.

В зависимости от комбинаций полярности и фазы синхроимпульсов возможны четыре режима работы SPI. [Источник 2] . Хотя приведенные выше имена контактов являются наиболее популярными, в прошлом иногда использовались альтернативные соглашения об именовании контактов, поэтому имена контактов портов SPI для более старых продуктов IC могут отличаться от тех, которые представлены ниже:

Активные уровень импульсов — высокий. Сначала защёлкивание, затем сдвиг.

Активные уровень импульсов — высокий. Сначала сдвиг, затем защёлкивание.

Активные уровень импульсов — низкий. Сначала защёлкивание, затем сдвиг.

Активные уровень импульсов — низкий. Сначала сдвиг, затем защёлкивание.

В таблице принято:

Мастеру приходится настраиваться на тот режим, который используется ведомым. При обмене данными по интерфейсу SPI микроконтроллер может работать как ведущий (режим Master) либо как ведомый (режим Slave). При этом пользователь может задавать следующие параметры:

  • режим работы в соответствии с таблицей;
  • скорость передачи;
  • формат передачи (от младшего бита к старшему или наоборот).

Операции

Шина SPI может работать с одним ведущим устройством и с одним или несколькими ведомыми устройствами.
Если одно ведомое устройство используется, то SS может быть зафиксирован на низком логическом уровне, если позволяет ведомое устройство. Некоторые ведомые устройства требуют понижение сигнала чипа для начала действий. Примером может служить Maxim MAX1242 ADC, который запускает преобразование при переходе high→low. С множественными ведомыми устройствами, независимый сигнал SS необходим от ведущего для каждого ведомого устройства.
Большинство ведомых устройств имеют три состояния выходов, поэтому их сигнал MISO будет высокоимпедансным, когда устройство не выбрано.

Передача данных


Рисунок 1 - Типичная конфигурация системы с использованием двух сдвиговых регистров для формирования интер-чипа кольцевого буфера

Протокол передачи по интерфейсу SPI предельно прост и, по сути, идентичен логике работы сдвигового регистра, которая заключается в выполнении операции сдвига и, соответственно, побитного ввода и вывода данных по определенным фронтам сигнала синхронизации. Установка данных при передаче и выборка при приеме всегда выполняются по противоположным фронтам синхронизации. Это необходимо для гарантирования выборки данных после надежного их установления. Если к этому учесть, что в качестве первого фронта в цикле передачи может выступать нарастающий или падающий фронт, то всего возможно четыре варианта логики работы интерфейса SPI. Эти варианты получили название режимов SPI и описываются двумя параметрами:\

  • CPOL - исходный уровень сигнала синхронизации (если CPOL=0, то линия синхронизации до начала цикла передачи и после его окончания имеет низкий уровень (т.е. первый фронт нарастающий, а последний - падающий), иначе, если CPOL=1, - высокий (т.е. первый фронт падающий, а последний - нарастающий));
  • CPHA - фаза синхронизации; от этого параметра зависит, в какой последовательности выполняется установка и выборка данных (если CPHA=0, то по переднему фронту в цикле синхронизации будет выполняться выборка данных, а затем, по заднему фронту, - установка данных; если же CPHA=1, то установка данных будет выполняться по переднему фронту в цикле синхронизации, а выборка - по заднему).

Ведущая и подчиненная микросхемы, работающие в различных режимах SPI, являются несовместимыми, поэтому, перед выбором подчиненных микросхем важно уточнить, какие режимы поддерживаются ведущим шины. Аппаратные модули SPI, интегрированные в микроконтроллеры, в большинстве случаев поддерживают возможность выбора любого режима SPI и, поэтому, к ним возможно подключение любых подчиненных SPI-микросхем (относится только к независимому варианту подключения). Кроме того, протокол SPI в любом из режимов легко реализуется программно.

Часы полярности и фазы

Как показано на рисунке 2, в дополнение к установке тактовой частоты, ведущий должен также установить полярность и временной участок по отношению к данным. Временная диаграмма на рисунке, показывает полярность и фазу часов - красные линии обозначают начальные края часов,а синие-конечные.


Рисунок 2 - Временная диаграмма SPI

Возможны четыре комбинации фазы (CPHA) и полярности (CPOL) сигнала SCLK по отношению к сигналам данных. Режимы работы определяются комбинацией бит CPHA и CPOL:

  • CPOL = 0 — сигнал синхронизации начинается с низкого уровня;
  • CPOL = 1 — сигнал синхронизации начинается с высокого уровня;
  • CPHA = 0 — выборка данных производится по переднему фронту сигнала синхронизации;
  • CPHA = 1 — выборка данных производится по заднему фронту сигнала синхронизации.

Для обозначения режимов работы интерфейса SPI принято следующее соглашение:

  • режим 0 (CPOL = 0, CPHA = 0);
  • режим 1 (CPOL = 0, CPHA = 1);
  • режим 2 (CPOL = 1, CPHA = 0);
  • режим 3 (CPOL = 1, CPHA = 1).

Топология систем связи на базе SPI

В простейшем случае к ведущему устройству подключено единственное ведомое устройство и необходим двусторонний обмен данными. В таком случае используется трехпроводная схема подключения. Интерфейс SPI позволяет подключать к одному ведущему устройству несколько ведомых устройств, причем подключение может быть осуществлено несколькими способами, как показано на рисунках 3 и 4 [Источник 3] .


Рисунок 3- Радиальная структура связи с несколькими ведомыми устройствами через SPI


Рисунок 4 - Кольцевая структура связи с несколькими ведомыми устройствами через SPI

Первый способ позволяет реализовать радиальную структуру связи (топология типа «звезда»), его принято считать основным способом подключения нескольких ведомых устройств. В данном случае для обмена более чем с одним ведомым устройством ведущее устройство должно формировать соответствующее количество сигналов выбора ведомого устройства (SS). При обмене данными с ведомым устройством, соответствующий ему сигнал SS переводится в активное (низкое) состояние, при этом все остальные сигналы SS находятся в неактивном (высоком) состоянии. Выводы данных MISO ведомых устройств соединены параллельно, при этом они находятся в неактивном состоянии, а перед началом обмена один из выходов (выбранного ведомого устройства) переходит в активный режим.

Синхронизация в SPI

Частота следования битовых интервалов в линиях передачи данных определяется синхросигналом SCK, который генерирует ведущее устройство, ведомые устройства используют синхросигнал для определения моментов изменения битов на линии данных, при этом ведомые устройства никак не могут влиять на частоту следования битовых интервалов. Как в ведущем устройстве, так и в ведомом устройстве имеется счетчик импульсов синхронизации (битов). Счетчик в ведомом устройстве позволяет последнему определить момент окончания передачи пакета. Счетчик сбрасывается при выключении подсистемы SPI, такая возможность всегда имеется в ведущем устройстве. В ведомом устройстве счетчик обычно сбрасывается деактивацией интерфейсного сигнала SS. [Источник 4] .
Так как действия ведущего и ведомого устройства тактируются одним и тем же сигналом, то к стабильности этого сигнала не предъявляется никаких требований, за исключением ограничения на длительность полупериодов, которая определяется максимальной рабочей частотой более медленного устройства. Это позволяет использовать SPI в системах с низкостабильной тактовой частотой, а также облегчает программную эмуляцию ведущего устройства.

Приложения

SPI используется с различными периферийными устройствами, такими как:

  • Датчики: температуры, давления, АЦП, сенсорные экраны, видео игровые контроллеры
  • Устройства контроля: аудио кодеки, цифровые потенциометры, ЦАП
  • Камера: объектив Canon EF
  • Коммуникации: сеть Интернет, интерфейс USB, USB, USART, CAN, IEEE 802.15.4, IEEE 802.11
  • Память: Флэш и EEPROM
  • Часы реального времени
  • ЖК, иногда даже для управления изображения данных
  • Любые ММС или CD карты (в том числе поддержка SDIO)

Для высокопроизводительных систем, FPGAs иногда использует SPI интерфейс как ведомый к ведущему, а ведущий к датчикам, или для флэш-памяти, используемой для загрузки, если они основаны на SRAM. [Источник 5] .

Преимущества и недостатки интерфейса SPI

Преимущества

  • Полнодуплексная передача данных по умолчанию.
  • Более высокая пропускная способность по сравнению с I²C или SMBus.
  • Возможность произвольного выбора длины пакета, длина пакета не ограничена восемью битами.
  • Простота аппаратной реализации:
    • более низкие требования к энергопотреблению по сравнению с I²C и SMBus;
    • возможно использование в системах с низкостабильной тактовой частотой;
    • ведомым устройствам не нужен уникальный адрес, в отличие от таких интерфейсов, как I²C, GPIB или SCSI.

    Недостатки

    • Необходимо больше выводов, чем для интерфейса I²C.
    • Ведомое устройство не может управлять потоком данных.
    • Нет подтверждения приема данных со стороны ведомого устройства (ведущее устройство может передавать данные «в никуда»).
    • Нет определенного стандартом протокола обнаружения ошибок.
    • Отсутствие официального стандарта, что делает невозможным сертификацию устройств.
    • По дальности передачи данных интерфейс SPI уступает таким стандартам, как UART и CAN.
    • Наличие множества вариантов реализации интерфейса.
    • Отсутствие поддержки горячего подключения устройств.

    Стандарты

    Пример программной реализации

    Ниже представлен пример программной реализации SPI мастера на языке Си. Линия CS (chip select, выбор микросхемы) должна быть активирована (в большинстве случаев — притянута к низкому уровню), перед тем, как начнётся обмен данными, и деактивирована после окончания обмена. Большинство устройств требуют несколько сеансов передачи с активной линией CS. Эта функция может быть вызвана несколько раз, пока линия активна.

    SPI (англ. Serial Peripheral Interface, SPI bus — последовательный периферийный интерфейс, шина SPI) — последовательный синхронный стандарт передачи данных в режиме полного дуплекса, разработанный компанией Motorola для обеспечения простого и недорогого сопряжения микроконтроллеров и периферии. SPI также иногда называют четырёхпроводным (англ. four-wire) интерфейсом.

    SPI является синхронным интерфейсом, в котором любая передача синхронизирована с общим тактовым сигналом, генерируемым ведущим устройством (процессором, контроллером). Принимающая (ведомая) периферия синхронизирует получение битовой последовательности с тактовым сигналом. К одному последовательному периферийному интерфейсу ведущего устройства-микросхемы может присоединяться несколько микросхем. Ведущее устройство выбирает ведомое для передачи, активируя сигнал «выбор кристалла» (англ. chip select) на ведомой микросхеме. Периферия, не выбранная контроллером, не принимает участия в передаче по SPI.



    В SPI используются четыре цифровых сигнала:

    MOSI (SI, DO, SDO, DOUT) — выход ведущего, вход ведомого (англ. Master Out Slave In). Служит для передачи данных от ведущего устройства ведомому.

    MISO (SO, DI, SDI, DIN) — вход ведущего, выход ведомого (англ. Master In Slave Out). Служит для передачи данных от ведомого устройства ведущему.

    SCLK (DCLOCK, CLK, SCK) — последовательный тактовый сигнал (англ. Serial Clock). Служит для передачи тактового сигнала для ведомых устройств.

    CS или SS — выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).

    Установка данных при передаче и выборка при приеме всегда выполняются по противоположным фронтам синхронизации. Это необходимо для гарантирования выборки данных после надежного их установления. Если к этому учесть, что в качестве первого фронта в цикле передачи может выступать нарастающий или падающий фронт, то всего возможно четыре варианта логики работы интерфейса SPI. Эти варианты получили название режимов SPI и описываются двумя параметрами:

    • CPOL=0 показывает, что сигнал синхронизации начинается с низкого уровня, так что передний фронт является нарастающим, а задний — падающим.
    • CPOL=1, показывает, что сигнал синхронизации начинается с высокого уровня, таким образом передний фронт является падающим, а задний — нарастающим.
    • CPHA=0 показывает, что необходимо производить выборку по переднему фронту
    • CPHA=1 показывает, что выборку данных необходимо производить по заднему фронту.

    Пунктирной линией показывает момент передачи данных.

    Режим 0 / Mode 0


    В этом режиме пассивным уровнем линии SCK является «0», а передача дынных производится по заднему (падающему) фронту.

    Режим 1 / Mode 1


    В этом режиме пассивным уровнем линии SCK является «0», а передача дынных производится по переднему (нарастающему) фронту.

    Режим 2 / Mode 2


    В этом режиме пассивным уровнем линии SCK является «1», а передача дынных производится по переднему (нарастающему) фронту.

    Режим 3 / Mode 3


    В этом режиме пассивным уровнем линии SCK является «1», а передача дынных производится по заднему (падающему) фронту.

    От теории перейдем к практике.

    Как всегда начнем с объявления необходимых переменных.

    Для начала проведем настройку линий интерфейса. В принципе все это можно сделать в первоначальной настройке контроллера, но для примера вынесем все в отдельную функцию. Данную функцию можно запустить один раз при настройке контроллера.

    Для начала обмена необходимо перевести линию CS (SS) в «0».
    Окончанием связи служит перевод линии CS в «1».

    Ну и конечно же функции Передачи и Приема.

    Память Atmel DataFlash AT45DB081D.

    • Страничная Flash память;
    • Емкость — 8 Мбит;
    • Организация — 4096 страниц по 256 или 264 байта;
    • Высокоскоростной SPI интерфейс обмена;
    • Напряжение питания от 2,5 или 2,7 до 3,6 В;
    • Максимальное входное напряжение до 6,25 В, что позволяет подключать ее напрямую к 5-ти вольтовому контроллеру;
    • Два буфера SRAM памяти по 256 или 264 байта каждый;
    • Принцип работы «чтение-модификация-запись»;
    • Программная и аппаратная защита от записи.

    Несколько особенностей при работе с данной памятью.

    1. По умолчанию вся память организована по 264 байта на страницу. Ее можно реорганизовать на 256 байт на страницу, НО это возможно сделать только один раз и обратно на 264 сменить не удастся. Так что не будем на этом заморачиваться, тем более что это никак нам не мешает. Также у памяти есть специальные 4 байта в которые можно записать идентификатор (например серийный номер изделия), но запись в них так же однократная и перезаписи не подлежит.

    • RESET — аппаратный сброс микросхемы;
    • WP (Write Protection) — аппаратная защита от перезаписи.

    3. Обмен данными происходит по 4-х проводному интерфейсу SPI. Микросхема может работать в режимах SPI 0 и 3, а также двух собственных режимах Atmel. Чтобы во всем этом не разбираться будем использовать обычный SPI mode 0.

    4. Так как память страничная, то как такового доступа к отдельным ячейкам нет. Все операции чтения/записи происходят по принципу «чтение-модификация-запись» с использованием 2 специальных буферов. Использование 2 буферов помогает ускорить и упростить некоторые операции (пока один буфер записывается в память, второй заполняется новыми данными).

    5. После подачи питания и перед обращением к памяти необходимо сделать гарантированную задержку в 20 миллисекунд.

    Особенности страничной памяти.

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

    Написано может быть и чуть не понятно, но в общем работа с памятью сводится к последовательному заполнению внутреннего буфера. В случае его полного заполнения производится запись в страницу памяти. В дальнейшем буфер снова заполняется с начала.

    Адрес байта в памяти записывается тремя байтами:
    x x x P P P P P P P P P P P P B B B B B B B B B
    где x x x — резерв (не используется, =0);
    P P P P P P P P P P P P — адрес страницы (12 бит), может принимать значения от 0 до 4095;
    B B B B B B B B B — адрес байта на странице (9 бит), может принимать значения от 0 до 263/255.

    В качестве примера вычислим расположение байта под номером 353 246.
    Для определения номера страницы разделим число на 264:
    353246 / 264 = 1338,053 = 1338 = 01010 0111010
    А теперь определим адрес байта на странице:
    353246 — (1338*264) = 353246 — 353232 = 14 = 000001110
    Таким образом получается адрес: 00001010 01110100 00001110 или 0Ah 74h 0Eh.

    Ну что же приступаем, глядишь на деле все и проясниться.

    Итак, первая команда которую необходимо рассмотреть — это Status Register Read (D7h). Она необходима для определения готовности памяти. Так как внутренний процесс записи может занимать продолжительное время, то для определения его окончания нужно считать Status регистр и проверить в нем старший бит RDY, если там «1» то память готова.

    Оформим это в отдельную функцию.


    Использовать ее можно вот так:


    А для определения окончания записи, вот так:

    Команда очистки памяти.


    Этот процесс достаточно длительный и может занимать от 7 до 22 секунд.

    Рассмотрим остальные команды на примере чтения пяти байт из памяти, начиная с адреса 353246 (адрес страницы — 1338, адрес байта — 14) в массив unsigned char MEMbuff[5];. Работать будем через Buffer 1.

    1. Считать необходимую страницу во внутренний буфер. Адрес страницы 1338 = 00001010 01110100 или 0Ah 74h, остальные биты «0».


    2. Прочитать из внутреннего буфера необходимые данные, начиная с адреса 14 = 00001110 или 0Eh, остальные биты «0».


    1 Dummy Byte — 1 пустой (произвольный) байт необходим памяти для подготовки данных, этакая небольшая временная задержка.

    После этих двух операций пять считанных байт, начиная с адреса 353246, будут записаны в массив MEMbuff.

    А теперь попробуем записать те же пять байт в ту же область памяти. На этот раз работать будем через Buffer 2.

    1. Считать необходимую страницу во внутренний буфер. Адрес страницы 1338 = 00001010 01110100 или 0Ah 74h, остальные биты «0».


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

    2. Начиная с адреса 14 = 00001110 или 0Eh, произвести «модификацию» в буфере 2.


    Хотя в даташите ничего не сказано про 1 Dummy Byte, правильно память заработала только с ним.

    3. Записать буфер 2 в страницу памяти.

    Проверка.

    Так как модели для протеуса не нашлось, будем экспериментировать в железе.

    Для индикации работы подключим к RC2 анод светодиода, катод на землю.

    Проверочная программа.
    1. Зажигает светодиод. Выполняет очистку памяти. После окончания очистки гасит светодиод.
    2. Записывает 5 байт в память.
    3. Читает 5 байт из памяти.
    4. Считанные данные записываются в EEPROM память контроллера. Светодиод начинает мигать.

    Для проверки необходимо прошить программу в контроллер, дождаться когда начнет мигать светодиод, выключить контроллер и считать EEPROM.

    В этой статье я хочу провести краткий обзор шины SPI (интерфейса, широко распространённого во встраиваемой технике, используемого для подключения различных устройств) и попытаюсь описать процесс создания драйвера протокольного уровня SPI устройства для Linux. Данный документ не претендует на роль полного руководства, а скорее преследует цель указать нужное направление. Так как статья не вошла в размер одного топика, мне пришлось разбить её на две части.

    0. Вместо введения

    Что это за статья?
    Эта статья представляет собой компиляцию информации из различных источников, вольный перевод некоторых частей документации, а также мои собственные комментарии, дополнения и описания возникших проблем.

    1. Что такое SPI?
    2. Обзор SPI подсистемы в Linux
    3. Разработка userspace протокольного SPI драйвера с использованием spidev
    4. Разработка протокольного SPI драйвера уровня ядра
    5. Документация

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

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

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

    Если вы видите ссылки в названии какой-либо структуры или функции, можете открыть её в новой вкладке, так вы сможете попасть непосредственно на описание данной структуры/функции в официальной документации к ядру Linux.

    Ошибки
    Я не волшебник, я только учусь. Если найдёте какие-либо ошибки или неточности, пожалуйста, сообщите мне.

    1. Что такое SPI?

    Аббревиатура SPI означает «Serial Peripheral Interface» или в русском варианте «последовательный периферийный интерфейс». Название говорит само за себя, данный интерфейс используется для работы с различными периферийными устройствами. Например, это могут быть различные ЦАП/АЦП, потенциометры, датчики, расширители портов ввода/вывода (GPIO), различная память и даже более сложная периферия, такая как звуковые кодеки и контроллеры Ethernet.

    С технической точки зрения SPI — это синхронная четырёхпроводная шина. Она представляет собой соединение двух синхронных сдвиговых регистров, которые является центральным элементом любого SPI устройства. Для соединения используется конфигурацию ведущий/ведомый. Только ведущий может генерировать импульсы синхронизации. В схеме всегда только один ведущий (в отличие от той же шины I2C, где возможен вариант с более чем одним ведущим), количество ведомых может быть различно. В общем случае выход ведущего соединяется со входом ведомого, и наоборот, выход ведомого соединяется со входом ведущего. При подаче импульсов синхронизации на выход SCK, данные выталкиваются ведущим с выхода MOSI, и захватываются ведомым по входу MISO. Таким образом если подать количество импульсов синхронизации соответствующее разрядности сдвигового регистра, то данные в регистрах обменяются местами. Отсюда следует что SPI всегда работает в полнодуплексном режиме. А вот нужны ли нам данные, полученные от устройства при записи какого-либо параметра, это уже другой вопрос. Часто бывает что данные полученные от устройства при записи в него данных являются мусором, в таком случае их просто игнорируют, но мы их получим вне зависимости от нашего желания.

    Контроллер SPI, как правило, реализуется периферийным блоком в MCU или eMPU. В большинстве чипов он может работать как в режиме ведущего, так и в режиме ведомого. Но на данный момент Linux поддерживает только режим ведущего (Master).

    Существует несколько способов включения SPI устройств.

    image

    Простейший из них вы видите на рисунке выше (спасибо Wikipedia за рисунки под свободной лицензией GFDL). В данном случае к ведущему все ведомые подключаются параллельно, за исключением сигнала выбора ведомого (

    CS). Для каждого ведомого необходим отдельный сигнал выбора ведомого (на рисунке они обозначены как SSx). Для сигналов выбора ведомого могут использоваться как специально предназначенные для этого выходы SPI-контроллера, так и порты ввода/вывода общего назначения (GPIO) микроконтроллера.

    • MOSI — Master Output, Slave Input (выход ведущего, вход ведомого). Данный сигнал предназначен для последовательной передачи данных от ведущего к ведомому. Также может называться SDO, DO и т.п.
    • MISO — Master Input, Slave Output (вход ведущего, выход ведомого). Данный сигнал предназначен для последовательной передачи данных от ведомого к ведущему. Может называться SDI, DI и т.п.
    • SCK — Serial Clock (сигнал синхронизации). Используется для синхронизации при передаче данных. Также может иметь название SCLK, CLK и др.

    CS — Chip Select (выбор микросхемы). С помощью данного сигнала происходит активация ведомого устройства. Обычно он является инверсным, то есть низкий уровень считается активным. Иногда его называют

    Частным случаем независимого подключения является вариант с одним единственным ведомым. В таком случае может возникнуть желание подтянуть сигнал

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

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

    CS. Каскадная схема подключения, в зарубежной литературе называемая «daisy-chain» (можно перевести как «гирлянда»), лишена такого недостатка.

    image

    Как видно из рисунка выше, здесь используется общий сигнал выбора ведомого для всех ведомых. Выход каждого из ведомых соединяется со входом следующего. Выход последнего ведомого соединяется со входом ведущего, таким образом образуется замкнутая цепь. При таком подключении можно считать что последовательно соединённые устройства образуют один большой сдвиговый регистр. Соответственно, данные можно записать во все устройства «за один присест», предварительно собрав нужный пакет, объединяющий данные для каждого из устройств в порядке соответствующем физическому порядку соединения. Но тут есть один тонкий момент. Во-первых, все микросхемы должны поддерживать такой тип подключения; во-вторых, ядро Linux не поддерживает такой тип подключения, так что если всё же захотите его использовать, то вам придётся модифицировать существующие драйвера, либо же написать собственные.

    • CPOL (Clock Polarity) — определяет начальный уровень (полярность) сигнала синхронизации.
      CPOL=0 показывает, что сигнал синхронизации начинается с низкого уровня, так что передний фронт является нарастающим, а задний — падающим.
      CPOL=1, сигнал синхронизации начинается с высокого уровня, таким образом передний фронт является падающим, а задний — нарастающим.
    • CPHA (Clock Phase) — фаза синхронизации, определяет по какому из фронтов синхронизирующего сигнала производить выборку данных.
      CPHA=0 показывает что необходимо производить выборку по переднему фронту, а
      CPHA=1 показывает что выборку данных необходимо производить по заднему фронту.

    CS и MISO не показаны. Но в данном случае они не так интересны, например, сигнал

    CS представляет собой просто «провал» на всём протяжении передачи данных.

    2. Обзор SPI подсистемы в Linux

    Вторая часть — это протокольные драйверы, используемые для работы с различными ведомыми устройствами, которые подключены к шине SPI. Данные драйверы называют «протокольными», потому что они лишь отправляют и получают различные данные от ведомых устройств, при этом не работая напрямую с каким-либо оборудованием. Именно данный тип драйверов нам наиболее интересен, так как позволяет добавить поддержку интересующего ведомого устройства в систему, его то мы и рассмотрим.

    Большинство протокольных драйверов представляет собой модули ядра. Например, если устройство представляет собой аудиокодек подключаемый по SPI, то драйвер будет также использовать функции предоставляемые ALSA, а программы (например, madplay) смогут работать с ним посредством символьного устройства /dev/audio, не имея ни малейшего понятия о том как он аппаратно устроен и к какой шине подключен.

    Также ядро предоставляет протокольный драйвер общего назначения, называемый spidev, с интерфейсом в виде символьного устройства. Он позволяет совершать полудуплексные обращения к ведомому SPI-устройству посредством стандартных системных вызовов read() и write(), устанавливать режим работы, а также производить полнодуплексный обмен данными посредством ioctl() вызовов.

    • userspace драйверы, работающие в пространстве пользователя и представляющие собой обычные программы на любом языке, работающие с SPI устройством посредством чтения/записи соответствующего символьного устройства spidev.
    • драйверы, работающие в пространстве ядра и предоставляющие интерфейс для userspace посредством файлов устройств в каталоге /dev, либо с помощью атрибутов в каталоге устройства в sysfs.

    tx_buf — указатель на буфер данных в пространстве памяти ядра, которые необходимо передать, либо NULL;
    rx_buf — указатель на буфер данных в пространстве памяти ядра, в который данные следует считать, либо NULL;
    len — размер буферов rx и tx в байтах;
    tx_dma — DMA адрес tx_buf, используется если установлен параметр spi_message.is_dma_mapped;
    rx_dma — DMA адрес rx_buf, используется если установлен параметр spi_message.is_dma_mapped;
    speed_hz — устанавливает скорость для передачи, отличную от установленной по-умолчанию для устройства. Если данное значение равно 0, то используется скорость по-умолчанию, указанная в поле max_speed_hz структуры spi_device.
    bits_per_word — устанавливает количество бит на слово, отличное от определённого по умолчанию. Если данное значение равно 0, то используется значенние по-умолчанию, указанное в поле bits_per_word структуры spi_device.
    delay_usecs — время ожидания в микросекундах, после того как был отправлен последний бит передачи и перед тем как сменить состояние chipselect'а, либо начать передачу следующей передачи в очереди. Будьте крайне осторожны с данным параметром, нужно смотреть в какой части драйвера контроллера реализуется задержка. Например, для чипов серии at91 она реализована в обработчике прерывания, так что её использование чревато последствиями.

    При инициализации структуры spi_transfer существует очень важный момент, они обязательно должны быть выделены в области памяти доступной для DMA через kmalloc, kzalloc и иже с ними. Если master-драйер использует dma, то при использовании статически объявленных массивов драйвер будет падать при попытке передачи.

    При передаче данных по SPI количество записанных бит всегда равно количеству считанных. Протокольные драйверы всегда должны предоставлять указатели на буферы tx_buf и/или rx_buf. В некоторых случаях они могут предоставлять DMA адреса для передаваемых данных.

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

    Если указатель на tx_buf установлен как NULL, то SPI контроллер будет выталкивать нули при заполнении буфера rx_buf. В случае, когда rx_buf установлен в NULL, считываемые данные будут игнорироваться. Количество выталкиваемых (и захватываемых) байтов всегда равно len. Попытка вытолкнуть только часть слова приведёт к ошибке. (Например, при попытке выталкивании трёх байт и длине слова 16 бит или 20 бит, в первом случае будет использовано 2 байта на слово, во втором — 4 байта).

    Данные для передачи всегда хранятся в порядке специфичном для данной аппаратной платформы. При отправке/считывании данных происходит автоматическое конвертирование порядка байт из специфичного для SPI (обычно big-endian, за исключением случая когда выставлен параметр SPI_LSB_FIRST) в аппаратно-специфичный порядок для данного CPU. Например, если параметр bits_per_word равен 16, то буферы будут занимать по 2N байт, и содержать по N слов с длиной 16 бит каждое, хранящемся в байтовом порядке, специфичным для данного CPU.

    image

    В том случае, если размер слова не является степенью двойки, то представление слова в памяти включает дополнительные биты. Слова, хранящиеся в памяти для протокольного драйвера всегда являются выровненными по правому краю (right-justified), так что дополнительные биты всегда будут являться старшими разрядами.
    Для наглядности снова приведу осциллограмму:

    В данном случае tx-буфер содержит значение 0xf98e, установленное значение bits_per_word соответствует 12 битам на слово. Устройство работает в SPI_MODE_0. На рисунке синяя линия соответствует выходу MOSI контроллера, а жёлтая — SCK. Здесь хорошо видно что при отправке пришло только 0x098e, старшие четыре бита были отброшены, так как они считаются дополнительными. Если совсем просто, то одно 12-битное слово занимает в памяти два байта, а разница между размером слова в памяти и его действительным размером составляет 2*8 — 12 = 4 бита, которые отбрасываются при передаче.

    SPI не поддерживает какого-либо механизма автоматического обнаружения устройств. К тому же, в большинстве случаев, SPI устройства не предусматривают горячее подключение/отключение, поэтому они, как правило, просто распаиваются непосредственно на плате. В связи с этим данные устройства считаются специфичными для конкретной платы (board-specific). Параметры для таких устройств указываются в файле платы: arch/. /mach-*/board-*.c.
    Например, вот так будет выглядеть установка параметров для аудиокодека tlv320aic23b для отладочной платы SK-AT91SAM9260:

    где modalias – название драйвера ядра, отвечающего за обслуживание устройства (в нашем случае “tlv320aic23b”);
    chip_select – номер соответсвующего chip select'а;
    max_speed_hz – максимальная частота в Гц;
    mode – режим SPI, определяемый константами SPI_MODE_0… SPI_MODE_3, также через операцию битового “или” могут быть добавлены флаги SPI_CS_HIGH (устанавливает активным высокий уровень для chipselect-а ), SPI_NO_CS (передача данных без активации CS в принципе). Полный список возможных флагов можно посмотреть в описании структуры spi_device;
    bus_num – номер шины (как правило, соответсвует номеру SPI контроллера в даташите на MCU/eMPU).
    Также структура spi_board_info содержит следующие поля, не инициализированные в примере выше:
    const void *platform_data – данное поле предназначено для хранения указателя на данные специфичные для конкретного драйвера;
    void *controller_data – для некоторых контроллеров необходима информация о настройке устройства, например, DMA;
    int irq – зависит от подключения устройства.

    Все поля структуры spi_board_info устанавливают соответствующие поля структуры spi_device.
    В случае необходимости установки параметров для других SPI устройств, в масив добавляются ещё аналогичые элементы.
    Данные структуры хранят информацию, которая не может быть всегда определена драйверами. Информация, которая может быть определена функцией probe() драйвера (например, количество бит на слово), в данную структуру не включается.

    Стоит заметить, что всё же существует возможность горячего подключения ведомых SPI устройств. В этом случае используют функцию spi_busnum_to_master() для получения указателя на структуру spi_master по номеру шины SPI и дальнейшего перебора устройств на шине. Но данная тема выходит за рамки данной статьи.

    Сегодня мы начинаем знакомство с шиной SPI (Serial Peripheral Interface).

    Ещё одним важнейшим фактором необходимости нашего с ней знакомства является то, что данная шина аппаратно организована в контроллерах AVR.

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

    Поэтому хочется познакомиться с данной шиной поближе.

    Давайте откроем техническую документацию на контроллер Atmega8, откроем страницу, где изображена распиновка данного контроллера и посмотрим, что от 16 до 19 ножки и находятся выводы шины SPI

    image00

    Теперь немного подробнее о данных выводах

    Вот схема реализации шины SPI в контроллере Atmega8

    image01

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

    Нам интересен SHIFT REGISTER, через него и происходит обмен информации. Как только на ножке синхронизации будет определённый фронт, или нисходящий или восходящий, в зависимости от настройки, данные регистры у ведомого и ведущего устройства обменяются информацией, причем не всей информацией, а только одним битом. Данные регистры сдвинутся влево и старшие биты из каждого регистра уйдут в младшие биты такого же регистра сопряженного устройства. То есть ведомый передаст свой старший бит через ножку MOSI ведущему, который его запишет в освободившийся засчет сдвига влево младший бит, а ведомый свой вытесненный засчет сдвига передаст старший бит через ножку MISO в младший бит ведущего. Вот так и идёт обмен, то есть за 8 полных циклов тактирования они полностью обменяются байтами

    image02

    Как только все 8 бит одного байта информации передадутся, определённый регистр нам просигнализирует о том, что данный процесс закончен. Вернее, определённый бит определённого регистра.

    Также в блок-схеме мы видим делитель, на вход которого поступают тактовые импульсы и уже потом разделённые на определенное значение поступают по цепочке на ножку SCK и уже оттуда подаются на ведомое устройство на одноимённую ножку. Этим и обеспечивается синхронность работы устройств. Частота тактовых импульсов выбирается из наименьшей поддерживаемой всеми устройствами, участвующими в обмене.

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

    Существует несколько способов обена информацией между несколькими устройствами, то есть когда на одно ведущее устройство приходится несколько ведомых. Мы рассмотрим два самых распространённых из них.

    image03

    Здесь мастер направляет данные к определённому устройству, включая на ножке SS логический 0. При данном способе возможно выбрать только одно устройство, также потребуются несколько свободных ножек портов контроллера.

    image05_502

    Здесь мы видим, что ножки выбора все запараллелены и обмен идёт по кругу. Тем самым скорость падает, засчёт того, что увеличивается круг передачи, но зато экономятся лапки портов.

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

    Ну, вроде со схемотехникой передачи данных по шине SPI мы разобрались.

    Теперь разберёмся, как же данным процессом управлять на уровне аппаратных регистров контроллера AVR.

    Данные регистры мы видим в блок-схеме выше на странице.

    У Atmega8 существуют следующие регистры для обслуживания шины SPI.

    image06

    Данный регистр включает в себя следующие биты:

    Если данный бит в 1, то режим ожидания будет у нас при восходящем фронте, а если в 0, то при нисходящем.

    image09

    Посмотрим диаграммы передачи данных в зависимости от установки CPOL и CPHA

    image10

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

    image07

    Посмотрим зависимость частоты от данных трёх битов

    image11

    Ну теперь мы, можно сказать, немного познакомились с интерфейсом SPI.

    В следующем занятии мы уже попытаемся данную шину использовать на практике, подключив к нашему контроллеру какое-нибдуь ведомое устройство.

    Купить программатор можно здесь (продавец надёжный) USBASP USBISP 2.0

    Читайте также: