Перейти к содержанию
    

Verilog. Проблема с асинхронным сбросом в always блоках

Нет, я не пропал. Простите.

 

Попытался запустить предложеный Вами код. Но...

Вопросов не поубавилось. Напротив ...

 

Для ясности на картинку "надел" имена сигналов использующихся в коде.

post-29795-1429213735_thumb.png

 

module PumpControl(
input clk_1Hz,
input pump,
input activate,

output reg alarm
);

//-------------------------------------------------------------------------------------------
reg [12:0] cntCharge	= 12'd0;	//	Счетчик необходимого кол-ва импульсов с датчика
reg [3:0]  cntTimer	=  4'd0;	//	Таймер времени ожидания, по истечению которого - авария
parameter countMin 	= 12'd5;	//	Кол-во импульсов с датчика, меньше которого - появится ошибка
parameter waitingTime	=  4'd10;	//	Время, за которое должно появится достаточное кол-во импульсов
reg stop		=  1'b0;
reg cntChargeQ		=  1'b0;

//  always 1  --- cntCharge
always @(negedge activate or posedge pump)
if (!activate)
	cntCharge <= 12'd0;
else if (stop || cntChargeQ)
	cntCharge <= 12'd0;
else
	cntCharge <= cntCharge + 1'b1;

//  always 2
always @(negedge activate or posedge pump)
if (!activate)
	cntChargeQ <= 1'b0;
else if (stop)
	cntChargeQ <= 1'b0;
