Пример цифровой системы с несколькими тактовыми частотами.

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

Архитектура видеоадаптера
Хочу рассказать об одном проекте, в котором я принимал участие – разработка PCI видеоадаптера. Вот тут используется несколько тактовых частот в одном проекте.

Когда работаешь над таким сложным проектом, то понимаешь, что без нескольких тактовых частот никак не обойтись. Как минимум есть три не связанных частоты:
  1. Частота шины PCI, 33Mhz. Данные передаются четырехбайтовыми словами, таким образом, теоретический недостижимый максимум скорости передачи по шине 33*4~132Мб/сек. Недостижимый максимум, потому, что кроме собственно передачи данных есть еще потери тактов в начале и конце фреймов PCI, возможно прекращение передачи по команде арбитра шины или возможны такты ожидания, вставляемые самим устройством.
  2. Частота, на которой работает память DDR, 133Mhz. При использовании 16-ти битной микросхемы DDR (Double Data Rate) скорость передачи 2*2*133~532Мб/сек (кстати так же недостижимая). Память хранит образ картинки, отображаемой на экране. Чтобы изображение появилось на экране монитора программа, исполняемая центральным процессором, должна записать в память видеоадаптера (framebuffer) все пиксели этого изображения. Записываемые данные поступают через шину PCI блоками по несколько слов (burst).
  3. Частота с которой идет отображение пикселей на экране, PixelClock, 108Mhz для видео режима 1280х1024, 60Hz. В режиме TrueColor (байт на каждый цвет: красный, зеленый синий) видеоконтроллер должен читать из памяти со скоростью 3*108~324Мб/сек. Если потребуется сделать видеоадаптер, у которого можно переключать видеорежимы, то тогда нужно перепрограммировать PixelClock и требования по пропускной способности памяти будут другими. Видеоконтроллер считывает из памяти фреймбуффера пикселы и, синхронно с разверткой видео, выдает их монитору. Активность видеоконтроллера по доступу к видеопамяти меньше во время строчных и кадровых синхроимпульсов.

В всяком случае видно, что есть два агента (контроллер PCI и видеоконтроллер), конкурирующие за доступ к общей памяти через контроллер DDR, и все три модуля работают на своих частотах.  Как организовать их совместную работу?

К счастью, есть довольно простое решение – использование асинхронного FIFO.
Модуль FIFO  (First In, First Out) - это канал передачи данных между «передатчиком» и «приемником», где каждый новый элемент передаваемых данных ставится в хвост очереди, а при считывании выбираются элементы данных из головы очереди. Очередь может расти и сокращаться в зависимости от активности передатчика или приемника. Асинхронное FIFO в добавок ко всему прочему позволяют добавлять и выбирать элементы очереди с разной скоростью (с использованием различной тактовой частоты). Конечно нужно следить, чтобы элементы не выбирались из пустой очереди и чтобы нельзя было добавить элементы в полную очередь.

Применительно к видеоадаптеру более точно его архитектура может выглядеть как-то вот так:

Архитектура видеоадаптера

Получается вот что:

  1. Видеоконтроллер читает из FIFO2 пикселы с постоянной скоростью развертки (за исключением времени кадровых и строчных импульсов). Так FIFO2 опустошается.
  2. Так же, видеоконтроллер следит за количеством данных имеющихся в очереди FIFO2. Если данных становится слишком мало (меньше некоторого порога), то выдается запрос контроллеру памяти на чтение очередной порции пикселов из памяти фреймбуффера.
  3. Видеоконтроллер будет читать из памяти и наполнять FIFO2, пока количество данных там не превысит некоторое пороговое значение. Затем контроллер памяти освобождается и может выполнять какую-то другую работу.
  4. Даже если контроллер памяти DDR в данный момент времени занят чтением пикселей из памяти для отображения на экране монитора, пользовательская программа все равно может тем временем «писать в видеопамять» через шину PCI. На самом деле записанные данные пока просто накапливаются в FIFO1. Пока FIFO1 не заполнилось полностью можно писать в видеоадаптер на полной скорости шины PCI. Если же оно заполнится полностью, то придется вставлять такты ожидания на шине. В идеале такого не должно случаться никогда.
  5. Когда контроллер памяти освобождается (больше нет необходимости читать данные в FIFO2 для видеоконтроллера) он может приступить к выборке накопленных данных FIFO1 и записи их в видеопамять. Контроллер памяти практически в 4 раза быстрее чем шина PCI, поэтому он с легкостью опустошит FIFO1 даже если пользовательская программа продолжает «рисовать в памяти экрана» наполняя это же самое FIFO1.

В среде Altera Quartus II нет необходимости изобретать велосипед, реализуя свой собственный модуль FIFO. Можно взять готовый альтеровский компонент, настроить его параметры и поставить в свой проект.

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

В среде Altera Quartus II можно создать свой собственный экземпляр FIFO с помощью MegaWizard Plug-In Manager из меню Tools.

MegaWizard Plug-In Manager, FIFO

При создании собственного варианта FIFO в этом диалоге можно задавать всякие возможные параметры. Можно задавать:

  1. Разрядность слов, хранимых в FIFO (How wide should FIFO be?).
  2. Количество слов в очереди FIFO (How deep should FIFO be?).
  3. Тип тактовых частот на запись и на чтение, синхронные ли они? (Do you want a common clock…?) Для нашего примера видеоадаптера важно получить раздельные частоты для чтения (rdclk) и записи (wrclk).
  4. Еще есть опция определяющая синхронность тактовых частот (Are the FIFO clocks synchronized?)

Обратите внимание, что теоретически для некоторых задач частоты могут быть различными, но тем не менее синхронными. Это получается если частоты точно кратны (например 33Mhz и 66Mhz) и синфазны (фронты совпадают).

К сожалению это не наш случай. Даже если посмотреть на картинку архитектуры видеоадаптера можно заметить, что на шине PCI 33Mhz, а контроллер памяти работает на частоте 133Mhz. Все равно это не тот случай, эти частоты не синхронны. У этих частот разная природа. Частота на шине PCI определяется чипсетом материнской платы. Во-первых, чипсеты бывали разные чудные, вплоть до того, что позволяют менять частоту на шине в некоторых пределах. Во-вторых, частота на шине PCI может немного «плавать» при включенной опции биоса чипсета «spread spectrum» (возможно в современных компьютерах это все уже не актуально, все таки PCI довольно устаревшая шина). Частота же видеоконтроллера всегда определается генератором на плате видеоадаптера. Таким образом, эти частоты никак не связаны.

Далее в визарде можно задавать дополнительные параметры:

MegaWizard Plug-In Manager, FIFO

Мы можем потребовать наличие дополнительных информационных сигналов таких, как:

  1. full – очередь FIFO полностью заполнена.
  2. empty – FIFO пусто, в нем нет ни одного элемента данных.
  3. usedw[] – количество элементов, которое в данный момент находятся в очереди.

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

И вот то, что очень важно: внутри создаваемого компонента асинхронного FIFO уже автоматически будут созданы все нужные синхронизаторы для пересечения данных и управляющих сигналов в разные clock domain. Как я уже писал сделать это не очень просто, особенно, когда нужно провести группу сигналов от одной частоты к другой, но это уже сделано для нас.

Наверное дальше нужно будет описать принципы реализации асинхронного FIFO и методы преодоления в нем проблемы Сlock Domain Cross. Возможно я напишу отдельную статью про это.

 

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