Добро пожаловать, Гость
Логин: Пароль: Запомнить меня
  • Страница:
  • 1

ТЕМА: Грабли с логикой, счетчиком и асинхронным сбросом

Грабли с логикой, счетчиком и асинхронным сбросом 10 года 11 мес. назад #2011

  • Ezhik
  • Ezhik аватар Автор темы
  • Не в сети
  • Новый участник
  • Новый участник
  • Сообщений: 2
  • Спасибо получено: 0
Возможно, то, о чем я расскажу, где-то подробно описано. Может это "основы основ", которые я ввиду своей неопытности проморгал.
С другой стороны, из этого поста, наверное, можно сделать небольшую статейку-иллюстрацию, ибо пример довольно поучителен.

Все описанное ниже проводилось в среде Quartus II 13.0sp1, железо - плата DE0, плис Cyclone III ( www.terasic.com.tw/cgi-bin/page/archive....guage=English&No=364 )
Тактовая частота - всего лишь 50 МГц, а в программе SignalTap - 100МГц.

Потребовалось мне как-то сделать совершенно примитивный модуль - одновибратор со счетчиком. По сигналу он выдает импульс заданной длины и счетчик, который считает, пока этот импульс держится. Также мне нужен был сигнал сброса. По привычке сделал этот сброс асинхронным.
Получилось что-то такое:
always @(posedge clk or negedge reset_n)	
begin
	if(~reset_n)
	begin
		pulseR <= 0;
		q_pulseR <= 0;
	end
	
	else
	begin
		if(start)
			pulseR <= 1;
		
		if(pulseR)
			q_pulseR <= q_pulseR + 1;
		else
			q_pulseR <= 0;
			
		if(q_pulseR + 1 == width)
			pulseR <= 0;

	end
end
Ну и, чтобы проверить работу прямо в железе, в программе signaltap, я создал длинный счетчик. примерно так:
reg [31:0] cnt_max;

always @(posedge clk)
    cnt_max<=cnt_max+1;

// далее где-то в коде я подаю на вход своего модуля сигнал start:
.start(cnt_max == 15)
Я думаю, бывалые плисоводы сразу догадаются, что из такого может получиться.
Запускаю, смотрю. Не работает: импульс не появляется, счетчик не считает, крокодил не ловится. При том, что в signaltap-e этот самый start виден.
Почему-то не срабатывает условие if(start).
Провожу несколько экспериментов. В частности, когда я сделал сброс синхронным, убрав "or negedge reset_n", все по волшебству заработало.
Ниже скриншот двух случаев: с асинхронным ресетом и с синхронным.


Тактовая частота делается в PLL, все констрейны, связанные с клоками в sdc-файле прописаны. Критических предупреждений не было.
Я очень надеюсь, что бывалые плисоводы смогут в комментариях дать подробный ответ, почему так получается и укажут мне, что я упустил из виду.



Однако, я провел исследования и пришел к следующим выводам:

1) очевидно, конструкция с асинхронным ресетом синтезируется так, что в некоторых случаях при несоблюдении каких-то правил, возникают подобные эффекты.
решение 1: сделать ресет синхронным.

2) комбинационная логика в условии.
решение 2: можно ее предварительно защелкнуть в регистр, и все заработает.
reg start;
always @(posedge clk)
    start <= cnt_max == 14; // когда счетчик будет равен 15 на следующем такте, start выставится в 1.
можно также сделать запись в регистр в самом модуле, но тогда появится задержка в 1 такт.

3) использование длинного счетчика. тут на выбор аж три варианта
решение 3: использовать короткий счетчик. Если сделать 8 бит вместо 32 - все будет работать.
решение 4: сделать длинный счетчик с переносом (это я подсмотрел в руководстве "TimeQuest для чайников")
always @(posedge clk)
begin
   cnt_max[7:0] <= cnt_max[7:0] + 1;
   if(cnt_max[7:0] == 8'hFF)
   begin
        cnt_max[15:8] <= cnt_max[15:8] + 1;
        ... // и так далее до старших разрядов
   end
end
решение 5: использовать мегафункцию lpm_counter -- не проверял, но по идее она сама должна в зависимости от ПЛИС правильно синтезировать счетчик.

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

Re: Грабли с логикой, счетчиком и асинхронным сбросом 10 года 11 мес. назад #2038

  • Falcon
  • Falcon аватар
  • Не в сети
  • Осваиваюсь на форуме
  • Осваиваюсь на форуме
  • Сообщений: 31
  • Спасибо получено: 8
Так было бы более наглядней и понятней.
always @(posedge clk or negedge reset_n)	
begin
	if(~reset_n)
	begin
		pulseR <= 0;
		q_pulseR <= 0;
	end
	
	else
	begin
		if(start)
			pulseR <= 1;
		
		if(pulseR)
                   if(q_pulseR != width - 1)
			q_pulseR <= q_pulseR + 1;
		   else
                  begin
		    	q_pulseR <= 0;
                         pulseR <= 0;
                 end


	end
end
Смотрите где то вы с ресетом на портачили
так как такая запсиь
always @(posedge clk or negedge reset_n)	
begin
	if(~reset_n)
спокойно приводит к ошибке
где то инвертор забыли поставить или на оборот лишний поставили и все.

Так что гораздо правильнее ставить инвертор только в главном модуле а в остальных писать так
always @(posedge clk or posedge reset_n)	
begin
	if(reset_n)

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

Последнее редактирование: от Falcon.

Re: Грабли с логикой, счетчиком и асинхронным сбросом 10 года 11 мес. назад #2039

  • Ezhik
  • Ezhik аватар Автор темы
  • Не в сети
  • Новый участник
  • Новый участник
  • Сообщений: 2
  • Спасибо получено: 0
1) Суть этой темы не в том, как лучше реализовать данный модуль. Какой вариант лучше синтезируется - отдельный вопрос.
В Вашем и в моем варианте в любом случае условие if(start) при определенных обстоятельствах не сработает.
В этом, а не в том, как лучше код оформить, я предлагаю детально разобраться. :)

2) Что в микроконтроллерах, что во многих ТТЛ-микросхемах, что в готовых мегакорках для ПЛИС в т.ч. и от Альтеры, очень часто принято сброс делать логическим "0", хотя и исключения видел.
Первое что нашел в гугле - www.electronicspoint.com/why-reset-gener...neg-edge-t74773.html
В моем модуле в самом наименовании сигнала есть подсказка: Постфикс "_n" как раз и означает, что для сброса необходимо подать "0".
Ну и скриншоты с сигналтапа содержат сигнал сброса, и он на всех скриншотах в лог "1".
Так что уровень сигнала сброса тут ни при чем. Тем более, что синтезируются они практически одинаково.

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

  • Страница:
  • 1
Время создания страницы: 0.123 секунд
Работает на Kunena форум