else
	cntChargeQ <= (cntCharge == countMin - 12'd2); // -2 потому, что отсчет от нуля, и единица теряется при переносе

//  always 3  --- cntTimer
always @(negedge activate or posedge clk_1Hz)
if (!activate)
	cntTimer <= 4'd0;
else if (!stop)
	if (cntChargeQ)
		cntTimer <= 4'd0;
	else
		cntTimer <= cntTimer + 1'b1;

//  always 4
always @(negedge activate or posedge clk_1Hz)
if (!activate)
	stop <= 1'b0;
else if (!stop)
	stop <= (cntTimer == waitingTime - 4'd2);


//  always 5  --- alarm
always @*
if (!activate || cntChargeQ)
	alarm <= 1'b0;
else if (stop)
	alarm <= 1'b1;


endmodule

 

Код практически один в один, за исключением того, что сигнал activate был проинвертирован.

Ни в первом, ни во втором случае устройство в железе не заработало.

 

Вот так выглядит PTL. Но мне пока что затруднительно сопоставить это с кодом.

post-29795-1429215017_thumb.png

 

Попытался симулировать -компилятор пишет, мол, синтаксическая ошибка

Device family: MAX II
Running quartus eda_testbench
>> quartus_eda --gen_testbench --check_outputs=on --tool=modelsim_oem --format=verilog Mill_6520-F3_CPLD -c Mill_6520-F3_CPLD 
{--vector_source=D:/Projects/Mill_6520-F3_CPLD/output_files/Waveform.vwf} {--testbench_file=./simulation/qsim/Mill_6520-F3_CPLD.vt}
PID = 920
*******************************************************************
Running Quartus II 32-bit EDA Netlist Writer
 Version 13.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition
 Processing started: Fri Apr 17 00:14:24 2015
Command: quartus_eda --gen_testbench --check_outputs=on --tool=modelsim_oem --format=verilog Mill_6520-F3_CPLD -c Mill_6520-F3_CPLD 
--vector_source=D:/Projects/Mill_6520-F3_CPLD/output_files/Waveform.vwf --testbench_file=./simulation/qsim/Mill_6520-F3_CPLD.vt
Can't find port "clk_1Hz" in design
Can't find port "pump" in design
Can't find port "activate" in design
Can't find port "alarm" in design
Can't find port "cntCharge" in design
Can't find port "cntCharge[12]" in design
Can't find port "cntCharge[11]" in design
Can't find port "cntCharge[10]" in design
Can't find port "cntCharge[9]" in design
Can't find port "cntCharge[8]" in design
Can't find port "cntCharge[7]" in design
Can't find port "cntCharge[6]" in design
Can't find port "cntCharge[5]" in design
Can't find port "cntCharge[4]" in design
Can't find port "cntCharge[3]" in design
Can't find port "cntCharge[2]" in design
Can't find port "cntCharge[1]" in design
Can't find port "cntCharge[0]" in design
Can't find port "cntChargeQ" in design
Can't find port "cntTimer" in design
Can't find port "cntTimer[3]" in design
Can't find port "cntTimer[2]" in design
Can't find port "cntTimer[1]" in design
Can't find port "cntTimer[0]" in design
Can't find port "Stop" in design
Generated Verilog Test Bench File ./simulation/qsim/Mill_6520-F3_CPLD.vt for simulation
Quartus II 32-bit EDA Netlist Writer was successful. 0 errors, 25 warnings
 Peak virtual memory: 276 megabytes
 Processing ended: Fri Apr 17 00:14:34 2015
 Elapsed time: 00:00:10
 Total CPU time (on all processors): 00:00:02
Running quartus eda_func_netlist
>> quartus_eda --functional=on --simulation --tool=modelsim_oem --format=verilog Mill_6520-F3_CPLD -c Mill_6520-F3_CPLD 
PID = 1272
*******************************************************************
Running Quartus II 32-bit EDA Netlist Writer
 Version 13.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition
 Processing started: Fri Apr 17 00:14:43 2015
Command: quartus_eda --functional=on --simulation=on --tool=modelsim_oem --format=verilog Mill_6520-F3_CPLD -c Mill_6520-F3_CPLD
Generated file Mill_6520-F3_CPLD.vo in folder "D:/Projects/Mill_6520-F3_CPLD/simulation/modelsim/" for EDA simulation tool
Quartus II 32-bit EDA Netlist Writer was successful. 0 errors, 0 warnings
 Peak virtual memory: 276 megabytes
 Processing ended: Fri Apr 17 00:14:49 2015
 Elapsed time: 00:00:06
 Total CPU time (on all processors): 00:00:03
*******************************************************************
Running quartus modelsim
>> vsim -c  -do Mill_6520-F3_CPLD.do
PID = 1268
 Reading C:/altera/13.0sp1/modelsim_ase/tcl/vsim/pref.tcl 

 # 10.1d

 # do Mill_6520-F3_CPLD.do 
 # ** Warning: (vlib-34) Library already exists at "work".
 # 
 # Model Technology ModelSim ALTERA vlog 10.1d Compiler 2012.11 Nov  2 2012
 # -- Compiling module \Mill_6520-F3_CPLD 
 # 
 # Top level modules:
 # 	\Mill_6520-F3_CPLD 
 # Model Technology ModelSim ALTERA vlog 10.1d Compiler 2012.11 Nov  2 2012
 # ** Error: Mill_6520-F3_CPLD.vt(29): near "-": syntax error, unexpected '-', expecting import or ';' or '#' or '('
 # ** Error: c:/altera/13.0sp1/modelsim_ase/win32aloem/vlog failed.
 # Executing ONERROR command at macro ./Mill_6520-F3_CPLD.do line 4

post-29795-1429215916_thumb.png

 

Блин. Руки опускаются.

 

Ну, теперь по существу:

По поводу

Зачем разрядность 8 если вы считаете до 50

В реальном железе, теоретически, частота импульсов в районе 240 Гц. Т.е. 12 бит - впритык. Но, на самом деле, я это узнаю, когда железяка заработает в комплексе. Да и отношения к делу это не имеет.

 

На счет "Эта операция дешевле", "Здесь ЛУТов меньше" - не спорьте, и уж, тем более, не паникуйте.

Во - первых, у меня два плюс два нифига не работает и код похож на бред.

Во - вторых, в моем случае плисина практически "бездельничает".

 

А вот на счет глитчей и глюков и т.п. - это уже по существу.

 

Асинхронное формирование сигнала сброса из 8-и разрядного регистра чревато возникновением паразитных фронтов
Но, управление от "cnt1Q" я бы сделал асинхронным, так как не уверен, что он будет длиться достаточно

Я не "осязаю" прохождения сигналов на уровне ключей внутрях ПЛИС, но если обстрагироваться дискретной логикой, то не ясно, как может что-то испортить сигнал сброса в принципе. При активном ресете все выходы, все регистры должны находится в нулях и не зависеть от других входных сигналов.

 

На счет

Промежуточные выходы конца счета сделаны отдельными дополнительными регистрами, чтобы избежать там глитчей
Подразумевается случайное "укорочение" из-за появления внешнего сигнала или в задержках между ЛУТами.

Внешние сигналы можно запустить через D-триггеры, тактируемые системным клоком. Но, конкретно в этой задаче, плюс-минус один тик счетчиков на работу механизма влияния не оказывает.

 

И вот:

При попытке использовать сигнал activate асинхронно, компилятор говорит "Error (10122): Verilog HDL Event Control error at PumpControl.v(18): mixed single- and double-edge expressions are not supported"

Если negedge заменить на posedge, то ошибка "Error (10200): Verilog HDL Conditional Statement error at PumpControl.v(19): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct"

Че ему, заразе, нужно?

 

В том виде, в котором код приведен, схема работает так:

При поступлении сигнала activate, спустя одну секунду появляетя сигнал на выходе alarm. Горит до исчезновения activate.

Импульсы на входе pump никогда никакого влияния не оказывают.

Во время эксперимента Clock подаю частотой 10Гц.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вот тут Вы в корне не правы. Проверка на > или < - это сумматор (вычитатель, точнее), со всеми вытекающими цепями переноса. Проверка на == и != это древесная структура XOR - OR - ... - OR, которая в принципе быстрее сумматора, причем убыстрение растет экспоненциально с увеличением разрядности.
Спорить не буду, не проверял быстродействие, но рациональное зерно в рассуждениях конечно есть.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Операция ==0 значительно дешевле <Х

 

Сказано: дешевле.

Это комплексный критерий учитывающий стоимость разработки, отладки, ресурс, быстродействие, надежность, термостабильность, энгопотребление и даже эстетику.

 

Для тех кто не наигрался:

 

Изучаете архитектуру фпга,

Планируете как ляжет в железо ваш счетчик

Описываете на верилоге

Смотрите как легло

Повторяете предыдущие 2 пункта пока не ляжет как было запланировано

 

Некоторые крестьяне верят в участие высшей силы, которая помогает описанию

Иф (цнт==0)

Цнт <=49

Елсе

Цнт <= цнт - 1

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

 

И еще, для крестьян, пытающихся удивить компилятор изысканными выражениями в скобках: поверьте, он не оценит - это тупой алгоритм созданный группой в меру кривых рук управляемых чуть более осведомленным мосжечком чем ваш. Пишите проще и понятней.

Изменено пользователем Hose

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот так выглядит PTL. Но мне пока что затруднительно сопоставить это с кодом.

 

Расшифрую:

 

1) cntCharge:

на его вход данных поступает мультиплексировано либо 0, либо его выход + 1, на асинхронный сброс (clrn) подан activate. Мультиплексор управляется по "stop | cntChargeQ" - это его синхронный сброс.

 

2) cntChargeQ

