Наш магазин на eBay Наш магазин на AliExpress Наш канал в telegram

Работа модуля USI в контроллерах AVR Tiny

Модуль USI — это некий суррогат, который предоставляет минимальные аппаратные ресурсы, необходимые для построения последовательного интерфейса. Тут всё как обычно, универсальный — значит никакой конкретный, соответственно, чтобы использовать USI для организации какого-то конкретного интерфейса, всё равно придётся сочетать его с программными средствами, однако такое сочетание позволит разгрузить процессор, значительно увеличить скорость передачи и уменьшить код, по сравнению с чисто программными решениями. Чаще всего модуль USI используют для организации интерфейсов SPI и I2C, хотя возможны и другие применения.

Основные возможности:

  • двухпроводная синхронная передача данных (Мастер или Слэйв на скорости до Fosc/16)
  • трёхпроводная синхронная передача данных (Мастер на скорости до Fosc/2 или Слэйв на скорости до Fosc/4)
  • прерывание по окончанию приёма/передачи данных
  • пробуждение из энергосберегающего режима IDLE, а для двухпроводного режима вообще из всех энергосберегающих режимов, включая Power-down
  • определение START-условия (согласно спецификации I2C) с возможностью прерывания по этому событию
  • удержание линии SCL на низком уровне при обнаружении Start-условия или при переполнении счётчика (для двухпроводного режима). Удержание включается только после того, как шина будет переведена на низкий уровень Master-ом и выключается при сбросе сигнализирующего об обнаружении Start-условия флага

Структурная схема:

структурная схема модуля USI

Как видно из схемы, основные составные части модуля USI — это:

  • три регистра: USIDR — сдвиговый регистр (здесь хранятся принимаемые/передаваемые данные), USISR — регистр статусов (здесь содержится информация о различных событиях и значение 4-битного счётчика), а также USICR — регистр управления (в этом регистре выбираются настройки модуля).
  • блок контроля линии тактирования для 2-проводного режима. Этот блок умеет определять события Start, Stop и удерживать линию тактирования на низком уровне при обнаружении Start-условия или переполнении счётчика.
  • прозрачная защёлка (transparent latch). Подробнее о ней будет сказано ниже.
  • ну и пачка разных селекторов, инверторов, детекторов фронтов и т.д. (они выбирают тактовые сигналы для счётчика, сдвигового регистра и прозрачной защёлки)

Здесь хотелось бы сделать два существенных замечания.

Во-первых, «прозрачная защёлка» — это термин не для красоты, это такая штука, которая в Советской литературе обычно называлась D-триггер со статическим управлением. Не знаю зачем в документации на модуль USI написали, что эта защёлка предназначена для задержки изменения выхода на 1 такт (этим они всех запутали), на самом деле всё несколько сложнее. Работает прозрачная защёлка следующим образом: когда на входе тактирования (обычно обозначается C, но на нашей структурной схеме обозначен как LE) D-триггера висит 1 — он является «прозрачным» и состояние на его выходе повторяет состояние на входе, но когда на вход C приходит 0 — триггер запоминает установленное в этот момент на выходе состояние и хранит его до тех пор, пока вход тактирования снова не переключится в 1. Чтобы было понятнее — смотрим на рисунок ниже.

как работает прозрачная защёлка

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

Второе замечание касается прерываний. В доке написано, что сбросить флаги событий, по которым генерируются прерывания (USISIF, USIOIF) можно только записав единицу в соответствующие биты регистра USISR. То есть автоматически, при переходе по вектору прерывания, эти флаги сбрасываться не должны. Однако, проведённые эксперименты показывают, что флаги автоматически всё-таки сбрасываются.

Теперь давайте более подробно рассмотрим регистры модуля USI:

USIDR

регистр USIDR модуля USI

Сдвиговый регистр содержит принимаемые и передаваемые данные. Он доступен напрямую с шины данных и не имеет никакой буферизации.

Старший значащий бит этого регистра (MSB) может быть подключен к выводам DO или SDA, в зависимости от выбранного режима. К выводам он подключается не напрямую, а через «прозрачную» защёлку, о которой мы говорили выше. Стоит учитывать, что прозрачная защёлка работает так, как я описывал выше, только при выбранном внешнем тактировании (USICS1 = 1). При внутренних источниках тактирования (USICS1 = 0) эта защёлка всегда «прозрачна», независимо от входа C(LE), то есть, в этом случае, при изменении бита MSB состояние вывода DO/SDA тоже немедленно изменяется.

