Сага о светодиодах
Оглавление
- Введение
- 1. Зажигаем светодиод
- 2. Модуль count
- 3. Модуль shift_cnt
- 4. Модуль led_drv
- 5. Общая схема
- 6. Стенд для испытаний полученной схемы
- 7. Параметры
- 8. Параметрический сахар
- 9. Модуль led_drv
- 10. Модуль top
- 11. Стенд с параметрами
- 12. Запускаем стенд
- Что дальше?
*О найденных опечатках и замечаниях просим сообщить admin@fpga-systems.ru
Введение
Просто я описываю свой путь, свои исследования и свои заметки по дороге FPGA. И, конечно в начале будет светодиод. Потом я опишу свою работу с кнопками. А далее... Посмотрим, что будет далее.
Практически все эксперименты будут проводиться на плате Lichee TANG Premier RISC-V. На этой плате установлен чип EG4S20BG256. Это и есть FPGA. Помогать мне будут Verilog, GTKWAVE и IDE TD (Tang Dinasty). Эти инструменты легко можно найти в интернете. Кроме того, иногда я буду использовать Quartus.
1. Зажигаем светодиод
Это магическое действие производит практически каждый, начинающий свой путь в FPGA. Я не являюсь исключениием из этого правила и для меня следующая мантра “да будет светодиод” является такой же магической и священной как и мантра “Hello, World!”. И не отходя от традиции я привожу схему подключения светодиода, рис.1 и модуль зажигания, листинг 1. Схему я начертил сам, когда разбирался с распиновкой этой платы. Подключение платы к компьютеру было выполнено штатным кабелем через USB интерфейс.
Модуль зажигания я взял из примера Tang_FPGA_Examples/0.LED. Этот пример, а также некоторые другие примеры для работы с этой платой доступны на github. Данный пример был открыт как проект в TD. Для этого предварительно надо скачать эту IDE и файл лицензии к ней. В примере, в файле README указана ссылка для скачивания. Если у вас linux, то скачивать надо соответствующий файл. Но надо заметить что у меня заработало только то, что находилось в файле TD_RELEASE_MAY2019_r4.5.12562_RHEL.rar. Надо распаковать этот архив, в папке bin будет находится IDE. Команда ./td -gui запустит IDE в графическом режиме. Чтобы открыть проект необходимо в папке prj указать на файл с расширением al. Впрочем, если вы предпочитаете консоль, то запустите просто ./td и в открывшейся консоли команда help выдаст вам список практически всего меню, что есть в этой IDE. Наслаждайтесь.
В проекте есть файл io.adc, отвечающий за назначение контактов. Этот файл находится в папке constraint и в нем располагаются следующие данные.
Рис. 1. Электрическая схема
Листинг 1. Назначение контактов.
|
Поле LOCATION для светодиодов RGB_LED[2:0] содержит номера пинов к которым подключены светодиоды согласно схемы на рис.1. Надо сказать, что на самой плате уже есть три светодиода подключенные к этим пинам. Вернее это одна сборка из трех светодиодов.
Компиляция прошла без ошибок. В результате был получен файл led.bit и этот файл был загружен в плату. После чего светодиод заморгал.
Листинг 2. Управление светодиодом
|
Немного пройдемся по строкам этого священного писания. В строке 1 задано имя модуля. В строках 3...5 определены имена входных и выходных портов.
Далее определены три регистра.
- rledout - три триггера для хранения состояний светодиодов, строка 10;
- count - 24-х разрядный счетчик, строка 11;
- shift_cnt сдвиговый регист на 2 разряда, строка 12.
Блок initial (строки 14...19) выполняется один раз и задает начальные значения указанных регистров.
Далее выполняется блок always. Он выполняется каждый раз при положительном фронте тактового сигнала CLK_IN все оставшееся время и в данном случае его основное предназначение это включать и выключать светодиоды в соответствии с заданной в нем логикой.
Всю схему я здесь приводить не буду. Рассмотрим некоторые её части. На рисунке 2 представлен регистр состояний светодиодов. Это просто 3 D триггера.
Рис. 2. Регистр состояний светодиодов
И эта часть схемы соответствует строке 10 в описании модуля. Счетчик count представлен на рисунке 3 Видно, что он состоит из 25-ти D триггеров, у него есть сумматор и мультиплексор для установки начального значения.
Рис. 3. Счетчик
Также и счетчик shift_cnt, рис. 4, реализован на 2-х D триггерах. Кроме того, у него есть схема сравнения соответствующая строке 32 в тексте модуля.
Рис. 4. Счетчик shift_cnt
Можно заметить, что этот модуль зажигания состоит из трех частей. Обозначим эти части следующим образом.
- делитель тактовой частоты, он же счетчик count, который вырабатывает сигнал для сдвигового регистра при совпадении счетчика с установленным заранее значением time1;
- сдвиговый регистр shift_cnt;
- драйвер светодиодов led_drv.
Это можно изобразить так, как на рисунке.
Рис. 5. Функциональная схема модуля верхнего уровня.
Теперь разделим первоначальный текст из листинга 2 на три модуля и потом соберём из этих частей ту же схему.
2. Модуль count
Этот модуль будет выполнять функцию делителя частоты. Коэффициент деления задаётся при помощи параметра TIME1 строка 1.
Листинг 3. Делитель частоты
|
3. Модуль shift_cnt
Листинг 4. Сдвиговый регистр
|
Этот модуль принимает на вход тактовый сигнал и фактически он отсчитывает количество светодиодов, выдавая на выход номер светодиода, который будет зажжен.
4. Модуль led_drv
Листинг 5. Драйвер светодиодов
|
Этот модуль принимает номер светодиода от предыдущего модуля и последовательно включает один из светодиодов.
5. Общая схема
В следующем листинге описана сборка схемы из разработанных выше модулей.
Листинг 6. Общая схема
|
В железе эта схема теперь выглядит так. Эта схема вполне соответствует функциональной схеме приведенной на рисунке 5. Соответствие прямое. Понять и проанализировать работу этой схемы гораздо проще, чем эквивалентную по функционалу схему приведённую в листинге 2. Посмотрим как реализованы каждый из этих модулей.
Рис. 6. Электрическая схема
Модуль count, делитель опорной частоты.
Этот модуль можно теперь легко выделить из общей схемы. Здесь видно соответствие элементов схемы с элементами описания в исходном файле. В этом можно убедиться просто просматривая схему и читая строки в исходном файле.
Рис. 7. Делитель частоты.
Модуль shift_cnt, переключатель светодиодов.
Такое же соответствие можно увидеть и в переключателе светодиодов. Схема этого переключателя довольно простая. Так как светодиодов всего три, основу этой схемы составляет 2-х разрядный счетчик, который переходит в различные состояния в соответствии с логикой, представленной в листинге 18. По сигналу RST регистр может быть установлен в 0. В рабочем режиме это обычный счетчик, который отсчитывает количество светодиодов и по достижении полного количества светодиодов сбрасывается в 0 и начинает отсчет сначала. Так задается номер того светодиода, который будет зажжен.
Рис. 8. Переключатель светодиодов.
Модуль led_drv, подключения светодиодов.
Эта схема принимает последовательность номеров светодиодов и, обеспечивает последовательное переключение светодиодов так, что загорается всегда последовательно только один светодиод.
Рис. 9. Подключение светодиодов.
6. Стенд для испытаний полученной схемы
Теперь разработаем стенд, на котором можно будет прогнать схему и посмотреть как она будет работать. Понадобятся пара сигналов, которые будут подаваться на вход модуля.
Листинг 7. Входные сигналы
|
Далее добавим провода для подключения светодиодов.
Листинг 8. Провода для подключения светодиодов
|
Теперь подключим модуль верхнего уровня. Другими словами создадим экземпляр схемы.
Листинг 9. Создаем экземпляр модуля
|
Для оживления схемы зададим работу генератора тактовых сигналов.
Листинг 10. Генератор тактового сигнала
|
Тоже самое можно сделать более академически.
Листинг 11. Еще один генератор тактового сигнала
|
Установим сигналы в 0.
Листинг 12. Начальная установка
|
Сделаем сброс, подняв сигнал RST в 1 и через #10 единиц времени снова опустим его в 0.
Листинг 13. Выполняем сигнал сброс
|
Запустим схему в работу.
Листинг 14. Запуск схемы в работу
|
Некоторое время дадим поработать и выключим.
Листинг 15. Поработаем и выключаем
|
Создадим файл VCD для последующего анализа.
Листинг 16. Создание VCD файла
|
Наблюдаем за некоторыми сигналами.
Листинг 17. Монитор сигналов
|
И в целом весь стенд выглядит так.
Листинг 18. Схема стенда
|
Запускаем стенд. После чего наблюдаем следующие эпюры напряжений на входах и выходах сгенерированной схемы.
Листинг 19. Заклинания для запуска стенда
|
Рис. 10. Эпюры напряжений на входах и выходах схемы.
7. Параметры
Ссылка; IEEE Std 1364-2005 IEEE STANDARD FOR VERILOG. Описание стандарта Verilog. При анализе листингов можно заметить, что некоторые элементы схемы могут меняться в зависимости от решаемых задач. Например может измениться количество светодиодов в модуле драйвера светодиодов и тогда надо будет изменить количество регистров для подключаемых светодиодов, а также номер последнего светодиода. Также, если изменить количество светодиодов, то придется изменить и разрядность счетчика светодиодов в модуле переключателя светодиодов. Для того чтобы сделать это правильно и без ошибок, можно воспользоваться механизмом определения параметров модуля, который реализован в Verilog и позволяет создавать параметризированные проекты, переопределяя значения параметров во время, когда создается экземпляр схемы.
Немного о параметрах
В языке Verilog cуществует два различных способа обьявления параметров. Первый — это в виде списка параметров модуля, второй — как пункты модуля (с-подобный синтаксис). Объявление модуля может содержать определения параметров одного или обоих типов или может не содержать определений параметров. При обьявлении параметров им сразу присваиваются значения и обьявленные параметры используются где-то внутри модуля.
Первый способ выглядит так. И это упрощенный пример синтаксиса. Полное описание синтаксиса надо смотреть в стандарте.
Листинг 20. Упрощенный синтаксис определения параметров в виде списка параметров модуля
|
В следующем примере показано определение трех параметров модуля и их использование в самом модуле. Этот пример и следующие примеры взяты из стандарта IEEE Std 1364-2005.
Листинг 21. Пример определения списка параметров и их использования в модуле
|
Пример определения параметров вторым способом приведен в следующем листинге. Полное описание синтаксиса надо смотреть в стандарте.
Листинг 22. Параметры как пункты модуля
|
Когда создается экземпляр модуля, параметрам могут быть присвоены новые значения. Эти новые значения будут использованы внутри экземпляра модуля. При создании экземпляров модулей значения параметров можно изменять пользуясь синтаксисом именованых параметров, либо задавать значения строго позиционно, как в следующих примерах.
Листинг 23. Пример определения экземпляра модуля с использованием синтаксиса с именоваными параметрами.
|
Здесь показано создание экземпляров модуля vdff и определение новых значений для параметров delay и size для каждого нового экземпляра. Причем, не важно в каком порядке мы указываем имена этих параметров.
В следующем примере показан позиционный способ определения значений параметров при создании эекземпляров того же модуля vdff.
Листинг 24. Пример определения экземпляра модуля с использованием синтаксиса с именоваными параметрами.
|
8. Параметрический сахар
Подсластим наш проект параметрическим сахаром.
Модуль count
В модуле count изначально использовался параметр TIME1, смотри листинг 3. Этот параметр введен для того, чтобы иметь возможность задавать управляемые отсчеты для модуля shift_cnt. Сигнал STB на выходе модуля count формируется путем деления опорной частоты на значение параметра TIME1 и имеет длительность такта равную количеству тактов опорной частоты заданной параметром TIME1.
Модуль shift_cnt
В этом модуле необходимо произвести некоторые изменения. Здесь есть счетчик и шина данных, которая подключается к этому счетчику. Разрядность этой шины и счетчика должны быть согласованы между собой. Для правильной настройки разрядности введем параметр SIZE - количество необходимых разрядов. Значение по умолчанию для этого параметра равно 2, этого достаточно для управления 3-мя светодиодами. Локальный параметр NULL введен просто для нагладности.
Для управления работой счетчика необходимо знать сколько делать отсчетов, чтобы правильно переключать светодиоды. Для этого введем параметр LED_CNT - значение этого параметра равно количеству светодиодов в схеме минус 1, так как начало отсчета с 0. Значение этого параметра не должно превышать емкость счетчика. В следующем листинге представлен код модуля shift_cnt с параметрами.
Листинг 25. Сдвиговый регистр с параметрами
|
9. Модуль led_drv
В этом модуле также есть счетчик, регистр и шина данных, разрядность которых зависит от количества обслуживаемых светодиодов. Для настройки этих элементов введем следующие параметры.
- Параметр SIZE устанавливает разрядность шины данных счетчика CNT_N.
- Параметр END_LED задает условие для переключения счетчика в начальное состояние, а также количество разрядов в регистре rledout и в шине RGB_LED.
|
10. Модуль top
Модуль top служит для сборки всего устройства. В нем должны быть параметры, которые управляют настройками подключаемых модулей так, чтобы их работа была согласована в соответствии с количеством подключенных светодиодов к схеме.
- Параметру SIZE назначается количество разрядов для счетчиков.
- Параметру CLK_DIV назначается значение коэффициента деления тактовой частоты, чтобы управлять скоростью мигания светодиодов.
- Параметру LED_NUM назначается количество светодиодов в схеме.
- Локальный параметр LED_CNT задает количество отсчетов, которые должен сделать счетчик в модуле shift_cnt, см. описание модуля shift_cnt в листинге 25.
- Локальный параметр END_LED передает в модуль led_drv число соответствующее номеру последнего светодиода при счете светодиодов от 0, см. описание модуля led_drv в листинге 26.
Локальные параметры LED_CNT и END_LED введены для удобства и для наглядности.
Листинг 27. Модуль top
|
11. Стенд с параметрами
Листинг стенда с параметрами представлен ниже. Параметры, расположенные в начале модуля стенда предназначены для конфигурирования устройства. Рассмотрим эти параметры:
- Параметр CLK_DIV. Это уже знакомый параметр, который задает коэффициент деления опорной частоты и формирования сигнала STB. Меняя значение этого параметра можно изменять скорость переключения светодиодов.
- Параметр DEPTH задает ёмкость или мощность счетчика. Используя это значение можно вычислить количество разрядов для шин, регистров и счетчиков, используемых в этом устройстве. Это вычисленное значение присваивается параметру SIZE.
- Параметр LED_NUM содержит количество светодиодов, которые будет поддерживать сгенерированная схема
- Параметр SIZE определяет разрядность счетчиков в модулях shift_cnt и led_drv. Значение этого параметра определяется как двоичный логарифм от мощности счетчика DEPTH.
Значения этих параметров передеются в модуль top при создании экземпляра устройства.
Листинг 28. Стенд с параметрами
|
12. Запускаем стенд
При установленных параметрах как на листинге стенда схема будет работать следующим образом.
Рис. 11. Работа схемы с 10 светодиодами
Что дальше?
Далее отделим драйвер светодиодов от схемы управления и свяжем эти две части посредством интерфейса I2C и в другом варианте будем использовать интерфейс SPI.
Потом предположим, что эта схема будет управлять гирляндами светодиодов. В таком случае заменим устройство управления на конечный автомат, который будет создавать различные эффекты на этих гирляндах.
Поигравшись с конечным автоматом, придем к выводу, что неплохо было бы создать устройство управления, которое будет работать используя простые скрипты.
Статья будет доступна в формате PDF чуть позже