Всем привет! Не так давно мы приступили к созданию стенда для тестирования модулей цифровой обработки сигнала. Предполагается, что всякое вновь разрабатываемое устройство будет не просто подвергаться моделированию, а будет проходить более жесткий контроль через работу на реальной железке. Продолжаем идти в этом направлении...
Поворот не туда
При разработке первого варианта кольцевого буфера преследовалась цель показать основной принцип работы. Если по простому, то это буфер между пишущим и читающими модулями.
Для того, чтобы они смогли взаимодействовать, необходимо реализовать двухпортовую память и механизм записи и чтения данных из нее.
Наиболее простой механизм разделения всего адресного пространства памяти на 2 половины (верхняя и нижняя) хорош для учебных целей. Пока пишущий модуль занимается сохранением данных в одну половину, читающий занят выборкой данных из другой половины. Никто никому не мешает. Нет ничего проще, чем контроль перехода адресов (на запись и чтение) через границу и выставление или уборка соответствующего сигнала о готовности или не готовности данных.
Однако, с учебным кольцевым буфером не все так ладно. Он выполняет свою задачу только в том случае, если запись идет медленнее, чем чтение. При незаполненности половинки - сигнала о готовности нет, значит читающий модуль ожидает. Как только половинка готова, модуль чтения бросается забирать данные, а в это время пишется вторая половинка.
На картинке выше результат моделирование такого FIFO, которое хранит данные, пришедшие по медленному интерфейсу RS-232. Обратите внимание, что большую часть времени быстрая система ЦОС в лице интегратора простаивает в ожидании данных. Это видно по ступенчатому накоплению результата на выходе интегратора (y). Только при готовности данных в буфере срабатывают пачки импульсов на линии clk.
Для случая, когда пишущий модуль работает быстро, а читающий медленно, такая схема уже не работает. В наших планах передавать в компьютер результаты вычислений системы цифровой обработки сигнала (ЦОС) при помощи довольно медленного интерфейса RS-232. Очевидно, пора взять на вооружение FIFO подходящей конструкции.
Одна важная деталь
Как вы понимаете, конструкций FIFO буферов множество. Для самых различных жизненных ситуаций нашему вниманию предлагаются двунаправленные FIFO, а также буферы с приоритетами, где очередь может совсем не соблюдается (совсем как в жизни). Но из тех простых, что подходят для нашей задачи есть, так называемые, SCFIFO и DCFIFO. Не нужно пугаться, SCFIFO это синхронный буфер, он же с одной тактовой линией (читатель и писатель на одной тактовой частоте),а DCFIFO с двумя тактовыми линиями.
По первым двум буквам видно отличие: SC - single clock (одна тактовая линия), DC - dual clock (две тактовые линии).
У этих кольцевых буферов FIFO много общего. В каждый из буферов входят данные (data). Разумеется, они и выходят (q). Запрос на запись данных поступает по линии wrreq, запрос на чтение по линии rdreq. Эти линии запросов не дадут буферу записать данные, если они еще не готовы и выдать их, если необходимости в них еще не было. Несколько линий на выходе этих модулей сигнализируют о предельной загрузке буфера (full), отсутствии данных (empty). Значение остальных линий и шин (если они есть) можно узнать из документации.
Принцип работы
Сразу хочется предупредить, что досконально работу всех частей и механизмов таких модулей мы не рассмотрим. Однако, для общего понимания пару слов все-же будет сказано.
Как уже было сказано, центральным узлом FIFO буфера является двухпортовая память, один из портов предназначен для записи данных, другой для их чтения. На схеме ниже такая память обозначена как FIFO Memory (Dual Port RAM).
Обязательным условием является наличие двух счетчиков адреса. Один (wptr) подсчитывает адрес ячейки памяти (waddr), предназначенной для записи данных . Другой счетчик (rptr) ведет подсчет адреса ячейки (raddr), где хранится слово данных для чтения. Эти счетчики находятся во взаимодействии друг с другом с помощью линий wptr и rptr. Основное назначение этого взаимодействия это полный контроль над ситуацией. А ситуации, как известно, бывают разные.
При отсутствии данных буфере читателю выводится сигнал rempty. Это предохраняет от ошибочного чтения несуществующих данных. Для недопущения переполнения буфера модулю-писателю поступает сигнал wfull. Это приостановит поступление новых данных. Судя по синхронизирующим триггерам, проблема взаимодействия всех частей буфера между собой далеко не так проста, как может показаться на первый взгляд.
OpenSource модули - для того чтобы их использовали
Разрабатывать все то, что уже давно написано это занятие больше тренировочное. У нас пока цель немного другая - собираем испытательный стенд. Не нужно стесняться брать в пользование то, что для этого выкладывается в открытый доступ. Тем самым мы не обижаем авторов, а даже напротив, делаем им комплимент. По запросу поисковой системы готовые модули чаще всего находятся на GitHub.com и opencores.org, хотя и других ресурсов хватает. За кольцевой буфер DCFIFO наше спасибо отправляется автору Damien Pretet)
По ссылке выше лежит неплохой проект (async_fifo), это стало понятно после сборки и моделирования.
При скорости записи выше скорости чтения свободная память постепенно исчезает. Указатель (адрес) записи бежит по кругу от младших адресов к старшим и догоняет медленный указатель чтения. При этом на выход выставляется предупреждающий сигнал о переполнении.
При непринятии своевременных мер и продолжении записи, сигнал переполнения исчезает, но при этом неизбежна потеря данных. Сигнал переполнения это всего лишь разность чисел между указателями записи и чтения. Благо, что он появляется заранее и очевидно, что его обязательно нужно обрабатывать.
Теперь другая ситуация. Запись идет медленно, а считывание происходит быстро. При моделировании дадим памяти слегка заполниться путем запрета считываний, а потом их разрешим.
Довольно быстро адрес на чтение догоняет адрес на запись и происходит то, что должно было произойти: появляется сигнал об отсутствии данных. Этот сигнал необходимо обрабатывать модулю чтения по той простой причине, что на шине данных буфера будет какое-то число, но это совсем не валидные данные. Считывание с буфера в момент сигнала empty будет ошибочным.
По всей видимости, мы нашли что искали, осталось собрать и протестировать испытательный стенд. Делать это мы будем в следующих выпусках. До новых встреч!
Поддержите статью лайком если понравилось и подпишитесь чтобы ничего не пропускать.
Также не обойдите вниманием канал на YouTube. Подписки и лайки будут приятным ответом от аудитории.