Считываются данные всегда только с пина DI/SDA, независимо от конфигурации модуля, при этом в младший бит (LSB) записывается считанное с линии DI/SDA значение.

USISR

регистр USISR модуля USI

Регистр USISR содержит флаги прерываний, статусов и значение счётчика.

Bit 7 — USISIF: Start Condition Interrupt Flag

Если для модуля USI установлен двухпроводный режим, то этот флаг устанавливается при обнаружении Start-условия. Если выбран трёхпроводный режим (USIWM1:USIWM0=0b01) или не выбран никакой режим (USIWM1:USIWM0=0b00) и при этом для сдвигового регистра и счётчика выбран внешний источник тактирования (USICS1=1, USICLK=0), то любой фронт на ноге SCK вызывает установку флага USISIF.

Прерывание по этому флагу генерируется в том случае, если установлен флаг USISIE в регистре USICR и установлен флаг GIE (global interrupt enable). Это прерывание способно «разбудить» контроллер из любого энергосберегающего режима, включая Power-Down.

В двухпроводном режиме установка флага USISIF приводит к удержанию на низком уровне линии тактирования (после того, как её уронит Master) до тех пор, пока флаг не будет сброшен.

Bit 6 — USIOIF: Counter Overflow Interrupt Flag

Флаг USIOIF устанавливается при переполнении 4-битного счётчика (при переключении значения счётчика из 0b1111 в 0b0000).

Прерывание по этому флагу генерируется в том случае, если установлен флаг USIOIE в регистре USICR и установлен флаг GIE (global interrupt enable). Это прерывание способно «разбудить» контроллер из энергосберегающего режима IDLE.

В двухпроводном режиме установка флага USIOIF может приводить (а может и не приводить, — зависит от настроек) к удержанию на низком уровне линии тактирования (после того, как её уронит Master) до тех пор, пока флаг не будет сброшен.

Bit 5 — USIPF: Stop Condition Flag

В двухпроводном режиме флаг USIPF устанавливается при обнаружении Stop-условия. Сбрасывается флаг записью единицы в бит USIPF. Прерывания по этому флагу не предусмотрены.

Bit 4 — USIDC: Data Output Collision

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

Bits 3:0 — USICNT3..0: Counter Value

Эти 4 бита отражают текущее значение счётчика. Счётчик может быть напрямую записан или прочитан программой.

Тактирование счётчика может производиться от трёх источников: пин USCK/SCL (внешний сигнал), переполнение таймера Timer0 и программа. Когда выбран внешний источник тактового сигнала — счётчик инкрементируется от обоих фронтов этого сигнала. Поскольку счётчик и сдвиговый регистр тактируются от одного и того же сигнала, то переполнение счётчика может расцениваться как сигнал о том, что сдвиговым регистром принято/передано нужное количество бит.

При выбранном внешнем тактовом сигнале есть специальная опция, позволяющая генерерировать строб (один такт) для счётчика установкой бита USITC. Эта опция включается записью единицы в бит USICLK при выбранном внешнем тактовом сигнале (USICS1=1).

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

USICR

регистр USICR модуля USI

Bit 7 — USISIE: Start Condition Interrupt Enable

Установка в 1 этого бита включает прерывание по обнаружению Start-условия (по установке флага USISIF). Прерывание немедленно будет исполнено как только все три необходимых флага (USISIF, USISIE и GIE) окажутся установлены в единицу (при отсутствии условий для исполнения более приоритетного прерывания).

Bit 6 — USIOIE: Counter Overflow Interrupt Enable

Установка в 1 этого бита включает прерывание по переполнению счётчика (по установке флага USIOIF). Прерывание немедленно будет исполнено как только все три необходимых флага (USIOIF, USIOIE и GIE) окажутся установлены в единицу (при отсутствии условий для исполнения более приоритетного прерывания).

Bits 5:4 — USIWM1..0: Wire Mode

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

Режимы работы модуля USI:

USIWM1 USIWM0 описание
0 0

