Меню

Dds генератор произвольных сигналов

Функциональный DDS rенератор на ПЛИС

Недавно я увидел проект генератора сигналов на микроконтроллере AVR. Принцип генерации — DDS, на базе библиотеки Jesper максимальная частота — 65534 Гц (и до 8 МГц HS выход с меандром). И тут я подумал, что генератор — отличная задача, где ПЛИС сможет показать себя в лучшем виде. В качестве спортивного интереса я решил повторить проект на ПЛИС, при этом по срокам уложиться в два выходных дня, а параметры получить не строго определенные, а максимально возможные. Что из этого получилось, можно узнать под катом

День нулевой

До того, как наступят выходные, у меня было немного времени подумать над реализацией. Чтобы упростить себе задачу, решил сделать генератор не в виде отдельного устройства с кнопками и LCD экраном, а в виде устройства, которое подключается к ПК через USB. Для этого у меня есть плата USB2RS232. Плата драйверов не требует (CDC), поэтому, я думаю, что и под Linux будет работать (для кого-то это важно). Так же, не буду скрывать, что с приемом сообщений по RS232 я уже работал. Модули для работы с RS232 буду брать готовые c opencores.com.

Для генерации синусоидального сигнала потребуется ЦАП. Тип ЦАП я выбрал, как и в исходном проекте — R2R на 8 бит. Он позволит работать на высоких частотах, порядка мегагерц. Убежден, что ПЛИС с этим должна справиться

По поводу того, на чем написать программу для передачи данных через COM порт я задумался. С одной стороны, можно написать на Delphi7, опыт написания такой программы уже есть, к тому же размер исполняемого файла будет не большим. Еще попробовал набросать что-то для работы с Serial в виде java скрипта в html страничке, но более менее заработало только через Chrome serial API, но для этого надо устанавливать плагин… в общем тоже отпадает. В качестве новшества для себя попробовал PyQt5, но при распространении такого проекта, нужно тащить кучу библиотек. Попробовав собрать PyQt проект в exe файл, получилось больше 10 мб. То есть, будет ничем не лучше приложения, написанного на c++\Qt5. Стоит еще учесть, что опыта разработки на python у меня нет, а вот на Qt5 — есть. Поэтому выбор пал на Qt5. С пятой версии там появился модуль для работы с serial и я с ним уже работал. А еще приложение на Qt5 может быть перенесено на Linux и Mac (для кого-то это важно), а с 5.2 версии, приложения на QWidgets может быть перенесено даже на смартфон!

Что еще нужно? Естественно плата с ПЛИС. У меня их две (Cyclone iv EP4CE10E22C8N на 10 тыс. ячеек, и Cyclone ii EP2C5 на 5 тыс. ячеек). Я выберу ту, что слева, исключительно по причине более удобного разъема. В плане объема проект не предполагает быть большим, поэтому уместится в любую из двух. По скорости работы они не отличаются. Обе платы имеют «на борту» генераторы 50 МГц, а внутри ПЛИС есть PLL, с помощью которого я смогу увеличить частоту до запланированных 200 МГц.

День первый

В связи с тем, что модуль DDS я уже делал в своем синтезаторном проекте, то я сразу взялся за паяльник и начал паять ЦАП на резисторах. Плату взял макетную. Монтаж делал с применением накрутки. Единственное изменение, которое коснулось технологии — я отказался от кислоты Ф38Н для лужения стоек в пользу индикаторного флюс-геля ТТ. Суть технологии проста: в печатную плату впаиваю стойки, на них со стороны печатного монтажа припаиваю резисторы. Недостающие соединения выполняю накруткой. Еще, стойки удобны тем, что я их могу вставить прямо в плату ПЛИС.

К сожалению, дома в наличии не оказалось резисторов 1 и 2 килоома. Ехать в магазин было некогда. Пришлось поступиться одним из своих правил, и выпаять резисторы из старой не нужной платы. Там применялись резисторы 15К и 30К. Получился вот такой франкенштейн:

После создания проекта нужно задать целевое устройство: Меню Assigments -> Device

Далее там же нажимаю кнопочку «Device and Pin options» потому что некоторые пины настроены так, что работать не будут. Настраиваю все, как «Use as regular I/O»

В проекте я «нахадркодил» неуправляемый главный модуль DDS на фиксированную частоту.

После этого нажал «Start Compilation», чтобы среда разработки задалась вопросом, какие у нас линии ввода вывода есть в главном модуле проекта и к каким физическим PIN’s они подключены. Подключить можно практически к любому. После компиляции назначаем появившиеся линии к реальным PIN микросхемы ПЛИС:

На линии HS_OUT, key0 и key1 прошу пока не обращать внимание, они появляются в проекте потом, но скрин в самом начале я сделать не успел.

В принципе, достаточно «прописать» только PIN_nn в столбце Location, а остальные параметры (I/O standart, Current Strench и Slew Rate) можно оставить по умолчанию, либо выбрать такие же, что предлагаются по умолчанию (default), чтобы не было warning’ов.

Номера контактов разъема подписаны на плате

А пины ПЛИС, к которым подключены контакты разъема, описаны в документации, которая идет в комплекте с платой ПЛИС.

После того, как пины назначены, компилирую проект еще раз и прошиваю с помощью USB программатора. Если у вас не установлены драйверы для программатора USB Byte blaster, то укажите Windows, что они находятся в папке, куда у вас установлен Quartus. Дальше она сама найдет.

Подключать программатор нужно к разъему JTAG. А пункт меню для программирования «Tools -> Programmer» (либо нажать значек на панели инструментов). Кнопка «Start», радостное «Success» и прошивка уже внутри ПЛИС и уже работает. Только не выключайте ПЛИС, а то она все забудет.

ЦАП подключен к разъему платы ПЛИС. К выходу ЦАП подключаю осциллограф С1-112А. В результате должна получиться «пила» потому что на выход 8 бит выводится старшая часть слова DDS аккумулятора фазы. А оно всегда увеличивается, пока не переполнится.

Каких-то 1.5 часа и для частоты в 1000 Гц я вижу следующую осциллограмму:

Хочу заметить, что «пила» по середине имеет небольшой перелом. Он связан с тем, что резисторы имеют разброс значений.

Еще один важный момент, который нужно было выяснить — это максимально возможная частота, с которой будет работать DDS генератор. При правильно настроенных параметрах TimeQuest, после компиляции в «Compilation Report» можно увидеть, что скорость работы схемы выше 200 МГц с запасом. А это значит, что частоту генератора 50 МГц я буду умножать с помощью PLL на 4. Увеличивать значение аккумулятора фазы DDS буду с частотой 200 МГц. Итоговый диапазон частот, который можно получить в наших условиях 0 — 100 МГц. Точность установки частоты:

0.05 Гц. Точность в доли герца для генератора с таким диапазоном рабочих частот (0. 100 МГц) считаю достаточной. Если кому-то потребуется повысить точность, то для этого можно увеличить разрядность DDS (при этом не забыть проверить TimeQuest Timing Analyzer, что скорость работы логической схемы укладывалась в CLK=200 МГц, ведь это сумматор), либо просто снизить тактовую частоту, если такой широкий диапазон частот не требуется.

После того, как я увидел на экране «пилу», семейные дела заставили меня ехать на дачу (выходной же). Там я косил, варил, жарил шашлык и не подозревал о том сюрпризе, что ждал меня вечером. Уже ближе к ночи, перед сном, я решил посмотреть форму сигнала для других частот.

Не буду скрывать, что форма сигналов меня расстроила, особенно на 1МГц (жалкий, никчемный мегагерц!). Я планировал получить частоты несколько других порядков. Почитав про R2R ЦАП стала ясна причина проблемы — паразитные емкости. Поэтому в планах на следующий день было решено сделать ЦАП на резисторах 100 и 200 Ом, которые у меня есть в наличии, а этот ЦАП оставить для будущих разработок, не требующих работы на таких высоких частотах, ведь в гладкости пилы тоже есть свой плюс.

День второй

В связи с тем, что было интересно, как будет работать ЦАП на резисторах 100 и 200 Ом, я сразу взялся за паяльник. На этот раз ЦАП получился более аккуратным, а времени на его монтаж ушло меньше.

Ставим ЦАП на плату ПЛИС и подключаем к осциллографу

Проверяем 1 МГц — ВО! Совсем другое дело!

Форма пилы на 10 МГц еще похожа на правильную. Но на 25 МГц она уже совсем «не красивая». Однако, у С1-112а полоса пропускания — 10 МГц, так что в данном случае причина может быть уже в осциллографе.

В принципе, на этом вопрос с ЦАП можно считать закрытым. Теперь снимем осциллограммы высокоскоростного выхода. Для этого, выведем старший бит на отдельный PIN ПЛИС. Данные для этой линии будем брать со старшего бита аккумулятора DDS.

Но считаю, что выход ПЛИС стоило бы нагрузить на сопротивление. Возможно, фронты были бы круче.

