Лайфхак по разработке DMR на ПЛИС через генерацию HDL-кода в MATLAB
Однажды мне прилетела задача реализовать DMR на ПЛИС. Опустившись на дно интернета, я нашел лишь мануал ETSI и пару примеров по генерации кода – с этого начался мой тернистый путь изучения данной тематики. Недавно наткнулся на мем, и тут нахлынули воспоминания. Решил, дабы сэкономить время людей, которые столкнутся с чем-то подобным, поделиться подробным гайдом таких задач с примерами реализации.
Пока писал вступление, совсем забыл про то, ради чего мы здесь, естественно, ради мемов и крутых инженерных фишек!
FPGA по-русски – программируемые пользователем вентильные матрицы. ПЛИС – программируемые логические интегральные схемы.
Главная разница между ПЛИС и FPGA – это то, что первое по сути класс устройств, а второе – вид устройств.
Для чего они нужны и что с ними делать?
ПЛИС имеют широкий спектр применения: их используют в цифровой обработке сигнала, для передачи данных на высокой скорости, для криптографических операций, для систем защиты информации или в качестве прототипов для будущих СБИС (ASIC).
Алгоритмы под ПЛИС реализуются на языках описания аппаратуры, например на Verilog HDL. Так причем же здесь MATLAB?
MATLAB имеет возможность генерации кода HDL, а что более интересно, прямо из него можно получить готовый проект под Vivado и выполнить его синтез и имплементацию уже там. О том как сотворить это чудо, я хочу поговорить с вами далее в статье.
Я расписал подробный гайд, чтобы упростить работу инженеров, проектирующих на ПЛИС. Цель статьи – описание процесса разработки приемопередатчика на ПЛИС по стандарту цифровой подвижной радиосвязи (DMR). Проект будет реализован под отладочную плату ZedBoard Zynq-7000. Для реализации проекта используется подход модельно-ориентированного проектирования (МОП). Его структура отображена на рисунке 1, все достаточно просто: есть приемные и передающие тракты цифровой обработки, которые в итоге мы реализуем на ПЛИС.
Эту задачу можно образно разделить на три этапа:
Первый этап – это разработка системной модели. Он позволяет реализовать модель, на основе которой в дальнейшем можно выполнить верификацию разрабатываемых алгоритмов на отладочных или макетных платах за счет взаимодействия с реальным оборудованием.
Второй этап – это трансформация модели под генерацию HDL кода. Основными задачами этапа являются перевод всех применяемых в проекте типов данных в фиксированную точку и изменение алгоритмов, не поддерживающих генерацию кода HDL.
Третий этап – реализация полученного HDL кода на ПЛИС. Здесь выполняется работа со сгенерированным кодом и Vivado. Главная задача – успешные синтез, имплементация проекта и взаимодействие с полученными файлами прошивки и управляющих программ.
Системная модель
На рисунке 2 представлена системная модель приемопередатчика DMR. Эта модель реализована при помощи Communications System Toolbox, работает в «реальном времени» и позволяет захватывать сигнал с рации и передавать записанные данные на рацию. Также она реализует виртуальную рацию. Для передачи радиосигнала используется ADALM-PlutoSDR. Это отладочная плата на основе трансивера AD9363 и FPGA Xilinx® Zynq Z-7010.
На данном этапе разработки мы получаем возможность отладки приемопередатчика, учитывая факт использования стандартных библиотечных блоков. Мы можем в максимально короткие сроки произвести верификацию разработанных алгоритмов.
В этой статье я не хочу затрагивать анализ системной модели и тратить ваше и свое время на разбор каждого конкретного блока и обзор его функционала. Если кому-то интересен этот вопрос, напишите об этом – я сделаю обзорную статью по каждому блоку и разберу аспекты перевода модели из системной в модель под генерацию HDL кода в деталях.
Единственные блоки, которые я затрону более подробно, это «ADALM-Pluto Radio Transmitter», который позволяет использовать Pluto как передатчик сигнала в эфир, и «ADALM-Pluto Radio Receiver», который в свою очередь принимает сигнал. В данной модели многие алгоритмы написаны MATLAB скриптами, поэтому я думаю, что в дальнейшем найдутся люди, которым будет интересно узнать, как на практике реализуется кадровая синхронизация, перемежители или как формируются заголовки пакетов. Честно говоря, я сам надеюсь на продолжение нашего с вами общения на эту тему.
¯\_(ツ)_/¯
На рисунках 3 и 4 я показал работу системной модели и взаимодействие с рацией и Pluto. В этой реализации на приемной и передающей стороне есть задержка, равная длине накапливаемого буфера. На 3 рисунке показана работа передатчика. Как вы видите, рация улавливает сигнал и декодирует адресата, а на рисунке 4 показана работа приемника. На графике MS видны пики корреляции, также можно заметить, что сигнальные конструкции определяются в тот момент, когда я начинаю передачу сигнала с рации, а на графике Error показан сдвиг символьной синхронизации.
Модель для генерации HDL кода. Реализация на ПЛИС.
Перейдем к HDL реализации. Что это и зачем оно нужно, мы уже разобрали, предлагаю взглянуть на рисунок 5: на нем представлена HDL модель, построенная на основе системной модели. Отличием от системной модели является использование блоков, поддерживающих генерацию HDL кода, и перевод всего тракта цифровой обработки в фиксированную точку. Для удобства отладки на плате для приемной части реализована возможность переключения режимов, за счет чего у нас есть возможность отследить все изменения данных в процессе обработки. Для передатчика этот подход не использовался, так как он имеет достаточно простую реализацию, и с ним изначально не возникало вопросов.
В этой части я хочу акцентировать внимание на процессе генерации HDL кода из модели, а не на самой модели и ее архитектурных изысках. Первым этапом является подключения САПР Vivado от Xilinx к MATLAB, ниже показан MATLAB скрипт для подключения.
Чтобы сгенерировать код, наверное нам надо задать какие-то настройки, условия под наш проект, но это не точно.)
Дак о каких настройках я говорю и где они находятся?
Откроем HDL Workflow Adviser. Там мы увидим эти настройки, на рисунках 7, 9-11 они также показаны и объяснены. На рисунке 7 настройки референса-проекта, здесь мы выбираем плату, под которую будем генерировать код, в нашем случае это ZedBoard + FMCOMMS, сама плата показана на рисунке 8.
На рисунке 9 показаны настройки ядра прошивки, в данном случае мы создаем ядро приемника и передатчика.
На рисунке 11 представлены настройки входных и выходных портов IP-ядра, а также размерности этих портов и их размерности в битах.
После того как мы настроили параметры генерации кода, переходим в пункт 4.1 и создаем проект Vivado с нашим IP-ядром, после чего уже в самой Vivado создаем бинарный файл прошивки (вкладка «Generate Bitstream»). На самом деле не думаю, что на данном этапе хоть у кого-то с первого раза выполнилась имплементация, обычно это всегда несколько дней работы, прежде чем у вас нормально сойдутся тайминги, так что не судите строго за отсутствие описания этой боли в статье. Если интересно, то могу с вами обсудить это в комментариях.)))))
После создание бинарного файла мы получаем полноценную прошивку под ПЛИС, которая выполняет заложенный нами функционал. Залить прошивку на ПЛИС можно несколькими способами: либо использовать загрузчик Vivado (на рисунке 12 показан процесс открытия таргета), либо можно вручную заменить стандартный файл system.bit на сгенерированный system_top.bit, естественно переименовав его в system.bit.
После загрузки прошивки необходимо загрузить управляющую программу. Чувствую назревший вопрос: откуда взялась управляющая программа и почему мы раньше о ней не говорили?
Погодите-погодите, я сам только что о ней вспомнил. Управляющая программа позволяет реализовывать управление интерфейсами на отладочной плате.
В модели управляющей программы мы объявляем AXI-порт как управляющий. За счет него мы переключаем различные режимы работы приемника, также мы определяем, что по протоколу UDP выполняется прием и передача данных на ПК, компьютер я использую в этой связке для трансляции аудиосигнала от микрофона и к акустическому динамику. И здесь же описана взаимосвязь кристалла ПЛИС с FMCOMMS (блоки AD936x). Сама модель, о которой я так много сейчас сказал, показана на рисунке 13.
Из этой модели при помощи комбинации клавиш Ctrl+B (люблю горячие клавиши, не могу) мы генерируем управляющую программу на языке C и файл *.elf , который дальше можно либо заранее загрузить на SD-карточку отладочной платы и вызывать из командной строки, либо каждый раз загружать ее через командную строку. Для второго варианта используется набор команд, показанный на рисунке 14, первая команда отправляет наш файл по IP платы в корень файловой системы, а дальше уже из-под отладки мы его запускаем.
После вызова управляющей программы мы получаем возможность уже с ПК захватывать и передавать данные. На рисунке 15 показана модель, которую я для этого использовал.
Подведем итоги: на мой взгляд я довольно подробно раскрыл методологию МОП, применяемую нами в проектах. Надеюсь, статья была вам интересна и полезна, жду ваших вопросов, критики, буду рад любому фидбеку.))))