Продолжаем делать перевод документации фирмы Cypress на блоки UDB. Тем более, что всё очень удачно совпадает. Для продолжения практической статьи по UDB понадобится использование FIFO, а в теоретической части мы подобрались как раз к их описанию. Поэтому начинаем изучать их во всех деталях.
Режим | Описание |
Input/Output (Входной/выходной буфер) | В режиме входного буфера CPU или DMA записывают данные в FIFO, а Datapath считывает их. В режиме выходного буфера данные попадают в FIFO из Datapath, а считывает их оттуда CPU или DMA. |
Single Buffer (Одиночный буфер) | FIFO работает как одиночный буфер без статуса. Записанные в FIFO данные сразу доступны для чтения и могут быть перезаписаны в любое время. |
Level/Edge (Уровень/перепад) | Параметр, отвечающий за загрузку FIFO из Datapath, может инициироваться по уровню или по перепаду. |
Normal/Fast (Нормальный/быстрый) | Параметр, отвечающий за загрузку FIFO из источника Datapath: тактируется она с частотой выбранного для Datapath тактового источника (normal) или с частотой шины (fast). Это позволяет выполнять захват с наивысшей частотой в системе (частота шины), независимо от тактовой частоты Datapath. |
Software Capture (Программный захват) | Когда включен этот режим, а FIFO находится в режиме выходного буфера, чтение CPU или DMA связанного аккумулятора (A0 для F0, A1 для F1), инициализирует синхронную передачу значения аккумулятора в FIFO. Захваченное значение сразу доступно для чтения из FIFO. Если активирована поддержка связывания в цепочки, операция проследует по цепочке до блока MS, чтобы Datapath мог выполнить атомарное считывание многобайтовых значений. |
Asynch (Асинхронный) | Когда тактовые частоты Datapach и системной шины не синхронизированы, сигналы статуса FIFO могут быть проброшены на остальную часть Datapath либо напрямую, тактируясь от тактовой частоты Datapath, либо с двойной синхронизацией, в режиме Asynch. |
Independent Clock Polarity (Независимая тактовая полярность) | Каждый FIFO имеет управляющий бит для инвертирования полярности тактового сигнала FIFO по отношению к тактированию Datapath. |
На рисунке 21-7 показаны возможные варианты конфигурации пары FIFO, в зависимости от выбранных для каждого из них режимов Input/Output. Если один FIFO находится во входном режиме, а другой в выходном, получаем конфигурацию RX/TX. Типичный пример, где нужна такая конфигурация, контроллер шины SPI. В конфигурации Dual Capture (оба FIFO настроены на выход) обеспечивается независимый захват пары A0 и A1 или два независимых захвата регистров A0 или A1. Наконец, в режиме Dual Buffer (оба на вход) возможно использование для загрузки или сравнения как регистровой пары, так и двух независимых регистров.
Рисунок 21-7. Конфигурации FIFO.
Рисунок 21-8. Источники и приемники FIFO.
Когда FIFO работает в режиме входного буфера, источником является системная шина, а приемниками – регистры Dx и Ax. При работе в режиме выходного буфера, источниками являются регистры Ax и ALU, а приемником – системная шина. Выбор мультиплексора задан статически в регистре конфигурации UDB CFG15, как показано в таблице для F0_INSEL[1:0] или F1_INSEL[1:0]:
Fx_INSEL[1:0] | Описание |
00 | Режим входного буфера: системная шина записывает в FIFO, а приемником FIFO является Ax или Dx. |
01 | Режим выходного буфера: источником FIFO является А0, а приемником FIFO – системная шина. |
10 | Режим выходного буфера: источником FIFO является A1, а приемником FIFO – системная шина. |
11 | Режим выходного буфера: источником FIFO является выход ALU, а приемником FIFO – системная шина. |
Каждый FIFO вырабатывает два сигнала статуса, «bus» и «block», которые передаются на трассировочные ресурсы UDB через выходной мультиплексор Datapath. Статус «bus» можно использовать для взведения прерывания или запроса DMA чтения/записи в FIFO. Состояние «block» в основном предназначается для передачи состояния FIFO на внутренние сущности UDB. назначение битов статуса зависят от сконфигурированного направления (Fx_INSEL[1:0]), и битов уровня FIFO. Биты уровня FIFO (Fx_LVL) устанавливаются в регистре Auxiliary Control в пространстве рабочих регистров. Варианты статусов показаны в следующей таблице:
Fx_INSEL[1:0] | Fx_LVL | Состояние | Сигнал | Описание |
Ввод | 0 | Не полон | Статус «Bus» | Взводится, когда в FIFO есть место хотя бы для одного байта. |
Ввод | 1 | Опустошен как минимум наполовину | Статус «Bus» | Взводится, когда в FIFO есть место хотя бы для 2 байтов. |
Ввод | Н/Д | Пуст | Статус «Block» | Взводится, когда в FIFO нет ни одного байта. Когда FIFO не пуст, Datapath может считывать байты. Когда FIFO пуст, Datapath может находиться в состоянии ожидания либо сгенерировать состояние опустошения. |
Вывод | 0 | Не пуст | Статус «Bus» | Взводится, когда в FIFO доступен хотя бы 1 байт для чтения. |
Вывод | 1 | Заполнен как минимум наполовину | Статус «Bus» | Взводится, когда в FIFO доступны хотя бы 2 байта для чтения. |
Вывод | Н/Д | Полон | Статус «Block» | Взводится, когда FIFO полон. Когда FIFO не полон, Datapath может записывать байты в FIFO. Когда FIFO полон, Datapath может находиться в состоянии ожидания или сгенерировать условие переполнения. |
Рисунок 21-9 показывает типичную последовательность чтения и записи, а также генерации связанных с этими операциями статусов. На рисунке чтение и запись происходят в разное время, однако они могут выполняться и одновременно.
Рисунок 21-9 Работа приемников FIFO.
Когда FIFO работает в режиме выходного буфера, операция загрузки FIFO обычно использует тактовую частоту выбранного Datapath для тактирования сигнала записи. Как показано на рисунке 21-10, при выборе быстрого режима FIFO (FIFO FAST) для этой конкретной операции можно выбрать частоту шины. При использовании совместно с режимом Level/Edge = Edge, эта операция позволяет уменьшить задержку передачи из аккумулятора в FIFO с периода тактовой частоты Datapath до периода тактовой частоты шины, так как у шины частота может быть гораздо выше. Это позволяет CPU или DMA считывать полученный результат FIFO с минимальной задержкой.
Как показано на рисунке 21-10, операция быстрой загрузки выполняется независимо от текущего тактирования Datapath, однако использование тактовой частоты шины может повысить энергопотребление.
Рисунок 21-10. Приемники быстрой конфигурации FIFO.
Существуют два режима записи в FIFO из Datapath. В первом режиме данные синхронно передаются из аккумуляторов в FIFO. Управляющий сигнал этой записи (FX_LD) обычно формируется конечным автоматом или синхронизированным с тактированием Datapath условием. Запись в FIFO будет проводиться в любом цикле, в котором управляющий сигнал загрузки ввода равен ‘1’. Во втором режиме FIFO используется для захвата значений аккумулятора в ответ на положительный перепад сигнала FX_LD. В этом режиме формат сигнала сигнала является произвольным (однако его период должен быть равен как минимум одному циклу тактирования Datapath). Примером этого режима является захват значения аккумулятора при помощи входа внешней ножки в качестве триггера. Ограничением этого режима является то, что параметр входа должен возвращаться к значению ‘0’ как минимум за один цикл до обнаружения другого положительного перепада.
На рисунке 21-11 показана реализация режима обнаружения перепада на входе FX_LD. Режим обоих FIFO в UDB управляются одним и тем же битом, переключающим данную опцию. Обратите внимание, что обнаружение перепада тактируется с частотой, равной частоте выбранного FIFO.
Рисунок 21-11. Обнаружение перепада для внутренних приемников записи FIFO.
Распространенным и важным требованием является обеспечение возможности для CPU и DMA надежно считывать содержимое аккумулятора во время нормальной работы. Это делается при помощи программного захвата и включается при помощи бита конфигурации FIFO Cap. Этот бит применяется к обоим FIFO в UDB, но работает, только когда FIFO находится в режиме выходного буфера. При использовании программного захвата F0 должен считывать из A0, а F1 из A1.
Как показано на рисунке 21-12, чтение аккумулятора инициирует запись в FIFO из аккумулятора. Сигнал связывается в цепочку, чтобы чтение конкретного байта одновременно захватывало значения аккумуляторов всех UDB в цепочке. Это позволяет 8-битному процессору успешно считывать одновременно 16 битов или больше. Данные, возвращенные при чтении аккумулятора, должны игнорироваться, а захваченное значение может быть сразу доступно для чтения из FIFO.
Трассированный сигнал FX_LD, который генерирует загрузку FIFO, направляется на терм OR вместе с сигналом программного захвата. Когда одновременно используются аппаратный и программный захват, результат может быть непредсказуем. Как правило, эти функции должны быть взаимоисключающими, однако аппаратный и программный захват можно использовать одновременно, при следующих условиях:
При описанных выше условиях аппаратный и программный захват работают, по сути, одинаково, и во время любого цикла тактирования шины любой из этих сигналов может инициировать захват.
Также рекомендуется очищать целевой FIFO в программном коде (регистр ACTL) до начала программного захвата. Благодаря этому указатели на чтение и запись FIFO будут установлены в известное состояние.
Рисунок 21-12. Конфигурация программного захвата.
Честно говоря, я до конца не понимаю всей глубины смысла этого раздела. Возможно, кто-то пояснит суть в комментариях. Но создаётся стойкое впечатление, что это в первую очередь, предназначено для того, чтобы дать возможность 8-битному процессорному ядру успеть считать содержимое аккумулятора большей разрядности. Такие ядра используются в PSoC-3. В результате, содержимое аккумулятора атомарно перескакивает в FIFO, после чего содержимое последнего можно спокойно вычитывать за 2 или более тактов (чтобы прокачать 16 или 32 бит, плюс в MCS-51 операции будут вестись отдельными командами, на которые также будут потрачены такты), не боясь, что оно будет изменено. А для ARM ядер, похоже, что это не более, чем ненужный рудимент.
В регистре Auxiliary Control, который может быть использован для управления FIFO во время нормальной работы, содержится 4 бита.
Биты FIFO0 CLR и FIFO1 CLR используются для сброса или очистки FIFO. Когда одному из этих битов присваивается значение ‘1’, связанный с ним FIFO сбрасывается. Бит должен быть восстановлен в исходное значение (‘0’), чтобы FIFO продолжил работу. Если значение бита останется равным единице, соответствующий FIFO будет отключен и будет работать как однобайтный буфер без статуса. Данные могут быть записаны в FIFO, данные сразу доступны для чтения и могут быть перезаписаны в любое время. Направление данных при помощи битов конфигурации FX INSEL[1:0] все еще можно задавать.
Биты FIFO0 LVL и FIFO1 LVL определяют уровень, при котором FIFO взведёт статусный бит «bus» (когда шина читает или пишет в FIFO). То есть, состояние статуса «bus» зависит от заданного направления, как показано в таблице ниже.
FIFO LVL | Режим входного буфера (шина записывает в FIFO) | Режим выходного буфера (шина читает из FIFO) |
0 |
Не полон Может быть записан как минимум 1 байт |
Не пуст Может быть считан как минимум 1 байт |
1 |
Опустошен как минимум наполовину Могут быть записаны как минимум 2 байта |
Заполнен как минимум наполовину Могут быть считаны как минимум 2 байта |
Рисунок 21-13 показывает принцип асинхронной работы FIFO. В качестве примера представим, что F0 работает в режиме входного буфера, а F1 в режиме выходного буфера, что является типичной конфигурацией TX и RX регистров.
Рисунок 21-13. Асинхронная работа FIFO.
На стороне TX конечный автомат Datapath использует флаг Empty, чтобы определить, есть ли доступные для получения байты. Значение Empty устанавливается синхронно с конечным автоматом Datapath, а очищается асинхронно из-за записи из шины. После очистки статус снова синхронизируется с конечным автоматом Datapath.
На стороне RX конечный автомат RX использует Full, чтобы определить есть ли свободное пространство для записи в FIFO. Значение Full устанавливается синхронно с конечным автоматом Datapath, а очищается асинхронно из-за чтения шиной. После очистки статус снова синхронизируется с конечным автоматом Datapath.
Один бит FIFO ASYNCH используется для включения этого метода синхронизации, после активации этот метод применяется к обоим FIFO.
Он применяется только к статусу Block, так как предполагается, что статус Bus естественным образом синхронизируется процессом прерывания.
ASYNC | ADD SYNC | Операция | Модель использования |
0 | 0 | Синхронно с тактированием шины | Изменения статуса записи/чтения CPU происходят на частоте шины. Можно использовать для минимальной задержки, если удается достичь частоты тактирования Datapatch, равного частоте шине. |
0 | 1 | Пересинхронизация с частоты шины на частоту Datapath. | Этот режим должен быть режимом работы по умолчанию. Когда CPU выполняет операции чтения/записи, изменение статуса будет пересинхронизировано с частотой, используемой в Datapath. Даёт возможность использовать полный период частоты Datapath для установки сигнала для логики UDB. |
1 | 0 | Зарезервировано | — |
1 | 1 | Двойная синхронизация частоты шины на частоту Datapath. | Когда тактовые импульсы для Datapath не только не синхронизированы с системными по частоте, но и вырабатываются отдельным независимым генератором, этот параметр может быть использован для двойной синхронизации операций чтения и записи CPU с тактированием Datapath. |
Переполнение FIFO при работе
Для безопасной реализации внутренних (Datapath) и внешних (CPU или DMA) операций чтения и записи следует использовать сигналы статуса FIFO. От условий опустошения и переполнения нет встроенной защиты. Если FIFO полон, а последующие операции записи выполняются (переполнение), новые данные перезаписывают начало FIFO (данные, который на данный момент выводятся, и являются следующими в очереди на чтение). Если FIFO пуст, а последующие операции чтения выполняются (опустошения или истощения), считываемое значение не определено. Указатели FIFO сохраняют точность вне зависимости от незаполнения и переполнения.
Инверсия тактирования FIFO
Каждый FIFO имеет бит управления Fx CK INV, который отвечает за полярность тактирования FIFO Относительно полярности тактирования Datapath. По умолчанию, FIFO работает с той же полярностью что и тактирование Datapath. Когда этот бит равен 1, FIFO работает с обратной полярностью относительно Datapath. Это обеспечивает поддержку протоколов, обменивающимися данными по обоим фронтам, например, SPI.
Динамическое управление FIFO
Обычно FIFO конфигурируются статически либо в режим входного буфера, либо в режим выходного буфера. В качестве альтернативы каждый FIFO можно настроить на работу в режиме, в котором направление контролируется динамически (под воздействием внешних сигналов). Один бит конфигурации на каждый FIFO (Fx DYN) отвечает за активацию этого режима. Рисунок 21-14 показывает конфигурации, доступные в динамическом режиме FIFO.
Рисунок 21-14. Динамический режим FIFO.
В режиме внутреннего доступа (Internal Access) Datapath может считывать и записывать в FIFO. В этой конфигурации, чтобы выбирать источник операций записи в FIFO, биты Fx INSEL должны иметь значение 1. Fx INSEL = 0 (источник шины CPU) в этом режиме некорректен, он может принимать только значения 1, 2 или 3 (A0, A1 или ALU). Стоит заметить, что чтение имеет доступ только к соответствующему аккумулятору, направление регистров данных в этом режиме недоступно.
В режиме внешнего доступа (External Access) CPU или DMA могут как считывать, так и записывать в FIFO.
Конфигурация динамически переключается между внешним и внутренним доступом при помощи проброса сигналов от Datapath. Для этого используются входные сигналы Datapath d0_load и d1_load. Стоит заметить, что в режиме динамического управления d0_load и d1_load недоступны для их нормального использования при загрузке регистров D0/D1 из F0/F1. Сигналы dx_load могут быть вызваны любым трассировочным сигналом, включая константы.
Рассмотрим пример, в котором, начиная с внешнего доступа (dx_load == 1), CPU или DMA могут записывать один или несколько байтов данных в FIFO. Затем, при переключении на внутренний доступ (dx_load == 0), Datapath может выполнять операции над данными. После этого, при переключении на внешний доступ, CPU или DMA могут считать результат вычислений.
Так как Fx INSEL всегда должен быть равен 01, 10 или 11 (A0, A1 или ALU), что соответствует «режиму выходного буфера» при нормальной работе, сигналы статуса FIFO имеют следующие определения (в зависимости от параметра Fx LVL):
Сигнал статуса | Значение | Fx LVL = 0 | Fx LVL = 1 |
fx_blk_stat | Статус записи | FIFO полон | FIFO полон |
fx_bus_stat | Статус чтения | FIFO не полон | Заполнен как минимум наполовину |
Так как и Datapath и CPU могут записывать и считывать из FIFO, эти сигналы больше не считаются статусами «block» и «bus». Сигнал blk_stat используется для статуса записи, а сигнал bus_stat для статуса чтения.
Существует четыре сигнала статуса FIFO, по два для каждого FIFO: fifo0_bus_stat, fifo0_blk_stat, fifo1_bus_stat и fifo1_blk_stat. Значение этих сигналов зависит от направления конкретного FIFO, которое определено статической конфигурацией. Статус FIFO подробно описан в разделе 21.3.2.2 Datapath FIFO.