Синус делается по таблице. Размер таблицы 256 значений по 8 бит. Можно было бы взять и больше, но у меня уже был готовый mif файл. С помощью мастера создаем элемент ROM с данными таблицы синуса из mif-файла.

Выбираем 1 портовую ROM и задаем название модулю

С помощью browse находим наш mif файл с таблицей синуса

Тут тоже ничего не меняем

Снимаем галочку с модуля sine_rom_bb.v — он не нужен. Дальше finish. Квартус спросит добавить модуль в проект — соглашаемся. После этого, модуль можно использовать так же, как любой другой модуль в Verilog.

Старшие 8 бит слова аккумулятора DDS будут использоваться в качестве адреса ROM, а выход данных — значение синуса.

Осциллограмма синуса на разных частотах выглядит… одинаково.

При желании, можно рассмотреть проблемы ЦАП, связанные с разбросом резисторов:

Чтож, на этом выходные кончились. А ведь еще не написано ПО для управления с ПК. Вынужден констатировать факт, что в запланированные сроки я не уложился.

День третий

Времени совсем мало, поэтому программу пишем на скорую руку (в лучших традициях). Местами, чтобы сократить количество букв и удобство ввода информации с клавиатуры, применяется фильтр событий по имени виджета. Прошу понять и простить.

Исходный код на GitHub. Там же есть уже собранное под windows приложение.

Код прост, как 5 копеек. В файл проекта .pro кроме всего прочего нужно добавить модуль serialport:

День четвертый

В спешном порядке доделываем прием данных по UART. Для приема сообщений по UART нужно поставить пару модулей. Один Baud генератор, второй — приемник. Для того, чтобы приемник работал на 115200, нужно произвести некоторые рассчеты, исходя, что основная тактовая частота у нас — 200 МГц.

Ставлю модуль приема сообщений, на него подается uart_clk и сигнал с физического входа ПЛИС.

Дальше все это помещаю в отдельный модуль, который выдает только номер формы волны и значение приращения к регирстру аккумулятора фазы DDS.

Когда модуль uart_rx принял байт информации, он на один такт ставит в единицу линию uart_data_ready. В это время на линии uart_command находится принятый байт. Для приема сообщения пишу стейтмашину.

Выводим данные на выходы модуля

Добавляем модуль приема в главный модуль.

Значение приращения прибавляем к аккумулятору фазы

Из старшей части значения аккумулятора фазы получаем остальные волноформы. А в зависимости от выбранной формы — подключаем ее на выход.

Я был почти не удивлен, что оно сразу заработало. Единственная ошибка, которую я нашел — была в рассчетах: я делил искомую частоту на CLK, потом еще на два, потом умножал на разрядность аккумулятора. Но этого делать не нужно, потому что у нас получается 1 период при изменении значении аккумулятора от 0 до МАХ. Делить дополнительно на 2 нужно только если в качестве выхода меандра брать старший бит аккумулятора частоты (в этом случае частота получается ниже в 2 раза). Но получение меандра я переделал.

День четвертый

В него можно включить время, потраченное в каждый день на оформление статьи.

Приступим к проверке. Сначала осциллографом.

На радиочастотах от 28 и до 100 МГц я решил послушать генератор с помощью SDR приемника, поставив антенну рядом с платой.

Выводы

Как это часто бывает в ИТ — с оценкой сроков произошла ошибка в 2 — 2.5 раза. Цель достигнута: на коленке собран генератор до 100 МГц. Однако, чтобы эту поделку можно было назвать полноценным генератором, потребуется поработать еще. Поэтому есть большие перспективы для развития. Из за срыва сроков, я не добавил то, что в принципе мог: 1) генератор шума; 2) генератор волны, которую пользователь рисует сам; 3) генератор цифровой последовательности. Еще в генераторе нет регулировки амплитуды и смещения.

Использовано 227 ячеек из 10000. Список того, что еще можно добавить в проект:

  • Расширить разрядность ЦАП
  • Увеличить количество выходов с генерируемыми сигналами
  • Применить микросхему ЦАП в большей разрядностью
  • Реализовать управление амплитудой и смещением
  • Добавить элементы управления, ЖК экран, для портативности
  • Добавить генератор шума и других простых форм волн
  • Добавить возможность загрузки произвольных форм волн

Я думаю, что любой желающий сможет это сделать самостоятельно, расширив проект нужным функционалом. Добавить проще, чем сделать с нуля. Формат команды управления очень простой, поэтому генератором можно управлять с микроконтроллера.

Источник

Adblock
detector