Сага о светодиодах. Часть 3. Ведомая сторона.
Оглавление
Испытательный стенд для led_dev
Какая автоматизация без Makefile!
Работа над ошибками
Вернемся к части первой. И поработаем над таким вот замечанием.
"возникли вопросы к листингу кода. Например в листинге 2 (и не только) есть подобный код. Смущает код, описанный после ресета. У нас тут синхронный ресет (хотя при асинхронном я бы тоже так не делал). И два if независимых. В первом по RST_N==0 сигнал shift_cnt <= 0. Во втором при count == time1 и shift_cnt != 2'b10 сигнал shift_cnt <= shift_cnt + 1'b1. А так как второй if не зависит о первого (перед вторым if нету else) то непонятно что будет если эти условия выполнятся одновременно."
Автор этого замечания Artem Senin.
Управление светодиодом как было:
always @(posedge CLK_IN)begin
if(RST_N==0)begin
count <= 25'b0;
rledout <= 3'b1;
shift_cnt <=2'b0;
end
if(count == time1) begin
count<= 25'd0;
if(shift_cnt==2'b10)begin
rledout <= 3'b1;
shift_cnt <=2'b0;
end else begin
rledout <= {rledout[1:0],1'b0};
shift_cnt <= shift_cnt + 1'b1;
end
end else
count <= count + 1'b1;
end
Quartus для этого модуля генерирует вот такую схему,
Теперь изменим модуль так, чтобы в нём не было независимых утверждений jf.
Управление светодиодом с внесенными исправлениями:
always @(posedge CLK_IN)begin
if(RST_N==0)begin
count <= 25'b0;
rledout <= 3'b1;
shift_cnt <=2'b0;
end else begin
if(count == time1) begin
count<= 25'd0;
if(shift_cnt==2'b10)begin
rledout <= 3'b1;
shift_cnt <=2'b0;
end else begin
rledout <= {rledout[1:0],1'b0};
shift_cnt <= shift_cnt + 1'b1;
end
end else begin
count <= count + 1'b1;
end
end
end
Теперь для каждого условия в модуле есть альтернативная часть. Функциональная схема, в таком случае, приобретает вот такой вид.
Сравним полученные схемы. В схеме собранной по первому модулю есть только два мультиплексора, которые явно управляются сигналом RST. И это мультиплексор shift_cnt и rledout. Сброс счетчика count происходит не явно.
В схеме по исправленному модулю уже есть три мультиплексора, которые переключаются сигналом RST и производят сброс именно так как описано в модуле.
Отсюда правило. Указывать в модуле альтернативные варианты для условий if, чтобы в схемах не возникало неявных цепей.
Впрочем это правило я уже встречал где-то в литературе, посвященной проектированию на verilog.
И еще напомню, что источник выше обсуждаемого кода находится здесь
Драйвер светодиодов
В предыдущей части 2 рассматривалась конструкция правой части уравнения рисунок 1 "Блок схема устройства с блоком I2C". Теперь рассмотрим конструкцию в левой его части. Эта часть состоит из двух устройств:
- модуль i2c_slave - приемник управляющих сигналов;
- модуль led_dev - драйвер светодиодов.
Назначение и принцип работы i2c_slave известны из его описания. Назначение драйвера светодиодов состоит в том, чтобы определять по принятым данным какую линию светодиодов необходимо активировать и собственно активировать эту линию. В таблице представлено соответствие переданных управляющих слов и линий светодиодов.
Вход | Выход |
---|---|
8'h00 | 8'b00000000 |
8'h01 | 8'b00000001 |
8'h02 | 8'b00000010 |
8'h03 | 8'b00000100 |
8'h04 | 8'b00001000 |
8'h05 | 8'b00010000 |
8'h06 | 8'b00100000 |
8'h07 | 8'b01000000 |
8'h08 | 8'b10000000 |
Из таблицы понятно, что центральную часть разрабатываемого устройства будет занимать дешифратор последовательности байт, как показано в таблице. Задача несколько усложняется тем, что необходимо как-то взаимодействовать с устройством i2c_slave в плане ожидания от него управляющей последовательности байт.
Конструкция модуля led_dev
Напишем модуль, который будет выполнять работу, как описано выше.
Модуль led_dev
`include "timescale.v"
module led_dev (
clk,
rst,
dataIn,
leds);
input clk;
input rst;
input [7:0] dataIn;
output reg [7:0] leds;
always @(posedge clk) begin
if (rst) begin
leds <= 8'h00;
end
else begin
case (dataIn)
8'h00:leds <= 8'h01;
8'h01:leds <= 8'h02;
8'h02:leds <= 8'h04;
8'h03:leds <= 8'h08;
8'h04:leds <= 8'h10;
8'h05:leds <= 8'h20;
8'h06:leds <= 8'h40;
8'h07:leds <= 8'h80;
default:leds <= 8'h00;
endcase // case (dataIn)
end // else: !if(rst)
end // always @ (posedge clk)
endmodule
Рисунок этой схемы представлен ниже.
Один байт управляющего слова поступает на вход дешифратора, где происходит распознавание линии светодиодов в соответствии с таблицей 2.1, затем номер линии через мультиплексор подается на выходной регистр и через него на выходные порты, к которым и будут подключены светодиоды. Сигнал RST выключает все светодиоды, подавая через мультиплексор сигнал 8’h00 на выходной регистр, переводя в низкое состояние выходные линии.
Испытательный стенд для led_dev
Хотя работа и схема устройства led_dev довольно просты, все же поставим это устройство на испытательный стенд и убедимся в правильности его работы.
Конструкция испытательного стенда для led_dev представлена в следующем модуле. Комментарии по коду ускорят его понимание.
Стенд для проверки устройства led_dev:
`include "timescale.v"
module led_dev_tb ();
//Создадим тактовый опорный генератор
reg clk;
always #10 clk = ~clk;
// Поставим триггер rst
reg rst;
// Поставим счетчик 3-х битный. Будет задавать
// входную последовательность сигналов
reg [2:0] cnt;
// Подключим его к регистру на 8 бит
reg [7:0] regPI;
// Этот регистр имитирует выходной регистр
// устройства i2c, с которым led_dev будет
// в дальнейшем работать.
// Соберем из счетчика и регистра генератор байт
// с выходным регистром
always @( posedge clk) begin
cnt <= cnt + 1;
regPI [2:0] <= cnt;
regPI [7:3] <= 0;
$display( "CNT:", cnt );
end
// Создадим провода для светодиодов
wire [7:0] leds;
//Подключим к собранному стенду led_dev
led_dev iu_led_dev(
.clk(clk),
.rst(rst),
.dataIn(regPI),
.leds(leds));
// Начнем процесс
initial begin
clk = 0;
rst = 0;
// Сделаем первоначальный сброс
#30 rst = 1;
#10 rst = 0;
#20;
// Считаем с 0
cnt = 3'b0;
@(posedge clk)
#0;
begin
// Смотрим что получилось
$display(leds);
end
end
// И включим все это в работу
initial begin
// Зададим количество работы
#60000 $finish;
// сформируем файл для gtkwave
$dumpfile("out.vcd");
$dumpvars(0,led_dev_tb);
end
endmodule // led_dev_tb
Из комментариев должно быть понятно, как работает стенд. На рисунке ниже приведены эпюры в некоторых точках устройства, чтобы визуально проконтролировать работу led_dev.
Счетчик cnt, собранный на стенде, задает входную управляющую последовательность сигналов. Далее эти сигналы с выходных линий счетчика подаются на вход регистра regPI. Этот регистр имитирует работу выходного регистра модуля i2c slave. И далее на эпюрах видно как происходит дешифрирование входного сигнала и "засветка" соответствующих светодиодов.
Конструкция модуля i2c slave
Первое с чем я столкнулся в этой работе это то, что модуль i2c_slave из проекта взятого здесь и с которым я успешно работал используя i2c_master в качестве ведущего устройства при сборке в Quartus выдавал множество ошибок. Некоторые ошибки я смог исправить, а некоторые так и не смог, так как они требовали существенной переделки модуля. Вносить изменения в модуль i2c_slave я не стал. Порывшись в интернете я нашел несколько других модулей i2c, проверил их работу и остановился на модуле i2cSlave из проекта на OpenCode. Исходный код этого проекта можно скачать отсюда. Что я и сделал. Скачал этот проект. В модуле i2cSlaveTop собрал устройство led_dev совместно с модулем i2cSlave, см. следующий листинг.
Модуль i2cSlaveTop
//////////////////////////////////////////////////////////////////////
//// ////
//// i2cSlaveTop.v ////
//// ////
//// This file is part of the i2cSlave opencores effort.
//// ////
//// ////
//// Module Description: ////
//// You will need to modify this file to implement your
//// interface.
//// ////
//// To Do: ////
////
//// ////
//// Author(s): ////
//// - Steve Fielding, sfielding@base2designs.com ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2008 Steve Fielding and OPENCORES.ORG ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from ////
//// ////
//////////////////////////////////////////////////////////////////////
//
`include "i2cSlave_define.v"
module i2cSlaveTop (
clk,
rst,
sda,
scl,
leds
);
input clk;
input rst;
inout sda;
input scl;
//output
wire [7:0] myReg0;
output [7:0] leds;
i2cSlave u_i2cSlave(
.clk(clk),
.rst(rst),
.sda(sda),
.scl(scl),
.myReg0(myReg0),
.myReg1(),
.myReg2(),
.myReg3(),
.myReg4(8'h12),
.myReg5(8'h34),
.myReg6(8'h56),
.myReg7(8'h78)
);
led_dev u_led_dev (
.clk(clk),
.rst(rst),
.dataIn(myReg0),
.leds(leds)
);
endmodule
Для контроля создал проект в Quartus. На рисунке представлена полученная функциональная схема модуля i2cSlave совместно с устройством led_dev.
Тестирование I2C Slave
Следующая задача, которую необходимо было решить это тестирование собранного устройства. В составе проекта i2cSlave имеется стенд для тестирования самого устройства i2c. Я решил воспользоваться данным стендом. Устройство led_dev, на самом деле, я присоединил к i2cSlase прямо на стенде. Создал в модуле testHarness провода для подключения модуля led_dev и подключил его к модулю i2cSlave как показано в листинге. Весь код я не показываю, только часть в которой выполняется подключение модуля led_dev.
Модуль testHarness
// -------------------------- testHarness.v -----------------------
`include "timescale.v"
module testHarness ();
// ...
i2cSlave u_i2cSlave(
.clk(clk),
.rst(rst),
.sda(sda),
.scl(scl),
.myReg0(),
.myReg1(),
.myReg2(),
.myReg3(myReg0w),
.myReg4(8'h12),
.myReg5(8'h34),
.myReg6(8'h56),
.myReg7(8'h78)
);
led_dev u_led_dev (
.clk(clk),
.rst(rst),
.dataIn(myReg0w)
);
// ...
endmodule
Теперь осталось разработать источник управляющих сигналов для передачи в подчинённое устройство. Для этого в файле testCase0.v добавим 32-х битный счетчик cnt и создадим цикл, который будет передавать, в моём случае 4 раза, последовательность байт cnt.
Модуль testCase0
// ---------------- testcase0.v ---------------------
`include "timescale.v"
`include "i2cSlave_define.v"
`include "i2cSlaveTB_defines.v"
module testCase0();
reg ack;
reg [7:0] data;
reg [15:0] dataWord;
reg [7:0] dataRead;
reg [7:0] dataWrite;
integer i;
integer j;
integer C;
reg [31:0] cnt = 32'b0;
initial
begin
$write("\n\n");
testHarness.reset;
#1000;
$write("Testing register read/write\n");
testHarness.u_wb_master_model.wb_write(1, `PRER_LO_REG , 8'h17);
testHarness.u_wb_master_model.wb_write(1, `PRER_HI_REG , 8'h00);
testHarness.u_wb_master_model.wb_cmp(1, `PRER_LO_REG , 8'h17);
// enable i2c master
testHarness.u_wb_master_model.wb_write(1, `CTR_REG , 8'h80);
repeat (4) begin
for (i=0; i<8; i=i+1) begin
$display( "Loop:", i, "cnt:", "0x%4h",cnt, " b%32b", cnt );
multiByteReadWrite.write( \
{`I2C_ADDRESS, 1'b0}, \
8'h00, cnt, `SEND_STOP);
cnt = cnt + 1;
end
cnt = 0;
end
$write("Finished all tests\n");
$finish;
end
endmodule
Собирём стенд и посмотрим его в работе.
Из рисунка видно, что устройство i2cSlave правильно принимает управляющие байты. Устройство led_dev принимает эти байты и правильно их дешифрирует, "зажигая" соответствующие светодиоды.
Использование Quartus
Я уже несколько раз упоминал, что в своей работе над проектом использую Quartus. Но при этом особо не рассказывал как я это делаю.
Конечно есть мышино-визуальный способ использования этого замечательного инструмента. Но замечательным этот инструмент делает не только то, что он умеет откликаться на мышиную возню и компилировать и строить проекты, но также и то, что он позволяет, где это оправдано, применять автоматизацию с использованием TCL скриптов, а также вездесущей команды make.
И в этом небольшом отступлении я и хочу немного рассказать как я это использую.
Для начала мне приходилось создавать множество разных проектов для тестирования тех или иных вещей. И уходило много времени на создание всех этих каталогов, файлов, тестов и их вариантов. Поэтому я решил создать несколько tcl скриптов для выполнения различных рутинных действий. В частности один из этих скриптов должен будет, как мне хотелось, создавать новый проект, настраивать его для работы.
Чтобы начать пользоваться этой возможностью я погуглил в интернете, нашел несколько ресурсов, на которых раскрывается данная тема. В частности об этом пишут на хабре. Здесь я приведу один из источников в котором описана данная технология. Это Tcl Scripting, Quartus II Handbook version 11.1, Volume 2.
Для начала попробуем создать скрипт, при помощи которого можно создать новый проект. Хотелось, чтобы я мог написать в командной строке что-то вроде такого:
Командная строка для Quartus
$> quartus_sh -t new_project.tcl -project project_name
И проект готов.
Рассмотрим подробнее эту строку. Первым в ней идет указание на запуск quartus без графической оболочки. Далее идет параметр -t за которым указывается имя скрипта tcl. За именем скрипта указываются параметры для самого скрипта.
В выше упомянутом руководстве я нашел вариант того, как можно получить доступ к параметрам скрипта и как можно использовать полученные значения. Для этого применяется следующая конструкция:
Пример скрипта для работы с аргументами
package require cmdline
variable ::argv0 $::quartus(args)
set options {
{ "project.arg" "" "Project name" }
{ "frequency.arg" "" "Frequency" }
{ "argument.arg" "" "Argument Name" }
}
set usage "You need to specify options and values"
array set optshash [::cmdline::getoptions ::argv $options $usage] (*@\label{com:array}@*)
puts "The project name is $optshash(project)"
puts "The frequency is $optshash(frequency)"
puts "The argument is $optshash(argument)"
Для работы этого скрипта понадобится модуль cmdline. Далее мы создаём список параметров: имя_параметра значение_параметра описание_параметра.
В строке 9 из листинга предписывается заполнить массив с определенными выше параметрами их значениями, считанными из командной строки. И далее, просто печатаем имена параметров и их значения. Если параметр со значением не был указан, то значение параметра пусто.
Вывод при запуске этого скрипта будет следующим:
Пример работы в командной строке
$ quartus_sh -t print_cmd_args.tcl -project aaa -argument bbb
...
Info: Quartus(args): -project aaa -argument bbb
The project name is aaa
The frequency is
The argument is bbb
...
Итак, с помощью этих не хитрых строк можно получать из командной строки значения параметров. Теперь напишем скрипт, который будет получать имя проекта и создавать проект с этим именем. Снова обратимся к руководству Quartus. В нем приводится пример скрипта, с помощью которого можно создать проект, открыть и закрыть его. Возьмем этот скрипт за основу. Выглядит он вот так:
Полнофункциональный метод открытия проектов
package require cmdline
variable ::argv0 $::quartus(args)
set options { \
{ "project.arg" "" "Project Name" } \
{ "revision.arg" "" "Revision Name" } \
}
array set optshash [::cmdline::getoptions ::argv0 $options]
# Ensure the project exists before trying to open it
if {[project_exists $optshash(project)]} {
if {[string equal "" $optshash(revision)]} {
# There is no revision name specified, so default
# to the current revision
project_open $optshash(project) -current_revision
} else {
# There is a revision name specified, so open the
# project with that revision
project_open $optshash(project) -revision \
$optshash(revision)
}
} else {
puts "Project $optshash(project) does not exist"
exit 1
}
# The rest of your script goes here
Здесь, если проект существует, и не указана ревизия проекта, то мы открываем проект с текущей ревизией, если ревизия указана, то открываем проект с указанной ревизией, иначе сообщаем о том, что проект не существует.
Для создания проекта нам понадобится добавить в этот скрипт еще несколько строк в той ветке else, в которой обнаружено, что проекта с таким именем не существует. Добавим сюда строки для создания проекта.
Команда для создания проекта
...
project_new $optshash(project) -revision $optshash(project) -overwrite
...
И добавим строки с указанием устройства, для которого создаётся проект и имя семейства этих устройств, а также сколько процессоров можно использовать при построении проекта.
Команды назначения устройства
... set_global_assignment -name DEVICE 10M50DAF484C7G set_global_assignment -name FAMILY "MAX 10" set_global_assignment -name
NUM_PARALLEL_PROCESSORS 4...
Далее, я хотел бы, чтобы у меня была определенная структура каталогов для проектов, я называю это окружением проекта а иногда тестовым окружением в зависимости от того с чем я работаю. Так на самом верху у меня есть каталог определяющий общую тему проекта. Допустим это каталог fpga-system поскольку я занимаюсь написанием статей для этого ресурса. Ниже имеется каталог common, в котором содержатся различные модули на verilog содержащие общие модули и функции для всех проектов в категории fpga-systems. Кроме того, здесь же находятся каталоги с исходными текстами статей, которые я пишу. Далее располагаются каталоги указывающие на семейство устройств, под которые создаются проекты. Поскольку у меня таких устройств два, то и каталогов тоже два, а именно de10_lite для платы 10M50DAF484C7G и Sipeed Tang Premier RISC-V c чипом EG4S20BG256. В каждом из этих каталогов также находится каталог common с общими, но специфичными для данного устройства файлами. Далее идут каталоги с названиями проектов. Это будет верхний уровень проекта, в нем, как правило хранится файл с именем top.v, или как-то по другому, в котором содержится самый верхний модуль проекта. В каждом таком каталоге создаётся один рабочий каталог, в котором происходит сборка проекта и хранятся различные файлы и каталоги создаваемые при построении проекта. Эта структура является `идеальной` структурой и не является, в следствии своей идеальности рабочей структурой. Но она дает общее представление о том, как я хотел бы вести свои дела, и как, в связи с этим, я хотел бы упорядочивать порождаемые в ходе работы данные с тем, чтобы потом можно было просто воспроизвести все, что происходило во время работы.
И еще раз напомню, что эта структура каталогов не настоящая. Настоящее окружение несколько отличается от этого. И оно встраивается в рабочий процесс по созданию какого-то конкретного продукта. Например, для того, чтобы написать статью я разрабатываю и конкретное устройство и его тестирование и его описание и конечным продуктом является статья на сайте с описанием этого устройства. И таким образом, статья и разработанное устройство находятся в одном окружении. И когда я смотрю на верхний уровень этого окружения, то мне сразу понятно, что здесь находится, и внутри есть полное описание того, что здесь происходило.
Скрипт mkproject.tcl
Располагаем скрипт в каталоге, в котором необходимо создать проект. И запускаем скрипт указывая имя проекта и имя модуля верхнего уровня.
Скрипт должен:
- принять параметры;
- создать пару директорий, одну для документации, другую для работы;
- создать проект;
- выполнить некоторые назначения по проекту.
Реализация этих действий показана в листинге
Скрипт mkproject.tcl
package require ::quartus::project
package require ::quartus::flow
package require cmdline
variable ::argv0 $::quartus(args)
set options { \
{ "project.arg" "" "Project Name" } \
{ "revision.arg" "" "Revision Name" } \
{ "module_top.arg" "" "Module top file" } \
}
set usage "You need to specify options and values"
array set optshash [::cmdline::getoptions ::argv $options $usage]
puts "The project name is $optshash(project)"
set need_to_close_project 0
set make_assignments 1
# Set up the appropriate directory structure
# and move the files to their places
set partitions "run doc"
set run 0
# make directories $partitions
foreach partition $partitions {
if { [file exists $partition] == 0 } {
file mkdir $partition
puts "file $partition was created"
}
}
# make project
if { ! [project_exists
[lindex $partitions $run]/$optshash(project)]} {
project_new \
[lindex $partitions $run]/$optshash(project) \
-revision $optshash(project) \
-family "MAX 10" \
-part 10M50DAF484C7G
puts "[lindex $partitions $run]/$optshash(project) was created"
} else {
puts "$optshash(project) is exists"
}
# Set the device, the name of the top-level BDF,
# and the name of the top level entity
if {$make_assignments} {
# Ensure the project exists before trying to open it
if {[project_exists \
[lindex $partitions $run]/$optshash(project)]} {
if {[string equal "" $optshash(revision)]} {
# There is no revision name specified, so default
# to the current revision
project_open [lindex \
$partitions $run]/$optshash(project) \
-current_revision
} else {
# There is a revision name specified, so open the
# project with that revision
project_open [lindex \
$partitions $run]/$optshash(project) \
-revision \
$optshash(revision)
}
puts "Project $optshash(project) is open!"
}
set fam "MAX 10"
set mtop $optshash(module_top)
set_global_assignment -name FAMILY $fam
set_global_assignment -name VERILOG_FILE ../$mtop.v
set_global_assignment -name TOP_LEVEL_ENTITY $mtop
set_global_assignment -name SDC_FILE $mtop.sdc
set_global_assignment -name NUM_PARALLEL_PROCESSORS 4
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY .
set_global_assignment -name SEARCH_PATH ..
set_global_assignment -name SEARCH_PATH ../../../common
# ...
}
project_close
exit 0
Далее, для обеспечения полноты проекта необходимо сгенерировать модуль верхнего уровня. Ниже представлен скрипт, который это делает.
Скрипт mkcode.tcl
#Прописываем путь к библиотеке tcl
lappend auto_path "/usr/local/lib/tcllib1.21"
lappend auto_path "~/shcool/doc/reports/mytcllib"
lappend auto_path "./"
package require cmdline
package require mkverilog 1.0
#load_package flow
set options { \
{ "module_top.arg" "" "Module top file" } \
}
set usage "You need to specify options and values"
array set optshash [::cmdline::getoptions ::argv $options $usage]
puts "The module name is $optshash(module_top)"
# Создаем файл модуля
puts [mkverilog::mkcode $optshash(module_top)]
exit 0
Собственно, файл с кодом модуля на Verilog создает команда mkcode. Эта команда реализована в моей библиотеке и она очень проста. Так, что код этой команды я здесь приводить не буду.
Какая автоматизация без Makefile!
Продолжаем автоматизацию. Каждый раз набирать руками все эти скрипты, имена... это через некоторое время начинает утомлять. Можно ошибиться или что-нибудь подзабыть. Чтобы исключить, в этом контексте, человеческий фактор, разработаем Makefile. Требования к Makefile будут следующие:
- имя проекта я определяю прямо в самом Makefile. Это не очень хорошо, зато стабильно, быстро и избавляет от некоторых лишних действий с переменными среды, аргументами;
- имя топ модуля будет совпадать с именем проекта;
- имена создаваемых директорий также определены в самом Makefile;
- цели:
- create - создание проекта и файла топ модуля
- comp - компиляция проекта;
- all - create & comp;
- delete - уничтожить весть проект;
- clean - очистить проект.
А вот и сам Makefile.
Makefile
PROJECT = dev_top
MODULE_TOP = $(PROJECT)
VERILOG_SRC = $(PROJECT).v
WDIR = run
LIST_RM = $(WDIR)/*.rpt $(WDIR)/*.htm $(WDIR)/*.eqn $(WDIR)/*.pin $(WDIR)/*.pof db $(WDIR)/*.atm $(WDIR)/*.hdbx $(WDIR)/*.f $(WDIR)/*.map.* out atom_netlists $(WDIR)/db/* $(WDIR)/*.jdi $(WDIR)/*.done $(WDIR)/*.qxp $(WDIR)/*.sof $(WDIR)/*.pof $(WDIR)/*.sof $(WDIR)/*.fit.* $(WDIR)/*.sta.* $(WDIR)/*.sld
###################################################################
# Executable Configuration
###################################################################
MAP_ARGS = --family="MAX 10"
FIT_ARGS = --part=10M50DAF484C7G
ASM_ARGS =
QSH = quartus_sh
all: create comp
create:
$(QSH) -t ./mkproject.tcl -project $(PROJECT) -module_top $(MODULE_TOP)
$(QSH) -t ./mkmodule.tcl -module_top $(MODULE_TOP)
comp:
$(QSH) --prepare $(WDIR)/$(PROJECT)
$(QSH) --flow compile $(WDIR)/$(PROJECT)
delete:
rm -rf $(WDIR)/db run
clean:
rm -rf $(LIST_RM)
.PHONY: all clean delete compile
"Вуаля" и make сделает всю работу.
Итоги
В этой части были рассмотрены несколько аспектов проектной деятельности. Проектирование модуля для связи по протоколу I2C со стороны ведомого устройства. Тестирование этого модуля в сборке с ведущим устройством. Также я рассмотрел некоторую автоматизацию на языке Tcl по созданию тестовых проектов. Заметил, что время потраченное на автоматизацию с лихвой окупается в процессе проектирования. И это замечательно.
Также я заметил такое правило, что что-то появляется там где этому уделяется внимание. Или, другим манером, происходит то, чему уделяется внимание. Так я уделил внимание вопросу автоматизации и появилась автоматизация. Кроме того появилось еще несколько идей как можно внести еще больший вклад в автоматизацию проектной деятельности. Это довольно интересно. Что-то делаешь и появляются новые идеи как можно сделать еще что-то. В ходе выполнения следующих задач, я думаю, будут реализованы некоторые из этих идей.
Все задачи были успешно выполнены и представлены на обсуждение читателям. Я представляю, что аудитория на данном сайте это в основном инженеры и мне хотелось бы услышать ваше мнение о проделанной работе. Также может кто-то выскажет свои собственные мысли по вопросам затронутым в этой и предыдущих статьях.
А я, в свою очередь, приступаю к следующему этапу работы. А именно к тестированию конструкций на конкретном железе.