тут просто - если есть stop, то он обнуляется (мультиплексором), иначе на вход передает выход компаратора. Но!!! Компаратор сравнивает с числом 13'h0003!!!! вместо требуемых 48 (поэтому, скорее всего, схема и не работает).

 

3) cntTimer. На вход nENA ему подан Stop. Это заместо элемента "ИЛИ" по клоку на исходной схеме - пришел Stop, запретили счет. на его вход, по аналогии с первым счетчиком, идет мультиплексировано либо его выход+1, либо 0 (синхронный сброс). Управляется от cntChargeQ.

 

4) stop - по аналогии с предыдущим cntChargeQ, только вместо nENA (и вместо элемента "ИЛИ" в оригинальной схеме) запрет сделан мультиплексором, так как запрещает он сам себя в единице.

 

5) RS-триггер на выходе. тут все просто - RS-триггер - сбрасывается по activate | cntChargeQ, устанавливается по stop.

 

 

Ну, теперь по существу:

По поводу

В реальном железе, теоретически, частота импульсов в районе 240 Гц. Т.е. 12 бит - впритык. Но, на самом деле, я это узнаю, когда железяка заработает в комплексе. Да и отношения к делу это не имеет.

Это к делу имеет самое первейшее отношение. Чтобы синхронно сбросить cntTimer, надо подать на сброс такой импульс, чтобы во время фронта clk_1Hz был активный уровень на сбросе. У Вас счетчик cntChargeQ считает на 240 герцах - теперь представьте себе вероятность того что такой короткий импульс сброса попадет на фронт 10 герцового клока!

 

поэтому, я и сказал, что, скорее всего, cntChargeQ надо использовать асинхронно:

 

reg [5:0] cnt1;
reg [3:0] cnt2;
reg Alarm;
reg Stop;
reg cnt1Q;

/* First counter */

always @(posedge Charge or posedge Activate)
if (Activate) cnt1 <= 6'd0;
else if (Stop || cnt1Q) cnt1 <= 6'd0;
else cnt1 <= cnt1 + 1'b1;

