Наш канал в telegram

Программа для контроллера SPI-шлюза (режим SPI-master из терминалки ПК)

Программа, рассмотренная в этой статье, разработана для контроллера SPI-шлюза (шлюз у нас реализован на ATTiny2313). Эта программа позволяет из терминальной программы персонального компьютера общаться в качестве Master-а с различными SPI устройствами. В программе реализованы все 4 режима SPI, размер пакета может быть установлен от 1 до 64 бит, возможен выбор передачи пакета младшим или старшим битом вперёд, а также можно выбрать ручное или автоматическое управление линией SS. Написана программа полностью на ассемблере, в конце статьи выложены исходники (с комментариями) и прошивка.

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

Протокол обмена с компьютером был придуман на ходу и состоит из сообщений, размером в 1 или несколько байт.

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

Команды используются такие:

  1. 01h — загрузка конфигурации в шлюз. После принятия такой команды шлюз ждёт два байта конфигурации, которые определяют режим SPI, размер пакета, режим управления линией SS, порядок передачи бит (младшим или старшим вперёд) и скорость передачи. В шлюзе конфигурация хранится в двух специально выделенных регистрах: C1 и C2. Здесь нужно пожалуй добавить, что максимальная скорость передачи по SPI получилась где-то в районе 75 КБит/с, что довольно медленно для SPI и позволяет работать с любым устройством. Поскольку в конфигурации по умолчанию как раз заложена эта максимальная скорость, то менять её в общем-то особого смысла нет.
  2. 02h — считывание конфигурации из шлюза. После принятия такой команды шлюз отсылает на компьютер два байта конфигурации (С1, С2).
  3. 03h — загрузить пакет в шлюз. После принятия такой команды шлюз ждёт N байт пакета. N зависит от размера пакета, установленного в конфигурации шлюза и определяется по формуле N=(K-1)/8+1, где К — размер пакета в битах.
  4. 04h — считать пакет из шлюза. После принятия этой команды шлюз отсылает на компьютер N используемых байт сдвигового регистра.
  5. 05h — переключить SS в единицу. Если в конфигурации установлено ручное управление линией SS, то после принятия этой команды шлюз переключает линию SS в единицу.
  6. 06h — переключить SS в ноль. Если в конфигурации установлено ручное управление линией SS, то после принятия этой команды шлюз переключает линию SS в ноль.
  7. 07h — старт обмена. После принятия этой команды шлюз выполняет обмен пакетами с подключенным к нему по SPI устройством, в соответствии с установленной конфигурацией (режим SPI, размер пакета и прочее).

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

Служебные байты могут быть такими:

  1. 01h — предыдущая команда выполнена успешно.
  2. FFh — шлюзом была получена неизвестная команда.
  3. FEh — попытка установить размер пакета равным нулю (то есть получены неправильные байты конфигурации).
  4. FDh — попытка передачи, при высоком уровне на линии SS (такая ошибка возникает, если послать шлюзу команду 07h при ручном управлении линией SS, когда эта линия установлена в 1).

Вообще ручное и автоматическое управление линией SS работает следующим образом: при ручном управлении линия переключается только специальными командами от компа, при автоматическом — линия переключается в низкий уровень автоматически, сразу после приёма пакета от компьютера, после этого автоматически запускается обмен, а сразу после его завершения SS автоматически возвращается к высокому уровню (тут правильнее было бы проверять — не пришёл ли от компа ещё один пакет, пока мы передавали, и, в случае его обнаружения, — продолжать передачу, но пока переделывать прогу лень).

Прога написана таким образом, что при загрузке пакета из компьютера в шлюз, сначала надо отправлять младшие байты пакета, а потом старшие (т.е. если пакет имеет вид «2Ah 3Bh 4Eh», то шлюзу надо сначала отправлять 4Eh, потом 3Bh, а потом 2Ah).

