- PVSM.RU - https://www.pvsm.ru -
Некоторое время назад, хаброжитель DmitrySpb79 [1] написал статьи о создании электронных часов. В них он рассмотрел источники точного времени [2], а так-же элементную базу для создания электронных часов [3]. Были упомянуты Arduino, STM, Raspberry PI, ESP8266, но совсем забыли про ПЛИС [4].
Давайте заполним этот небольшой пробел. Узнаем, на сколько просто сделать часы на ПЛИС и какие аппаратные ресурсы для этого потребуются. К тому же, мне подарили микросхему ПЛИС очень малого объема — 64 макроячейки. Это ПЛИС LC4064v фирмы Lattice с которыми я до этого никогда не работал. Я думаю, будет интересно!
Цели:
Меня ожидает несколько очень приятных вечеров, посвященных разработке на ПЛИС!
Lattice Semiconductor Corporation [5] — американский производитель микросхем. Компания располагается в Орегоне и выпускает высокопроизводительные ПЛИС. Есть информация о том, что микросхемы популярны в промышленных разработках из за открытости документации и протоколов. Широкий перечень изделий [6] и их назначений говорит о том, что они делают серии ПЛИС для автоматизации, автомобилестроения, создания компактных, портативных, экономичных устройств. Так же есть серии ПЛИС больших объемов (до 100k и более макроячеек).
К сожалению, я пока не смог найти магазин, где можно было бы купить ПЛИС объемом в 1 — 4 тысячи макроячеек и ценой в одну-две тысячи рублей. Однако, плату под свои требования я нашел — Programmable Logic IC Development Tools MachXO3LF StarterKit [7]. Количество ячеек — 6900, на плате уже есть программатор (FTDI [8]), 8 светодиодов [9]. Цена 25$, однако, стоимость доставки, при оформлении покупки в Lattice Store, оказалась 45$. Чтож, будут деньги — буду искать на digikey [10] или mouser [11] и заодно их осваивать. Однако, еще нашелся вариант покупки на Родине, в магазине Элитан [12], по цене 2992 рубля. На Ebay/Aliexpress выбор пока не большой, однако удалось найти чип без платы на 5 тысяч ячеек — LFXP2-5E-5QN208C [13].
При разборке старой электроники, периодически попадаются CPLD небольших размеров (32, 64 ячейки). Одну такую микросхему мне и подарил мой товарищ. Микросхема ПЛИС LC4064V (pdf [14]) — представитель семейства ispMACH 4000V/B/C/Z Family [15]. Мой вариант работает от напряжения 3.3В, на частотах до 400 МГц! В корпусе TQFP имеется целых 32 линии ввода/вывода, из них две линии используются под тактовые входы. Линии толерантны к 5 В в режимах LVCMOS3.3, LVTTL и PCI. Все выводы могут быть "притянуты" pull-up, pull-down либо могут висеть в воздухе. Так же, можно работать в режиме open-drain.
Для небольших ПЛИС, к которым относится LC4064v нужен: ispLEVER Classic [16].
Для прошивки нужно установить: Diamond Programmer [17].
Для более крупных ПЛИС: Lattice Diamond [17].
Для активации программ, нужно зарегистрироваться на сайт [18]е, указать свой MAC адрес и скачать ключи лицензий.
Для создании общего представления о том, как разрабатывать проекты в среде Lattice Diamond, рекомендую ознакомиться с этим видео [19].
Программаторы LPT уже практически ушли в прошлое. Да и собирать программатор нет времени и желания(есть желание делать проект). Как и в случае с Altera, я решил найти и купить готовый китайский клон программатора, на площадках Ebay или Aliexpress. Однако, если программатор для Altera стоит в пределах 300 рублей [20], то для Lattice цены уже порядка 2000 рублей [21]. За, казалось бы, одинаковые изделия, отличающиеся только наклейкой. Но если хорошенько поискать, то можно найти дешевле — 1300 рублей [22]! Беру сразу два: себе и товарищу. По приезду, один программатор отказался работать [23]. Начал было общаться с продавцом, тот уверил, что они все проверяют. В итоге, я его сам и починил, пропаяв землю на разъеме USB.
Сравнил с программатором для Altera, чтобы убедиться, что они всетаки разные, а не "отличаются только ID USB".
Еще немного фото: 1 [24], 2 [25], 3 [26]. Микросхем действительно больше, так что вполне очевидно, что программатор получается дороже.
Для проверки микросхемы на скорую руку делаю плату со светодиодами и кнопкой. Саму микросхему припаиваю на плату-переходник.
В качестве генератора не нашел ничего проще, чем ПЛИС Altera Cyclone [27] :) Поделил частоту тактового генератора 50 МГц до 2 Гц и вывел обратно. Этот сигнал подал на тактовый вход LC4064v. Сделал простейший 4х битный счетчик, а его биты вывел наружу и подключил к светодиодам.
Прошиваю — работает!
Теперь, когда стало ясно, что ПЛИС работает и поддается программированию, можно придумать себе проблему задачу и героически ее решить!
На самом деле, идея сделать часы пришла не сразу. Количество ячеек, равное 64, заставляет задуматься над задачей, которую можно им поручить. Вспоминаются старые времена, когда в наличии имелся строго определенный МК, который я умел программировать, и я пытался уместить в него решаемую задачу. Программирование ПЛИС предполагает обратное: решение задачи и выбор ПЛИС нужного размера по результатам синтеза. Но тут мы переворачиваем всё с ног на голову, и ограничиваем себя размером. Это заставит нас потрудиться, как в выборе задачи, так и в ее реализации. Эдакое экстремальное программирование в ограниченных условиях.
Что сделать же сделать? Электронный синтезатор? Маловато ячеек: только приемник MIDI команд занимает не одну сотню. Нужно что-то простое! Например декодер звукового I2S потока и вывод его через ЦАП на резисторах? Как то очень специфично, просто и не очень зрелищно. Линий много — можно повесить семисегментные индикаторы (7х4 = 28 даже статически!). А что изображать? Можно сделать либо частотомер (отличный вариант, ведь микросхема работает аж до 400 МГц) либо часы. Решено выбрать часы.
Для часов нам потребуются семисегментный индикатор на четыре цифры. Сначала я хотел приобрести новый индикатор в магазине, а потом вспомнил, что у меня уже есть часовой индикатор, который лежит в ящике уже, наверное, лет десять. Мне его когда-то очень давно подарил regenerator с форума РадиоКот [28]. Схема включения моего индикатора имеет следующий страшный вид:
В рамках избавления ящиков от залежавшихся компонентов, а так же издевательства над ПЛИС(и собой), было решено использовать именно этот, на первый взгляд, непонятный индикатор. На самом же деле все достаточно просто: сверху мы подаем управляющее напряжение на индикаторы. Как правило, один провод идет сразу на два сегмента. А какой из двух сегментов будет работать, определяется шиной, которую мы подключили к общему проводу в данный момент. Схема, в целом, соответствует классической схеме динамической индикации [29] с той разницей, что индикаторов у нас получается всего два. Для проверки работы всех индикаторов, вывел логическую единицу на все выходы, а сигнал на транзисторы вывел по очереди.
По результатам теста, выяснилось, что мы, в принципе, можем выводить цифру на любой индикатор. Однако, в самом левом индикаторе отсутствует один сегмент. Это не позволит выводить на него все возможные цифры, но самое важное — цифру "ноль". Этот факт подтверждается и вот этой картинкой [30]. Поэтому ноль в десятках часов будем гасить.
Еще нам потребуется "часовой генератор" — это генератор на частоту 32768 Гц. Почему такая частота? Потому что, если взять 15 битный двоичный счетчик и подать на него эту частоту, то на выходе мы получим 1 Гц (2^15 = 32768). То есть интервал в одну секунду. Хочу отметить еще один важный момент в выборе частоты генератора. Для того, чтобы поделить частоту на 32768 потребуется 15 битный двоичный счетчик, а это как минимум займет 15 ячеек в ПЛИС, что сразу отнимет почти четверть ресурсов. Счетчик для генератора в 50 МГц потребует уже 30 бит для деления до секундного интервала. При таких затратах, ячеек на логику работы часов может не хватить.
Пока часового кварца нет, в качестве генератора частоты опять же будет выступать Altera Cyclone, в которой я целочисленно поделил частоту 50 МГц до 32768 Гц.
Для деления частоты применяю свой модуль на Verilog. Работать с ним очень просто: на clk подаем исходную частоту, из s_out получаем результат. Коэффициент деления задаем параметром DIV. В моем случае 50000000 Гц это входная тактовая частота, а 32768 Гц — частота, которую нужно получить.
frqdivmod #(.DIV(50000000/32768)) divider(.clk(clk50M), .s_out(clk32768));
module frqdivmod(clk, s_out);
parameter DIV=2;
// calculated parameters
parameter WITH = ($clog2(DIV)>0) ? $clog2(DIV) : 1;
input wire clk;
output wire s_out;
reg clk_n;
reg [(WITH-1):0] pos_cnt;
reg [(WITH-1):0] neg_cnt;
wire [(WITH-1):0] div_value = DIV[(WITH-1):0];
initial begin
clk_n <= 1'b0;
pos_cnt <= {(WITH){1'b0}};
neg_cnt <= {(WITH){1'b0}};
end
assign s_out = (DIV==1) ? clk : clk_n;
always @ (posedge clk) begin
pos_cnt <= (pos_cnt + 1'b1) % div_value;
end
always @ (negedge clk) begin
neg_cnt <= (neg_cnt + 1'b1) % div_value;
end
always @(clk, pos_cnt, neg_cnt) begin //pos_cnt in sens list addd for resolve warning "variable is read inside the Always Construct but isn't in the Always Construct's Event Control"
if ((DIV%2) == 1'b0) begin
clk_n <= ( pos_cnt >= (DIV/2)) ? 1'b1 : 1'b0;
end else begin
clk_n <= (( pos_cnt > (DIV/2)) || ( neg_cnt > (DIV/2))) ? 1'b1 : 1'b0;
end
end
endmodule
Первая итерация по созданию часов — это создание схемы двоичного счетчика с асинхронным сбросом (клик по картинке откроет схему на сайте http://www.falstad.com/ [31] где вы сможете ее корректировать по собственному желанию)
При достижении счетчиком значения "10" (b1010)- мы должны его сбросить. Этот же сигнал будет использоваться в качестве тактового для счетчика следующего разряда.
Цепочка RC используется для того, чтобы увеличить период сигнала достижения "10". Если этот сигнал будет слишком коротким, то некоторые триггеры могут не успеть сброситься, или поменять свое значение. Но применение асинхронного сброса в ПЛИС может привести к ряду проблем. Для того, чтобы увеличить период сигнала, мы применяем аналоговую схемотехнику, хотя разрабатываем цифровую схему. Если мы захотим применить такой подход в ПЛИС, то нам потребуется вывести этот сигнал наружу микросхемы — на внешний вывод, установить туда цепочку, и потом подать это обратно — уже на другой вход ПЛИС.
// counter
module cntr #(parameter width=4) (clk, res, out);
input wire clk, res;
output reg [width-1:0] out; initial out <= {width{1'b0}};
always @(posedge clk or posedge res) begin
if (res) begin
out <= 0;
end else begin
out <= out + 1'b1;
end
end
endmodule
В качестве эксперимента, я все-таки сделал часы на счетчиках с асинхронным сбросом. При этом никаких RC цепочек я не выводил и не использовал. Моей целью было выяснить, действительно ли не стоит использовать асинхронную логику, или "да ладно и так сойдет". До какого-то этапа часы исправно отсчитывали время
Но в тот момент, когда я решил добавить в часы мигание секунд, всё внезапно поломалось.
При разработке на ПЛИС настоятельно рекомендуется использовать синхронную логику. В случае с часами и счетчиком, текущее значение счетчика должно храниться в регистре, а следующее значение регистра мы должны вычислять комбинационной схемой. Следующее значение однозначно будет вычислено(мы надеемся на это) до наступления следующего такта, но загружено в регистр будет по фронту тактового импульса. То есть никаких "иголок" сброса проскакивать не будет. Исходя из текущих значений регистров, мы всегда однозначно определяем значение на следующем такте.
reg [3:0] s;// 0..9 - 4bit --регистр секунд
// флаг переполнения значения единиц секунд
wire s_cy = (s == 4'd9);
//вычисление следующего значения для регистра:
wire [3:0] next_s = (s_cy) ? 4'd0 : (s + 1'b1); //либо это текущее+1, либо 0, когда достигли 9
//меняем значение по положительному фронту тактового сигнала
always @(posedge clk1Hz) begin
s <= next_s;
end
Для вывода значения регистра на семисегментный индикатор, нам потребуется модуль преобразователя из двоичного в семисегментный код:
//bin to 7seg
module bcd2seg0_9(sin, sout);
input wire [3:0] sin;
output wire [6:0] sout;
reg [6:0] SEG_buf;
always @ (sin)
begin
case(sin)
4'h0: SEG_buf <= 7'b0111111;
4'h1: SEG_buf <= 7'b0000110;
4'h2: SEG_buf <= 7'b1011011;
4'h3: SEG_buf <= 7'b1001111;
4'h4: SEG_buf <= 7'b1100110;
4'h5: SEG_buf <= 7'b1101101;
4'h6: SEG_buf <= 7'b1111101;
4'h7: SEG_buf <= 7'b0000111;
4'h8: SEG_buf <= 7'b1111111;
4'h9: SEG_buf <= 7'b1101111;
default: SEG_buf <= 7'b0000000;
endcase
end
assign sout = SEG_buf;
endmodule
Для экономии ресурсов, описываем варианты только для чисел от 0 до 9. Для эксперимента, пробуем альтернативный модуль преобразователя:
//bin to 7seg
module bcd2seg(sin, sout);
input wire [3:0] sin;
output wire [6:0] sout;
assign sout = (sin==4'h0) ? 7'b0111111 :
(sin==4'h1) ? 7'b0000110 :
(sin==4'h2) ? 7'b1011011 :
(sin==4'h3) ? 7'b1001111 :
(sin==4'h4) ? 7'b1100110 :
(sin==4'h5) ? 7'b1101101 :
(sin==4'h6) ? 7'b1111101 :
(sin==4'h7) ? 7'b0000111 :
(sin==4'h8) ? 7'b1111111 :
(sin==4'h9) ? 7'b1101111 : 7'b0000000;
endmodule
Но объем затраченных ресурсов не изменился. Радуемся за умный синтезатор.
Дальше просто создаем регистры для секунд(единицы, десятки), минут(единицы, десятки), часов(единицы, десятки). Для каждого задаем расчет следующего значения. Но изменение значения секунд мы делаем при каждом секундном импульсе, а вот изменение значения десятков секунд — только при переполнении единиц. Соответственно, единицы минут меняются только когда переполнились и десятки и единицы секунд. И так далее.
При этом, синтез показал, что все отлично, но ячеек устройства уже не хватает. Упс. Для того, чтобы исправить ситуацию, решено секундный регистр упростить. Он все равно не выводится, поэтому два двоично-десятичных счетчика меняем на один двоичный от 0 до 59. А забегая немного вперед, я сделал его на один бит больше, зато сократил счетчик общего делителя частоты часового кварца. Поэтому счет идет от 0 до 119, но с частотой 2 Гц (см ниже, часть про установку времени).
//clk - general clock 32768
reg [13:0] clk_div; initial clk_div <= 14'd0; //?? не синтезируется в Lattice
always @(posedge clk) clk_div <= clk_div + 1'b1;
//регистры секунд, минут, часов
reg [6:0] sec;// 0..119
reg [3:0] m ;// 0..9
reg [3:0] mm ;// 0..5
reg [3:0] h ;// 0..9
reg [3:0] hh ;// 0..2
//следующие значения и переполнения
wire sec_cy = (sec == 7'd119);
wire [6:0] next_sec = (sec_cy) ? 7'd0 : (sec + 1'b1);
wire m_cy = (m == 4'd9);// && sec_cy;
wire [3:0] next_m = (m_cy) ? 4'd0 : (m + 1'b1);//(m_cy) ? 4'd0 : (m + ss_cy);
wire mm_cy = ((mm == 3'd5) &&(m == 4'd9));
wire [2:0] next_mm = (mm_cy) ? 3'd0 : (mm + 1'b1);
wire h_cy = (h == 4'd9)||((hh == 4'd2) && (h == 4'd3));
wire [3:0] next_h = (h_cy) ? 4'd0 : (h + 1'b1);
wire hh_cy = ((hh == 2'd2) && (h == 4'd3));
wire [1:0] next_hh = (hh_cy) ? 2'd0 : (hh + 1'b1);
//заносим новые значения в регистры
wire timer_clk = clk_div[13];
always @(posedge timer_clk) begin
sec <= next_sec;
m <= ( sec_cy) ? next_m : m;
mm <= ( m_cy&&sec_cy) ? next_mm : mm;
h <= ( mm_cy&&m_cy&&sec_cy) ? next_h : h;
hh <= (h_cy&mm_cy&&m_cy&&sec_cy) ? next_hh : hh;
end
Каждый регистр ЧЧ: ММ мы выводим на семисегментные индикаторы. Но перед этим преобразовываем в семисегментный код.
//семирязрядныли линии для вывода на семисегментники
wire [6:0] s_m;
wire [6:0] s_mm;
wire [6:0] s_h;
wire [6:0] s_hh;
//модули преобразования из двоичного в семисегментный код
bcd2seg0_9 sseg_m( .sin(m), .sout(s_m));
bcd2seg0_5 sseg_mm(.sin(mm), .sout(s_mm));
bcd2seg0_9 sseg_h( .sin(h), .sout(s_h));
bcd2seg0_2 sseg_hh(.sin(hh), .sout(s_hh));
Но у нас динамическая индикация. Причем, при выводе переключаются не отдельные семисегментные блоки, а отдельные элементы индикаторов. Поэтому, спустимся до уровня каждого элемента индикатора:
//отдельные элементы каждого индикатора
wire a1,b1,c1,d1,e1,f1,g1;
wire a2,b2,c2,d2,e2,f2,g2;
wire a3,b3,c3,d3,e3,f3,g3;
wire a4,b4,c4,d4,e4,f4,g4;
//разложим биты линий по отельным элементам
assign {g4, f4, e4, d4, c4, b4, a4} = s_m;
assign {g3, f3, e3, d3, c3, b3, a3} = s_mm;
assign {g2, f2, e2, d2, c2, b2, a2} = s_h;
assign {g1, f1, e1, d1, c1, b1, a1} = s_hh;
Дальше, исходя из схемы индикатора, понимаем, что там две линии по минусу. Будем их переключать по очереди:
wire led_line1 = (clk_div[7]); //8-й бит делителя частоты 32768 выдает нам частоту
wire led_line2 = (~led_gnd1);//динамического переключения сегментов 256 Гц
Присваиваем совмещенным линиям сегментов, соответствующие им значения, в зависимости от того, какая сейчас линия активна:
wire h_show = !(hh==0); //гасим ноль в десятках часов
assign led6 = (led_line1&&(b1&&h_show)) || (led_line2&&(b1&&h_show)); // b1
assign led7 = (led_line1&&(a1&&h_show)) || (led_line2&&(g1&&h_show)); // a1/g1
assign led8 = (led_line1&&(d1&&h_show)) || (led_line2&&(e1&&h_show)); // d1/e1
assign led9 = (led_line1&&e2) || (led_line2&&(c1&&h_show)); // e2/c1
assign led10 = (led_line1&&g2) || (led_line2&&b2); // g2/b2
assign led12 = (led_line1&&d2) || (led_line2&&c2); // d2/c2
assign led13 = (led_line1&&f2) || (led_line2&&a2); // f2/a2
assign led15 = (led_line1&&a3) || (led_line2&&f3); // a3/f3
assign led16 = (led_line1&&b3) || (led_line2&&g3); // b3/g3
assign led17 = (led_line1&&c3) || (led_line2&&d3); // c3/d3
assign led18 = (led_line1&&e4) || ((led_line2)&&e3); // e3/e4 !!
assign led19 = (led_line1&&g4) || ((led_line2)&&b4); // g4/b4
assign led20 = (led_line1&&d4) || ((led_line2)&&c4); // d4/c4
assign led21 = (led_line1&&f4) || ((led_line2)&&a4); // f4/a4
И тут выясняется, что ресурсов снова не хватает! В процессе борьбы за ресурсы были предприняты следующие шаги:
Переделал енкодер из bcd в семисегментный код. Обычный енкодер преобразует числа от 0 до 15 в шестнадцатиричный формат. В часах используется десятичная система для отображения, поэтому в енкодере были оставлены только цифры от 0 до 9, то есть вход — 4 бита и выход 10 вариантов семибитных слов. Но для десятков минут (от 0 до 5) достаточно 3 битного енкодера. То есть 6 вариантов. Похожая картина и для десятков часов. Только там вообще 3 цифры — от 0 до 2. И это уже 2 бита для входа енкодера и всего 3 варианта на выход. Все это наверняка должно было снизить сложность синтеза. Так и случилось! Количество использованных ячеек снизилось с 63 до 59.
Уменьшил разрядность регистров десятков минут и часов. Это снизит количество ячеек по количеству бит, плюс упростит схемы сумматоров.
reg [6:0] sec;// 0..119 - 7bit
reg [3:0] m ;// 0..9 - 4bit
reg [2:0] mm ;// 0..5 - 3bit
reg [3:0] h ;// 0..9 - 4bit
reg [1:0] hh ;// 0..2 - 2bit
В общей сложности, на момент начала оптимизаций было занято 63 из 64 ячеек, что ставило под вопрос возможность реализации не только возможных дополнительных функций, но и основных (таких, как установка времени). Теперь занято стало 56 макроячеек и 8 свободны. В процентном соотношении было 98%, стало 87%. Для такого малого объема это очень хорошо: около 10%!
Теперь, когда с ресурсами стало легче, займемся установкой времени. Решено сделать 3 кнопки: "часы", "минуты", "секунды". При нажатии и удерживании кнопки "часы", их значение должно увеличиваться. Те же условия и для кнопки "минуты". Сделать это просто: мы просто разрешаем записать в регистр новое значение при каждом такте, если нажата кнопка (а не только при переполнении младшего разряда).
При нажатии кнопки "секунды" — другая логика: секундный счетчик должен быть сброшен и счет секунд должен быть остановлен.
Для того, чтобы установка времени была более комфортной, скорость увеличения значения пришлось увеличить, а для этого частоту итогового тактового генератора выбрать не 1 Гц, а 2 Гц (об этом я писал выше). Это так-же сэкономило одну ячейку на делителе частоты, которому потребовалось на один разряд меньше.
input wire btn_HH, btn_MM, btn_SS; //кнопки часов, минут, секунд
wire timer_clk = clk_div[13];
always @(posedge timer_clk) begin
sec <= (btn_SS) ? 7'd0 : next_sec; //reset seconds
m <= ( sec_cy)||(btn_MM) ? next_m : m;
mm <= ( m_cy&&sec_cy)||(btn_MM&&m_cy) ? next_mm : mm;
h <= ( mm_cy&&m_cy&&sec_cy)||(btn_HH) ? next_h : h;
hh <= (h_cy&mm_cy&&m_cy&&sec_cy)||(btn_HH&&h_cy) ? next_hh : hh;
end
Как видим, два раза в секунду у нас проверяется сигнал переполнения или признак нажатия кнопки. В обоих случаях, часы или минуты увеличиваются. А значению секунд присваивается ноль, пока удерживается кнопка "секунды".
Для секундного индикатора нам уже не подходит какой-либо бит из регистра делителя частоты 32768. Потому что минимальная частота там — 2Гц, а мигать надо раз в секунду. Но два раза в секунду у нас увеличивается двоичный счетчик секунд. Поэтому просто возьем нулевой бит из этого счетчика:
assign led_second_tick = sec[0];
Высвобождение ячеек позволило добавить функционала. Одна из идей — сделать источник питания с резервной батареей. При наличии основного питания, часы могут работать в полноценном режиме, а в случае перехода на резервное питание — уходить в экономный режим: отключать индикацию и заниматься только подсчетом времени.
Для того, чтобы определить целесообразность этого функционала, нужно определить ток в штатном режиме и ток, который будет потреблять устройство в режиме энергосбережения. Можно ориентировочно посчитать, что при токе примерно в 10 мА на сегмент и не больше 12-ти одновременно работающих сегментов, мы получим только от индикации — 120 мА. Плюс сама ПЛИС потребляет энергию. Согласно документации — это должно быть порядка 10 мА.
Измерения показывают, что всё устройство в целом потребляет 125 мА. Это близко к расчетам. Добавляю в логику дополнительные условия и еще один сигнал на вход. Это сигнал перевода устройства в экономный режим. Управляющий сигнал будем брать с источника питания, с той части схемы, которая получает энергию из сети. Чтобы пользователь видел, что устройство работает, находясь в экономном режиме, добавим мигание секундным светодиодом. Частота будет та же, но заполнение не 50%, как в штатном режиме, а сделаем очень короткую вспышку. Для этого возьмем часть битов из счетчика-делителя частоты. На реализацию этой логики ушла всего одна ячейка.
input wire btn_SAFE; //входная линия с БП
wire SAFE_MODE = ~btn_SAFE; //когда идет 1 с БП, значит нормальный режим, инвертируем
//гасим линии вывода
wire led_line1 = (clk_div[7])&&(SAFE_MODE==0);
wire led_line2 = (~led_gnd1) &&(SAFE_MODE==0);
//корректируем вывод на секундный индикатор
assign led_second_tick = (sec[0]&&(!SAFE_MODE))||(sec[0]&&(clk_div[13:6]==10'd0)&&(SAFE_MODE));
Ток в режиме энергосбережения составил 18,5 мА. В принципе, это не так и мало. Однако, если найти примененную ПЛИС на сайте производителя, то она там классифицируется, как "architectures to offer a SuperFAST™ CPLD solution with low power". Супербыстрые — это до 400 МГц. У меня подозрения, что такой ток ради быстроты. Но в линейке есть более медленные и при этом экономные варианты: ispMACH 4064ZE, Operating Power Supply Current Vcc = 1.8V при этом ток 80 микроампер [34].
Для создания генератора, изначально решил попробовать использовать логические элементы ПЛИС [35]. Это было бы весьма оригинально и экономно. Однако, "что-то пошло не так" и такой вариант работать не стал. Причем даже на Cyclone, причем даже в случае создания железных буферов. Я думаю, конечно, можно заставить работать и такую схему, поиграв с параметрами обратной связи. В общем, нужно делать внешний генератор. Поискал схемы. Выбранная схема на транзисторах заработала, но параметры получаемого сигнала не позволили использовать ее в качестве генератора. В итоге решил собрать проверенную схему генератора — на ТТЛ микросхеме. Но на КР1533ЛА3 вот эта схема [36] не заработала. В итоге запустился генератор по мотивам вот этой схемы:
Осталась одна проблема: микросхема КР1533ЛА3 должна работать при напряжении 5В +- 10%, то есть от 4.5 до 5.5, а ПЛИС работает от 3.3 вольт. Однако, работа микросхемы происходит по сути в аналоговом режиме. Рискнул, запустил от 3.3 вольт — работает! Поставил часы походить.
Эксперимент по выбегу ротора турбин частоты генератора показал, что часы "бегут". За три часа набирается уже секунд 20. При тестировании на начальном этапе, в качестве генератора использовался Cyclone с делением частоты генератора 50 МГц. При этом какого-то ощутимого отклонения в ходе часов не наблюдалось. А тут за 6 часов все "убегает" на 2-3 минуты! Подводить часы каждый день неприемлемо. Поэтому я вернулся к схеме
Анализ схем такого рода навел меня на мысль о том, что тип микросхемы имеет какое-то значение. Во всех таких схемах применяется КМОП, а в моем случае была микросхема ТТЛ. Чтобы проверить эту гипотезу, я зашел в магазин и приобрел несколько микросхем 561-й серии. Среди них оказалась микросхема К561ЛА9. Изучение документации показало, что работать эта микросхема может от напряжений в диапазоне 3..18 вольт, что снимает вопрос о правильности её питания. Схема запустилась сразу, только не на 32768 Гц, а на какой-то более высокой гармонике. Резистор 100К пришлось увеличить до 300К. Поставил часы походить. За два дня часы убежали вперед примерно на 30 секунд. Это тоже не мало, но уже лучше, чем +3 минуты за 6 часов. Теперь можно подобрать конденсаторы в схему генератора для более установки более точного хода. И продумать способ построения частотомера, способного измерить такое отклонение частоты. Иначе настройка точности хода может затянуться. С помощью ПЛИС Cyclone и генератора на 50 МГц я набросал частотомер со временем измерения 1 и 10 секунд, данные читал с помощью SignalTap. В генератор поставил конденсаторы по питанию, подобрал конденсатор и подстроечный конденсатор частоты хода. Частоту вогнал в 32768 плюс минус точность измерений. За сутки хода, видимого на глаз отклонения не обнаружено. На этом с генератором все.
Чтение МРБ 1178 показало, что с часовыми кварцами можно достичь точности хода до 2 секунд в месяц. Считаю, что такое значение точности вполне достаточно для простых часов.
Согласно расчетам и измерениям, устройство потребляет не мало: 120 мА. Питать устройство изначально планировалось от электросети 220 вольт. Поэтому высокие значения КПД от преобразователя 220 -> 3.3 вольта — не требовались. При таких токах, линейный стабилизатор приведет к увеличению потребления, но при этом даст отличную надежность, в силу своей простоты. Вообще, я согласен, что надо беречь энергию и даже подобрал подходящие компоненты. Но у нас простые часы и я готов оплатить перерасход электроэнергии.
Сигнал о том, что напряжение в сети есть, будем брать с выхода стабилизатора. Если его там нету — гасим индикаторы!
Корпус выбрал маленький. Пришлось постараться, чтобы в него все поместилось. Некоторые стойки для монтажа накруткой пришлось обкусить. Блок питания придется использовать внешний. На корпус выведены кнопки установки часов, минут и сброса секунд.
В результате проделанной работы я пришел к следующим положительным выводам:
Я отлично провел время, изучая новую для себя ПЛИС, узнал много нового, пристроил подаренную микросхему, светодиодный экран и собрал часы для дачи. Желаю вам интересных проектов и отличного настроения!
Исходные коды проекта на GitHub:
https://github.com/UA3MQJ/fpga_simple_clock [38]
Автор: UA3MQJ
Источник [44]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/112654
Ссылки в тексте:
[1] DmitrySpb79: https://habrahabr.ru/users/dmitryspb79/
[2] источники точного времени: http://geektimes.ru/post/260556/
[3] элементную базу для создания электронных часов: https://geektimes.ru/post/261258/
[4] забыли про ПЛИС: https://geektimes.ru/post/261258/#comment_8801016
[5] Lattice Semiconductor Corporation: http://www.latticesemi.com/
[6] перечень изделий: http://www.latticesemi.com/Products.aspx
[7] Programmable Logic IC Development Tools MachXO3LF StarterKit: http://www.latticestore.com/products/tabid/417/categoryid/59/productid/25000/default.aspx
[8] FTDI: https://www.youtube.com/watch?v=tCq98g_AMPA
[9] 8 светодиодов: https://www.youtube.com/watch?v=RWNzZ8jf5eE
[10] digikey: http://www.digikey.ru/
[11] mouser: http://ru.mouser.com/
[12] Элитан: http://www.elitan.ru/price/index.php?find=LCMXO3LF-6900C-S-EVN&delay=-1&mfg=all&seenform=y
[13] LFXP2-5E-5QN208C: http://www.ebay.com/itm/1PCS-LFXP2-5E-5QN208C-IC-FPGA-146-I-O-208PQFP-ALTERA-NEW-GOOD-QUALITY-Q3-/301724765208
[14] pdf: http://www.mouser.com/ds/2/225/ispMACH4000VBCZFamilyDataSheet-760658.pdf
[15] семейства ispMACH 4000V/B/C/Z Family: http://www.latticesemi.com/en/Products/FPGAandCPLD/ispMACH4000VBCZ.aspx
[16] ispLEVER Classic: http://www.latticesemi.com/ispleverclassic
[17] Diamond Programmer: http://www.latticesemi.com/en/Products/DesignSoftwareAndIP/ProgrammingAndConfigurationSw/Programmer.aspx
[18] зарегистрироваться на сайт: https://www.latticesemi.com/Accounts/AccountRegister.aspx
[19] этим видео: https://www.youtube.com/watch?v=SmdEP_ZsBgM
[20] 300 рублей: http://www.ebay.com/itm/altera-Mini-Usb-Blaster-Cable-For-CPLD-FPGA-NIOS-JTAG-Altera-Programmer-/200943750380?hash=item2ec92e4cec:g:XSQAAOxylYZR5OwR
[21] 2000 рублей: http://ru.aliexpress.com/item/LATTICE-USB-download-cable-to-download-the-software-to-send-complete-accessories/32315769632.html?spm=2114.30010708.3.10.OZ5Pgu&ws_ab_test=searchweb201556_2,searchweb201644_1_10001_10002_10005_301_10006_10012_10003_10004_401_62_10007,searchweb201560_8,searchweb1451318400_6150,searchweb1451318411_6452&btsid=0fc102c3-0472-43f0-9df3-2e85ffc906f7
[22] 1300 рублей: http://ru.aliexpress.com/item/Lattice-CPLD-FPGA-USB-downloader-ispDOWNLOAD-Cables-Enterprise-Edition/32266168665.html
[23] отказался работать: http://www.youtube.com/watch?v=q4A2FLf90mg
[24] 1: https://habrastorage.org/files/b1f/4fd/1e8/b1f4fd1e82df4fe4bd0fbaa9a81417c0.jpg
[25] 2: https://habrastorage.org/files/ce1/a0c/62c/ce1a0c62ce4c45528ff14a1bed254470.jpg
[26] 3: https://habrastorage.org/files/014/fe9/edc/014fe9edc7e043868e5ba5d9699b3a23.jpg
[27] ПЛИС Altera Cyclone: https://habrastorage.org/files/afe/f02/338/afef023381b04ea9bf983bd1917445f0.jpg
[28] РадиоКот: http://radiokot.ru/forum
[29] схеме динамической индикации: https://habrastorage.org/files/b5e/f40/e6c/b5ef40e6cdd24b01a685c7c6e46f8358.jpg
[30] этой картинкой: https://habrastorage.org/files/d2a/3d1/d60/d2a3d1d60b0643358e1da1e52756c967.jpg
[31] http://www.falstad.com/: http://www.falstad.com/
[32] Image: http://www.falstad.com/circuit/circuitjs.html?cct=$+1+0.000005+10.200277308269968+50+5+50%0A156+80+208+128+208+0+0%0A156+208+208+240+208+0+5%0A156+336+208+368+208+0+0%0A156+464+208+480+208+0+0%0Aw+176+208+176+240+0%0Aw+176+240+208+240+0%0Aw+304+208+304+240+0%0Aw+304+240+336+240+0%0Aw+432+208+432+240+0%0Aw+432+240+464+240+0%0Aw+464+208+448+208+0%0Aw+448+208+448+272+0%0Aw+448+272+464+272+0%0Aw+448+272+448+320+0%0Aw+448+320+320+320+0%0Aw+320+320+320+272+0%0Aw+320+272+336+272+0%0Aw+320+272+320+208+0%0Aw+320+208+336+208+0%0Aw+208+208+192+208+0%0Aw+192+208+192+272+0%0Aw+192+272+208+272+0%0Aw+192+272+192+320+0%0Aw+192+320+320+320+0%0Aw+80+208+64+208+0%0Aw+64+208+64+272+0%0Aw+64+272+80+272+0%0Aw+64+272+64+320+0%0Aw+64+320+192+320+0%0AR+80+240+32+240+1+2+200+2.5+2.5+0+0.5%0AR+64+320+32+320+0+0+40+5+0+0+0.5%0Aw+560+208+560+48+0%0Aw+432+208+432+80+0%0Aw+304+208+304+112+0%0Aw+176+208+176+144+0%0AM+560+48+592+48+2+2.5%0AM+432+80+592+80+2+2.5%0AM+304+112+592+112+2+2.5%0AM+176+144+592+144+2+2.5%0A197+640+64+800+64+0%0Aw+576+144+576+160+0%0Aw+576+160+640+160+0%0Aw+576+144+176+144+0%0Aw+640+128+576+128+0%0Aw+576+128+576+112+0%0Aw+576+112+304+112+0%0Aw+640+96+576+96+0%0Aw+576+96+576+80+0%0Aw+576+80+432+80+0%0Aw+640+64+576+64+0%0Aw+576+64+576+48+0%0Aw+576+48+560+48+0%0A157+816+64+928+64+0%0Aw+768+64+816+64+0%0Aw+768+96+816+96+0%0Aw+768+128+816+128+0%0Aw+768+160+816+160+0%0Aw+768+192+880+192+0%0Aw+768+224+912+224+0%0Aw+912+224+912+192+0%0Aw+768+256+944+256+0%0Aw+944+256+944+192+0%0Ao+35+64+0+38+5+0.00009765625+0+-1%0Ao+36+64+0+38+5+0.00009765625+0+-1%0Ao+37+64+0+38+5+0.00009765625+0+-1%0Ao+38+64+0+38+5+0.00009765625+0+-1%0A
[33] Image: http://www.falstad.com/circuit/circuitjs.html?cct=$+1+0.000005+4.252108200006278+50+5+50%0A156+80+208+128+208+2+0%0A156+240+208+272+208+2+0%0A156+400+208+432+208+2+5%0A156+560+208+576+208+2+0%0Aw+208+208+208+240+0%0Aw+208+240+240+240+0%0Aw+368+240+400+240+0%0Aw+528+240+560+240+0%0Aw+560+208+544+208+0%0Aw+544+272+560+272+0%0Aw+384+272+400+272+0%0Aw+384+208+400+208+0%0Aw+240+208+224+208+0%0Aw+80+208+64+208+0%0Aw+64+208+64+272+0%0Aw+64+272+80+272+0%0Aw+64+272+64+320+0%0AR+80+240+32+240+1+2+200+2.5+2.5+0+0.5%0AR+64+320+32+320+0+0+40+5+0+0+0.5%0Aw+496+208+496+80+0%0Aw+336+208+336+112+0%0Aw+208+208+208+144+0%0AM+656+48+688+48+2+2.5%0AM+528+80+688+80+2+2.5%0AM+400+112+688+112+2+2.5%0AM+272+144+688+144+2+2.5%0A197+736+64+896+64+0%0Aw+672+144+672+160+0%0Aw+672+160+736+160+0%0Aw+672+144+272+144+0%0Aw+736+128+672+128+0%0Aw+672+128+672+112+0%0Aw+672+112+400+112+0%0Aw+736+96+672+96+0%0Aw+672+96+672+80+0%0Aw+672+80+528+80+0%0Aw+736+64+672+64+0%0Aw+672+64+672+48+0%0Aw+672+48+656+48+0%0A157+912+64+1024+64+0%0Aw+864+96+912+96+0%0Aw+864+128+912+128+0%0Aw+864+160+912+160+0%0Aw+864+192+976+192+0%0Aw+864+224+1008+224+0%0Aw+1008+224+1008+192+0%0Aw+864+256+1040+256+0%0Aw+1040+256+1040+192+0%0A150+368+432+496+432+0+2+0%0A150+800+448+928+448+0+2+0%0A150+704+432+784+432+0+2+0%0Aw+224+272+240+272+0%0Aw+224+208+224+272+0%0Aw+384+208+384+272+0%0Aw+544+208+544+272+0%0Aw+224+272+224+320+0%0Aw+224+320+64+320+0%0Aw+384+272+384+320+0%0Aw+384+320+224+320+0%0Aw+544+272+544+320+0%0Aw+544+320+384+320+0%0Aw+176+208+208+208+0%0Aw+272+144+208+144+0%0Aw+400+112+336+112+0%0Aw+528+80+496+80+0%0Aw+368+240+368+208+0%0Aw+368+208+336+208+0%0Aw+864+64+912+64+0%0Aw+656+208+656+48+0%0Aw+528+240+528+208+0%0Aw+528+208+496+208+0%0Aw+368+448+176+448+0%0Aw+176+448+176+272+0%0Aw+368+416+368+240+0%0Aw+704+416+704+208+0%0Aw+704+208+656+208+0%0Aw+704+448+544+448+0%0Aw+544+448+544+336+0%0Aw+544+336+496+336+0%0Aw+496+336+496+272+0%0Aw+784+432+800+432+0%0Aw+496+432+496+464+0%0Aw+496+464+800+464+0%0Aw+176+240+192+240+0%0Aw+192+240+192+576+0%0Aw+336+240+352+240+0%0Aw+352+240+352+576+0%0Aw+352+576+192+576+0%0Aw+496+240+512+240+0%0Aw+512+240+512+576+0%0Aw+512+576+352+576+0%0Aw+656+240+672+240+0%0Aw+672+240+672+576+0%0Aw+672+576+512+576+0%0Aw+1008+576+672+576+0%0Ar+928+448+976+448+0+100%0Ac+992+448+992+512+0+0.00001+2.8823090184623055e-9%0Aw+976+448+992+448+0%0Ag+992+512+992+528+0%0Aw+1008+576+1040+576+0%0Aw+1040+576+1040+448+0%0Aw+1040+448+992+448+0%0Ao+22+64+0+38+5+0.00009765625+0+-1%0Ao+23+64+0+38+5+0.00009765625+0+-1%0Ao+24+64+0+38+5+0.00009765625+0+-1%0Ao+25+64+0+38+5+0.00009765625+0+-1%0A
[34] 80 микроампер: http://www.latticestore.com/products/tabid/417/categoryid/12/productid/360/searchid/1/default.aspx?searchvalue=lc4064z*
[35] логические элементы ПЛИС: https://habrastorage.org/files/780/ef5/be2/780ef5be2dd544aa90aa79e17912a9b2.jpg
[36] эта схема: https://habrastorage.org/files/1e7/a09/45a/1e7a0945a7f94c20bdad179bdb844f03.gif
[37] флюса ТТ: http://we.easyelectronics.ru/warning_guano/flyus-gel-tt.html
[38] https://github.com/UA3MQJ/fpga_simple_clock: https://github.com/UA3MQJ/fpga_simple_clock
[39] Часы на ПЛИС с применением Quartus II и немного Verilog: https://habrahabr.ru/post/125364/
[40] Часы на ПЛИС: http://icdevices.ru/fpga/clock_on_fpga.html
[41] Особенности кварцевой стабилизации частоты генераторов: http://digteh.ru/WLL/KvGen.php
[42] Кварцевые генераторы: http://www.vecon.ru/prompub/290/5/
[43] Часики. GPS + LCD-дисплей WH0802: http://marsohod.org/projects/plata1/115-spaceclock
[44] Источник: https://habrahabr.ru/post/275863/
Нажмите здесь для печати.