always @(posedge Charge or posedge Activate)
if (Activate) cnt1Q <= 1'b0;
else if (Stop)  cnt1Q <= 1'b0;
else cnt1Q <= (cnt1 == 6'd48);

wire reset_cnt2 = Activate | cnt1Q;

/* Second counter */
always @(posedge clk1hz or posedge reset_cnt2)
if (reset_cnt2) cnt2 <= 4'd0;
else if (!Stop) cnt2 <= cnt2 + 1'b1;

always @(posedge clk1hz or posedge Activate)
if (Activate) Stop <= 1'b0;
else if (!Stop) Stop <= (cnt2 == 4'd8);

/* Alarm */
always @*
if (Activate || cnt1Q) Alarm <= 1'b0;
else if (Stop) Alarm <= 1'b1;

 

Но, в таком раскладе могут быть неприятности из-за длинных счетчиков и попадания фронтов клока неудачным образом, да и из-за метастабильных состояний при этих раскладах. Это, раз. А два - если CntCharge досчитает до своего конечно состояния, и на этом клок остановится, то и вачдог зависнет, как будто, клок продолжается. Поэтому, сигнал сброса следует хитро пропустить по кругу через clk_1HZ, чтобы, даже при прекращении клока pump никогда не было такого, чтобы cntChargeQ застрял в 1. Но, об этом сами подумайте, когда разберетесь, в чем тут дело. Кстати, если этот "хитрый пропуск" сделать еще и грамотно - то он снимет и потенциальные первые проблемы, с неудачно ложащимися фронтами.

 

UPD:

И, вообще, я бы сделал так - на pump поставил бы делитель с выходом типа "меандр", далее пропустил бы этот меандр через трехбитный сдвиговый регистр, работающий на частоте clk_1HZ, а сброс cntTimer сделал бы от XOR двух старших бит этого сдвигового регистра. Таким образом снимаются вообще все проблемы разом.

 

reg [5:0] cnt1;
reg [3:0] cnt2;
reg Alarm;
reg Stop;
reg cnt1Q;
reg [2:0] sh_reg;

/* First counter */

wire cnt1_end = (cnt1 == 6'd49);

always @(posedge Charge or posedge Activate)
if (Activate) cnt1 <= 6'd0;
else if (Stop || cnt1_end) cnt1 <= 6'd0;
else cnt1 <= cnt1 + 1'b1;

/* divider by 2 (for 50/50 duty) */

always @(posedge Charge or posedge Activate)
if (Activate) cnt1Q <= 1'b0;
else if (Stop)  cnt1Q <= 1'b0;
else if (cnt1_end) cnt1Q <= ~cnt1Q;

/* Shift register */

always @(posedge clk1hz or posedge Activate)
if (Activate) sh_reg <= 3'd0;
else sh_reg <= {sh_reg[1:0], cnt1Q};

/* XOR gate (rise/fall detector) */

wire reset_cnt2 = ^sh_reg[2:1];

/* Second counter */

always @(posedge clk1hz or posedge Activate)
if (Activate) cnt2 <= 4'd0;
else if (reset_cnt2) cnt2 <= 4'd0;
else if (!Stop) cnt2 <= cnt2 + 1'b1;

always @(posedge clk1hz or posedge Activate)
if (Activate) Stop <= 1'b0;
else if (!Stop) Stop <= (cnt2 == 4'd8);

/* Alarm */

always @*
if (Activate || cnt1Q) Alarm <= 1'b0;
else if (Stop) Alarm <= 1'b1;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня есть вопрос!

 

как связаны сигналы в новой интерпретации

pump и clk_1HZ.

 

Если эти сигналы асинхронные и никак не связаны, их надо синхронизовать, потому что cntChargeQ рождается по клоку pump, а используется по клоку clk_1HZ и несмотря на то что сигнал вроде как 1 проводок, беда все равно может быть...

 

Если есть возможность синхронизовать по входу, то вы можете привести всю схему к работе от 1 клока синхронно и будет у вас счастье и не будет заморочек, даже асинхронный ресет вам будет не нужен.

 

Если ПЛИС бездельничает ну запустите на ней PLL на 1 МГц (наверняка входная частота какая то есть), пропустите оба входных сигнала и 1HZ и pump через 3 триггера. 1Hz можно даже опустить в таком случае и 10 сек отсчитывать по клоку 1MHz сразу...

 

reg [2:0] PumpR = 0;

 

always @(posedge clk_1MHz)
  begin
    PumpR <= {PumtR[1:0], pump};
  end

 

и тогда можно считать импульсы как

 

always @(posedge clk_1MHz)
   begin
     if((PumpR[2] == 0) && (PumpR[1] == 1))
       Cnt <= Cnt + 1'b1;
   end

 

время 10 секунд у вас пойдет по тому же самому клоку, никакой асинхронщины, никаких глитчей, вообще полный коммунизм и счастие!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И, вообще, я бы сделал так - на pump поставил бы делитель с выходом типа "меандр", далее пропустил бы этот меандр через трехбитный сдвиговый регистр, работающий на частоте clk_1HZ, а сброс cntTimer сделал бы от XOR двух старших бит этого сдвигового регистра. Таким образом снимаются вообще все проблемы разом.

Проблема в этом случае в том, что возможно ложное срабатывание, если pump будет иметь среднюю частоту 100Гц, тогда в домене 1Гц вместо меандра будет видна константа.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема в этом случае в том, что возможно ложное срабатывание, если pump будет иметь среднюю частоту 100Гц, тогда в домене 1Гц вместо меандра будет видна константа.

 

Ну, разумеется, все поделить на столько, чтобы проблем не было.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...