Из интересных фишек в реализации отмечу ещё вот какую. В зависимости от режима SPI и порядка передачи бит, чтение бита с шины и сдвиг могут происходить по разному (у нас есть 2 процедуры для чтения и 4 для сдвига) и в разном порядке. Чтобы в процессе обмена не выяснять каждый раз заново, какую именно процедуру нужно выполнять (это бы очень сильно снизило скорость работы) — мы делаем это только один раз, на этапе конфигурирования, а потом записываем в 4 специальных регистра (Proc1_Address_L, Proc1_Address_H, Proc2_Address_L, Proc2_Address_H) адреса процедур, нужных нам в данной конфигурации для чтения и сдвига, причём если сначала выполняется чтение, а потом сдвиг, то мы в первые два регистра пишем адрес процедуры чтения, а во вторые два — адрес процедуры сдвига, если сначала нам нужен сдвиг, потом чтение, то наоборот, — в первые два регистра пишем адрес процедуры сдвига, а во вторые два — адрес процедуры чтения. Всё, теперь непосредственно при обмене нам вообще не нужно задумываться о том, что и как делать, — нужно просто по чётным фронтам вызывать с помощью косвенной адресации процедуру по первому сохранённому адресу, а по нечётным — процедуру по второму сохранённому адресу.

Вот пожалуй и всё описание (если возникнут вопросы — добро пожаловать на форум), а теперь перейдём к алгоритму и программе.

Алгоритм:

Алгоритм работы SPI-шлюза

Итак, в аппаратной части мы имеем:

  1. PB0 — линия SCLK
  2. PB1 — линия MISO
  3. PB2 — линия MOSI
  4. PD5 — линия SS
  5. PD0 — линия Rx
  6. PD1 — линия Tx
Текст программы под катом

    sbrc  C2,6        ; если передавали старшим битом вперёд - пропускаем !!! - вот тут ошибка

[свернуть]

Для правильной работы шлюза в контроллере должны быть «запрограммированы» следующие фьюзы: SPIEN, SUT0

Скачать готовую прошивку и asm-файл

Приведу небольшой пример работы со шлюзом:

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

Итак, заходим в терминалку, выбираем порт, скорость обмена (скорость у нас 115200), подключаемся и делаем следующее:

— отправляем шлюзу 05h // (установить CS=1)
— получаем от шлюза 01h // он сообщает, что установил CS=1
— отправляем шлюзу 01h // говорим шлюзу, что будем слать конфигурацию
— отправляем шлюзу 10h D2h // Mode0, 16 бит, автоматическое управление SS, передача старшим вперёд, скорость «18»
— получаем от шлюза 01h // шлюз сообщает, что загрузил конфигурацию
— отправляем шлюзу 03h // говорим шлюзу, что будем слать пакет (поскольку выбрано автоматическое управление SS, то принятый пакет шлюз сразу же и отправит)
— отправляем шлюзу 01h 0Сh // пакет для max-а: «0Ch 01h» (выход из режима shutdown)
— получаем от шлюза 01h // шлюз сообщает, что всё успешно отправил
— отправляем шлюзу 03h // говорим шлюзу, что будем слать пакет
— отправляем шлюзу 07h 0Bh // пакет для max-а: «0Bh 07h» (scan limit=7, отображаем 7 символов)
— получаем от шлюза 01h // шлюз сообщает, что всё успешно отправил
— отправляем шлюзу 03h // говорим шлюзу, что будем слать пакет
— отправляем шлюзу FFh 09h // пакет для max-а: «09h FFh» (для всех символов режим декодирования B)
— получаем от шлюза 01h // шлюз сообщает, что всё успешно отправил
— отправляем шлюзу 03h // говорим шлюзу, что будем слать пакет
— отправляем шлюзу 02h 0Bh // пакет для max-а: «0Bh 02h» (отобразить на втором индикаторе символ «E»)
— получаем от шлюза 01h // шлюз сообщает, что всё успешно отправил

В результате этих действий на втором семисегментном индикаторе, подключенном к нашему max7219, будет отображаться символ «E».

P.S. Гы-гы-гы, в проге обнаружилась ошибка. После метки End_Transfer, вот в этой строке:

    sbrc  C2,6        ; если передавали старшим битом вперёд - пропускаем !!! - вот тут ошибка

Самое интересное, что комментарий написан правильно, а команда стоит неправильная, должно быть sbrs вместо sbrc. Исправлять и перекомпилировать не стал, оставил возможность вам самим это сделать.

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

Добавить комментарий