Видео в конце...
Всем привет! Лето окончательно пролетело и пора постепенно входить в форму. Сегодня разминаем пальцы в среде разработки и задачка будет очень даже стоящая нашего внимания.
Напоминаю, что на этом канале через разработку простейших устройств, являющихся частью сложных систем, мы осваиваем язык описания цифровых устройств Verilog (пока что), сталкиваемся с типичными проблемами в разработке, находим решение этих проблем, пожалуй, как нигде более проникаем в подробности работы технологий и, наконец, отвечаем на самый частый вопрос - Как это работает?
Почему столько разрядностей данных?
Как мы помним, в информационных системах только однобитовая информация (да/нет) является огромной редкостью. Чаще всего отдельные биты информации собираются в слова с количеством N бит в каждом.
Процессоры, являющиеся частью информационных систем работают с двоичными словами и разрядность этих слов может быть от 4 до 64 бит.
Отдельные модули современных процессоров могут оперировать и с длинными (512 бит) словами.
Эти самые процессоры и прочие чипы работают с самой разнообразной информацией.
Аналого-цифровые преобразователи (АЦП) создают цифровые данные, где от разрядности слов напрямую зависит точность вычислений. Более подробно с этим можно ознакомиться в статье "Низкоскоростной био-АЦП".
Видеокамеры, в зависимости от своей стоимости и сложности, могут выдавать в вычислительные системы информацию о состоянии цвета каждого пикселя изображения.
Например, в 16-битном формате на красную составляющую цвета выделяется 5 бит, на зеленую - 6 и на синюю снова 5. При обработке изображения на ПЛИС необходимо разделять эти составляющие и вполне возможно при этом формировать шины данных таких специфических разрядностей.
Не будем забывать, что существуют средства вывода информации и одно из самых простейших потребует двоичные слова, разрядность которых 4 или 8 бит.
Очевидно, с таким богатым набором разрядностей устройств и данных у нас наверняка возникнет проблема как совместить в одном проекте шины данных с различной разрядностью.
Что будем делать?
Не будем рассматривать простейшие случаи, когда нет причин бороться за какую-либо экономию и можно поступать крайне топорно и просто. Например, очень топорным решением можно назвать передачу кадра изображения с видеокамеры через интерфейс RS-232, когда каждую составляющую цвета можно уложить в шину 8 бит. Как правило, разрабатываемые контроллеры этого асинхронного последовательно интерфейса требуют за раз 8 бит информации. Вот берем и топорно отдаем в младшие биты байта по очереди 5,6 и 5 бит. Для понимания, также, смотрите выпуск с канала на YouTube.
Давайте рассматривать сложный случай. Например, на вычислительном модуле происходит обработка 16-битных данных, но связь компьютера с модулем происходит через контроллеры интерфейса RS-232, а они работают с 8-битными данными.
Первая мысль - переписать контроллеры интерфейса для работы с 16-битными данными и тогда сопрягать шины разной разрядности не прийдется. Но вот какой вопрос - а сколько различных контроллеров в таком случае нам понадобиться для дальнейших разработок? Контроллер должен быть константой и иметь лишь возможности для настройки отдельных параметров. Плохая идея, однозначно.
Мы будем заниматься созданием средства сопряжения 8-битного интерфейса передачи данных и 16-битного интерфейса обработки этих самых данных.
Постановка задачи
Отсчеты оцифрованного звукового сигнала, разрядностью 16 бит побайтно отправляются на аппаратную платформу. Контроллер асинхронного интерфейса передачи данных забирает из канала передачи данных по линии rx принятый байт (8 бит) и выставляет его на шине data.
При готовности данных на шине выставляется высокий уровень сигнала на линии dataReady.
На аппаратной платформе реализован интегратор, разрядностью 16 бит. Его мы разработали ранее. Данные приходят через шину x, а выходят через y.
После обработки 16-битных данных результат должен поступить на передающую часть контроллера RS-232. Разрядность ее 8 бит.
Байты на отправку подаются через шину data, при готовности данных на линии dataReady появляется высокий уровень. Фрейм из последовательности бит передается с линии tx, готовность к передаче следующего фрейма обозначается высоким уровнем на линии rts.
Необходимо разработать дополнительную логику, позволяющую перевести данные из 8-битного формата в 16-битный, а потом передать обратно в компьютер каждое 16-битное слово в 2 подхода по 8 бит.
Решение задачи. Собираем слово по частям.
Задача поставлена предельно четко и необходимо ее решать. В последовательном канале асинхронного интерфейса RS-232 передаются фреймы, каждый и которых переносит 1 байт (8 бит). Слово из 16 бит содержит старший и младший байт, Поэтому, перед подачей 16-битного слова на интегратор его нужно достать из фреймов по частям. Это значит, что сперва достается младший байт, сохраняется во временном регистре, а потом изымается старший байт. Начиная с этого момента 16 битное слово готово к обработке.
assign dataIn = {data8In, sampleLow};
На словах все просто, но еще не забыт печальный опыт гонки сигналов, о котором было рассказано в этом видео.
Как мантру повторяем
рецепт хорошей жизни разработчика ПЛИС - фронт тактового импульса держим подальше от границ смены состояний линий на шине.
Теперь давайте делать все качественно с самого начала.
Приемник информации из RS-232 сразу (одновременно с данными на data) выставляет высокий уровень на линии готовности байта (dataReady), как только этот самый байт готов.
В этом кроется потенциальная опасность. Следующий за приемником модуль может считать байт неверно потому как по переднему фронту на линии готовности состояния не всех линий на шине могут быть окончательно установлены. Не обязательно это должно произойти, но вероятность есть. Поэтому защищаемся от потенциальной ошибки, работая по спаду сигнала готовности байта.
Один из байтов (младший) должен отправляться на временное хранение в регистр, второй не обязательно. Происходит такая картина каждый нечетный фрейм (или четный, смотря как сделаете). Для определения таких моментов необходим счетчик до 1 (от 0). Этот счетчик может управлять записью в регистр.
Посмотрим на рисунке до чего мы уже додумались.
Смотрите внимательно, младший байт ложится на хранение во временный регистр, старший выставляется на шине модуля приема по следующему заднему фронту и только после этого передний фронт dataReady точно может гарантировать целостность слова данных. Далее цикл повторится для следующих 16-битных слов.
Обратите внимание на то, что отправка слова на обработку (зеленая точка переднего фронта) должна происходить не каждый передний фронт, а через раз. Это достигается введением в схему еще одного счетчика до 1.
Теперь разбираем слово на байты
Дамы и господа, к этому моменту 16-битное слово обработано интегратором и пришло время отправить результат обратно в компьютер. Модуль отправки данных по RS-232 принимает только 8-битные слова. Разбиваем 16 бит на 2 по 8 и делаем это при помощи мультиплексора.
Мультиплексор, как устройство был рассмотрен в этой статье. У этого мультиплексора входы и выходы 8-битные, но принцип един. Осталось разобраться чем управлять процессом мультиплексирования. Управляют им те же самые счетчики до 1.
assign data8out = cntS[0] ? dataOut[15:8]: dataOut[7:0];
Текста получилось довольно много, поэтому если еще привести полный исходный код, то процент дочитываний явно упадет) Пишите в комментариях о своих способах сопряжения шин. В следующем выпуске поработаем еще над этим проектом, возможно, стоит сразу рассмотреть вариант с буферизацией данных. Все прелести этого решения были рассмотрены в этой статье.
Поддержите статью лайком если понравилось и подпишитесь чтобы ничего не пропускать.
Также не обойдите вниманием канал на YouTube. Подписки и лайки будут приятным ответом от аудитории.