статью полностью в формате docx

advertisement
Урок 1
Мигающий светодиод
Мигающий светодиод – первый шаг при осваивании самых разных средств разработки. Несмотря
на практическую бесполезность результата, зажечь светодиод на плате означает освоить
инструмент, ведь для этого необходимо пройти весь путь, от начальной настройки среды
разработки при создании нового проекта до конфигурации целевого устройства, от изучения
синтаксиса, базовых правил формирования «скелета» программы до освоения принципов
тактирования устройства. Все, даже самые сложные проекты, можно рассматривать как
дополнение и расширение самой первой программы, «бесполезного» мигающего светодиода.
Перед тем, как приступить к работе с EP3C10 DevBoard, рекомендуется ознакомиться с
замечательной брошюрой Николая К. «Введение в Verylog» . http://sdrdeluxe.com/downloads/VerilogLessons.pdf
Весь материал учить необязательно, для начала, необходимы только базовые знания.
В качестве среды разработки нам потребуется QUARTUS II 13.0 sp1 Web Edition или более новые
версии. Программа бесплатная, ее можно скачать с торрента, тем более что занимает она более 7
гигабайт. Я не буду подробно останавливаться на установке, там все достаточно просто, разве что
стоит обратить внимание, драйвера для программатора будут находиться в
C:\altera\13.0sp1\quartus\drivers .
Для создания нового проекта, в меню QUARTUSa , откроем FileNew Project Wizzard , в новом
окне можно будет пошагово настроить все параметры нашего первого проекта.
На первой странице можно выбрать папку где расположится наш проект а также задать его имя –
LED_Blinking. Вторую страницу можно пропустить.
На третьей странице предлагается выбрать целевое устройство – ПЛИС, для которой мы
собираемся писать проект. На вкладке Family выберите Cyclone III а в графе Name Filter введите
EP3C10E144C8, выберите нужную микросхему из списка и нажмите кнопку Finish. Наш первый
прект создан.
Проект пока пустой, нам необходимо создать файл в котором мы будем описывать логику
работы нашего устройства. Говорить «я пишу программу для ПЛИС» некорректно, язык Verilog
хоть и похож на обычные языки программирования высокого уровня, на самом деле позволяет
описать схемотехнику задуманного устройства, которая определит алгоритм его работы. В
отличие от «программы» , где подразумевается выполнение определенной последовательности
действий.
Большие проекты, для удобства, могут содержать в себе множество файлов, нам же понадобится
всего один – главный файл нашего проекта. FileNew, выбираем Verylog HDL File. Чтобы не
запутаться, сохраним этот файл под именем нашего проекта FileSave As LED_Blinking.v . Теперь
нужно указать, что этот файл – главный файл проекта, ProjectSet as Top-Level Entity.
Все готово, теперь можно писать код.
// Модуль Моргание светодиодами
module LED_Blinking (
input Buttons[4:0],
output reg [12:0] Port_LED
);
// Текст модуля
Endmodule
Это текст пока еще пустого основного модуля. Как видим, имя нашего модуля LED_Blinking , в
списке переменных 5 сигналов Buttons обозначены как input и некий Port_LED шириной 13 бит
обозначен как регистр output. Только в этом месте, в описании переменных главного модуля, в
файле верхнего уровня, можно задавать нужные нам физически присутствующие входы/выходы
ПЛИС. В данном конкретном случае, будут сконфигурированы пять входов с именами Button_N к
которым мы можем в дальнейшем подключаться, а также 13 выходов, которые у нас на плате
имеют светодиоды.
Осталось только заставить светодиодики мигать и конец уроку. Только вот чтобы это сделать,
нужно каким-то образом отсчитывать временные интервалы. Необходим источник тактового
сигнала. Плата EP3C10 DevBoard имеет два генератора на 10МГц и 7.68МГц а также два входа для
внешнего тактирования. Очевидно, что удобно будет воспользоваться генератором на 10МГц.
Простым решением может показаться организовать счетчик, с помощью которого нужно
уменьшить частоту генератора до необходимой. Это неправильное решение. ПЛИС EP3C10 имеет
в своем составе два весьма продвинутых модуля PLL, каждый из которых, используя сигнал
внешнего генератора как опорный, может выдать до четырех тактирующих сигналов, в очень
широком диапазоне частот. Настроим один из них, полученный опыт обязательно пригодится нам
в дальнейшем, когда сложность проектов значительно повысится.
ToolsMegaWithard Plug-In ManagerNext, в окне поиска вводим “pll” и выбираем ALTPLL.
Зададим формат файла Verylog HDL и имя файла PLL1. Далее, откроется окно, в котором можно
задать нужные настройки модулю PLL.
На третьей странице зададим частоту входного тактируещего сигнала, 10МГц.
Четвертая страница, галки «areset» и «locked» можно снять, эти сигналы нам пока не нужны.
5,6,7 страницы пропускаем, на восьмой предлагается настроить первый выход модуля из четырех
(С0), оставим его как предложено, он будет выдавать 10МГц.
На девятой странице, настроим второй выход (С1) для выдачи частоты 1МГц, для этого установим
делитель на 10.
На десятой странице установим делитель 1000, для выдачи частоты 10кГц на выход С2.
Теперь можно жать Finish. В окне Project Navigator, в разделе Files, можно увидеть
сгенерированный файл PLL1.v. Откройте его.
module PLL1 (
inclk0,
c0,
c1,
c2);
input
inclk0;
output c0;
output c1;
output c2;
Как видим, модуль с названием PLL1 имеет один вход , 10МГц, и три выхода, 10,1, и 0.01 МГц. Эти
сигналы необходимо подключить в нашем основном модуле.
// Текст модуля
wire clk_10MHz, clk_1MHz, clk_10kHz;
PLL1 (PLL1_in, clk_10MHz, clk_1MHz, clk_10kHz);
Прежде всего, мы создали три провода clk_XX которые будут подключены к недавно созданному
внешнему модулю PLL1. Вход тактирующего сигнала в ПЛИС добавим в список переменных
основного модуля
input PLL1_in
Заметьте, что в списке переменных модуля PLL1 мы применили названия проводов, отличные от
их названий в описании модуля PLL1.v . Это допускается и это удобно, названия точно отражают
функционал. Имеет значение последовательность описания, то есть первая переменная всегда
будет входом, остальные три выходами, в той последовательности которая определена в файле
модуля.
Вот теперь мы готовы писать код для мигания светодиода.
//
reg [15:0] cnt;
always @(posedge clk_10kHz)
begin
if (cnt <= 10000) cnt <= cnt + 1;
else begin
cnt <= 0;
Port_LED[12] <= ~Port_LED[12];
end
end
Данную конструкцию можно описать словами следующим образом: каждый раз, по фронту
сигнала clk_10kHz, проверять значение 16-ти битного счетчика cnt, если его значение меньше
10000, прибавить 1 к его значению, если больше 10000, обнулить счетчик и инвертировать
значение выхода Port_LED[0], к которому будет подключен светодиод на плате.
Другими словами, частота 10кГц будет поделена на 1000, результат, сигнал с частотой в 1Гц будет
подан на светодиод.
Обратите внимание, запись « <= » в теле оператора IF (сравнение) означает «меньше либо равно»
, в остальных случаях означает «присвоить».
Если область действия оператора ( always, if, else ) ,больше чем одна запись, применяется
конструкция begin-end, для указания границ действия оператора.
Итак, весь код, необходимый для мигания светодиода выглядит так :
module LED_Blinking (
input Buttons[4:0],
output reg [12:0] Port_LED,
input PLL1_in
);
// Текст модуля
wire clk_10MHz, clk_1MHz, clk_10kHz;
PLL1 (PLL1_in, clk_10MHz, clk_1MHz, clk_10kHz);
//
reg [15:0]cnt;
always @(posedge clk_10kHz)
begin
if (cnt <= 10000) cnt <= cnt + 1;
else begin
cnt <= 0;
Port_LED[0] <= ~ Port_LED[0];
end
end
endmodule
Теперь можно скомпилировать код, ProcessingStart Compilation. Всего 23 логических элемента
из доступных свыше 10000 нам понадобилось чтобы заставить мигать светодиод.
Следующий шаг – назначение физическим выводам ПЛИС соответствующих входов/выходов
основного модуля. AssigmentsPin Planner, руководствуясь номерами выводов микросхемы
ПЛИС которые обозначены на плате, заполните небольшую таблицу, достаточно задать номер
выводов в поле Location. Младший разряд Port_Led[0] целесообразно назначить на нижний вывод
разъема платы, для наглядности.
После очередной компиляции проекта, QUARTUS создаст файлы прошивки с учетом назначенных
выводов.
Теперь осталось только запрограммировать получившейся прошивкой микросхему памяти
находящуюся на плате, чтобы лицезреть результат наших трудов. При подаче питания или после
сброса, код из микросхемы памяти сконфигурирует ПЛИС так как мы задумали.
Важно задать в настройках, какой тип микросхем используется при программировании.
AssigmentsDeviceDevice and Pin OptionsConfigurationUse Configuration DeviceEPCS16
Теперь, после очередной компиляции, можно уже приступать к программированию.
ToolsProgrammer, Hardware Setup – выбор доступного программатора. Mode – Active Serial
Programmer, Add Fileoutput filesLED_Blinking.pof
Устанавливаем галочки Programm, Verify, Blank check и жмем кнопку START.
Как видите, только для того чтобы светодиод мигал, нужно проделать большую работу. Но
дальше будет легче, у нас все настроено и мы можем сосредоточиться на написании кода.
Попробуем получить эффект «бегущий огонь». Нам понадобится еще одна переменная, которая
будет определять номер светодиода. Всего их у нас 13 светодиодов , с номерами 0-12.
//
reg [15:0]cnt;
reg [3:0] index;
always @(posedge clk_10kHz)
begin
if (cnt <= 1000) cnt <= cnt + 1;
else begin
cnt <= 0;
Port_LED[12:0] <= 0;
index <= index + 1;
if (index > 12) index <= 0;
Port_LED[index] <= 1;
end
end
Усложним задачу, сделав так, чтобы огонь, добежав до края линейки, возвращался в другом
направлении.
//
reg [15:0]cnt;
reg [3:0] index;
reg dir;
always @(posedge clk_10kHz)
begin
if (cnt <= 1000) cnt <= cnt + 1;
else begin
cnt <= 0;
Port_LED[12:0] <= 0;
if (index == 11) dir <= 1;
if (index == 1) dir <= 0;
if (dir == 1) index <= index - 1;
if (dir == 0) index <= index + 1;
Port_LED[index] <= 1;
end
end
Проверку направления dir можно записать одной строкой.
Вместо if (dir == 1) index <= index - 1;
if (dir == 0) index <= index + 1;
Записать index <= dir ? index - 1 : index + 1;
Это можно прочитать как «проверить условие dir ? если правда (1) то….. : иначе ложь (0) и ……»
Такую форму записи удобно применять если условие может принимать только два значения , 0
или 1.
И, напоследок, реализуем эффект двух огней, которые движутся навстречу друг другу. Визуально,
это будет выглядеть как если они встречаются посередине линейки и меняют направление.
Реализовать эффект можно несколькими способами с одинаковым результатом. Я добавил в код
всего одну строчку.
begin
if (cnt <= 1000) cnt <= cnt+ 1;
else begin
cnt <= 0;
Port_LED[12:0] <= 0;
if (index == 11) dir <= 1;
if (index == 1) dir <= 0;
index <= dir ? index - 1 : index + 1;
Port_LED[index] <= 1;
Port_LED[12 - index] <= 1; // второй огонь
end
end
Далее, предлагаю самостоятельно придумать несколько эффектов и реализовать их с помощью
Quartus, Verilig и конечно EP3C10 DevBoard.
На этом первый урок окончен.
Download