Выходы, схема удержания линии тактирования и детектор Start-условия — выключены. Выводы порта функционируют в нормальном режиме.

0 1

Трёхпроводный режим. Использует пины DO, DI и USCK.

В этом режиме выход DO «перекрывает» состояние пина, задаваемое из регистра PORT. Однако, соответствующий бит регистра DDR всё ещё котролирует направление пина (вход/выход). Когда пин настроен как «вход» — регистр PORT управляет состоянием подтягивающих резисторов.

DI и USCK не влияют на нормальную работу порта. При работе в качестве Мастера, тактовые импульсы генерируются программно, переключением соответствующего бита в регистре PORT (при этом вывод должен быть настроен как «выход»). Для этой цели (переключение бита в регистре PORT) может быть использован бит USITC в регистре USICR.

В трёхпроводном режиме работа модуля USI соответствует интерфейсу SPI режимы 0 и 1), только без функциональности сигнала SS (такого сигнала в USI просто нет). Эту функциональность при необходимости придётся реализовывать программно.

1 0

Двухпроводный режим. Использует пины SDA и SCL.

Выводы SDA и SCL двунаправленные и используют выходы с открытым стоком. Выходные драйверы для них должны быть включены установкой в единицу соответствующих битов в регистре DDR.

Когда выходной драйвер для вывода SDA включен, он притягивает линию SDA к низкому уровню, если выход сдвигового регистра или соответствующий бит регистра PORT равен нулю. В противном случае линия SDA отпущена (в Z-состоянии). Всё то же самое касается и линии SCL, только она при включенном выходном драйвере (то есть когда линия настроена на выход) может дополнительно притягиваться к нулю детектором Start-условия.

Подтягивающие резисторы на линиях SDA, SCL в двухпроводном режиме отключены.

В этом режиме линия SCL удерживается на низком уровне при обнаружении Start-условия (после того, как её притянет к низкому уровню Master).

1 1

Двухпроводный режим. Использует пины SDA и SCL.

Этот режим полностью аналогичен предыдущему, за исключением того, что линия SCL дополнительно удерживается на низком уровне при переполнении счётчика (после того, как её притянет к низкому уровню Master).

Bits 3:2 — USICS1..0: Clock Source Select

Комбинация этих битов выбирает источник тактового сигнала для сдвигового регистра и счётчика. Все возможные варианты тактирования показаны в таблице ниже

USICS1 USICS0 USICLK Источник тактирования сдвигового регистра Источник тактирования счётчика
0 0 0 отсутствует отсутствует
0 0 1 Программа (бит USICLK) Программа (бит USICLK)
0 1 x Переполнение Timer0 Переполнение Timer0
1 0 0 Внешний, положительный фронт Внешний, оба фронта
1 1 0 Внешний, отрицательный фронт Внешний, оба фронта
1 0 1 Внешний, положительный фронт Программа (бит USITC)
1 0 1 Внешний, отрицательный фронт Программа (бит USITC)

Bit 1 — USICLK: Clock Strobe

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

Когда выбрано внешнее тактирование (USICS=1), назначение бита USICLK меняется, теперь вместо формирования строба, он определяет выбор источника тактирования для счётчика. В этом случае при установленном бите USICLK источником стробов для счётчика является бит USITC, а при сброшенном — фронты внешнего тактового сигнала.

При попытке прочитать бит USICLK всегда считывается 0.

Bit 0 — USITC: Toggle Clock Port Pin

Запись 1 в этот бит вызывает переключение бита в регистре PORT, соответствующего линии USCK/SCL (из 0 в 1 или из 1 в 0). Переключение не зависит от установки направления вывода в регистре DDR, однако если вы хотите чтобы значение, установленное в регистре PORT было реально представлено на выводе, — значение в регистре DDR должно быть установлено в 1 (выход). Эта фишка позволяет легко реализовать генерацию тактовой частоты при организации Master-устройства.

Когда выбрано внешнее тактирование (USICS1=1) и бит USICLK равен 1, запись единицы в бит USITC напрямую тактирует 4-битный счётчик. Это позволяет быстро определить конец передачи при работе в качестве Master-устройства.

При попытке прочитать бит USITC всегда считывается 0.

На этом пока всё, примеры будут чуть позже…

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