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

не понятна разница в коде

Доброго времени суток. )))

Итак суть проблемы.

Пытаюсь , значит, описать счётчик для инкрементального энкодера. Обработка двух битного кода грея.

Сделано по синхронной схеме. CLK - порядка 20МГц, а сигналы энкодера 20-30 Кгц.

Реализация на Xilinx.

 

 

reg[31:0] count_enc[4:0];
reg[1:0] num0,l_enc0;

always @(posedge clk or negedge RST)	
	if(~RST) 
		begin
			count_enc[0] <= 32'b0;
		end 
	else
		begin

			case ({l_enc0,encd[1],encd[0]})
				4'b0001: num0 <= 2;
				4'b0010: num0 <= 1;
				4'b0100: num0 <= 1;
				4'b0111: num0 <= 2;
				4'b1000: num0 <= 2;
				4'b1011: num0 <= 1;
				4'b1101: num0 <= 1;
				4'b1110: num0 <= 2;
			default num0 <= 0;	
			endcase	

					if (num0 == 1)
						count_enc[0] <= count_enc[0] + 1'b1;

					if (num0 == 2)
						count_enc[0] <= count_enc[0] - 1'b1;

					l_enc0 <= {encd[1],encd[0]};

		end

 

Результат выше приведённого кода - счётчик считает, но иногда(редко) происходит набег(может и пропуск) счётчика.

Но если написать так:

 

reg[31:0] count_enc[4:0];
reg[1:0] num0,l_enc0;

always @(posedge clk or negedge RST)	
	if(~RST) 
		begin
			count_enc[0] <= 32'b0;
		end 
	else
		begin

			case ({l_enc0,encd[1],encd[0]})
				4'b0001: num0 <= 2;
				4'b0010: num0 <= 1;
				4'b0100: num0 <= 1;
				4'b0111: num0 <= 2;
				4'b1000: num0 <= 2;
				4'b1011: num0 <= 1;
				4'b1101: num0 <= 1;
				4'b1110: num0 <= 2;
			default num0 <= 0;	
			endcase	

					if (num0 == 1)
						begin
						count_enc[0] <= count_enc[0] + 1'b1;
						l_enc0 <= {encd[1],encd[0]};
						num0 <= 0;
						end

					if (num0 == 2)
						begin
						count_enc[0] <= count_enc[0] - 1'b1;
						l_enc0 <= {encd[1],encd[0]};
						num0 <= 0;
						end

		end

Чисто случайно вот так попробовал, и заработало..... Никаких пропусков и набегов.

Вопрос, в чём отличие, почему второе описание работает всегда верно, а первое нет? Где разница в работе?

В тестбенче логика одинаковая.

 

А ели в следующий раз случайно не попаду, как узнать, что проблема в коде, а не в электронике?

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


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

расклад в том что default num0 <= 0; - даст 0 только на следующем такте, поэтому во втором варианте - на следующем такте команда полюбому будет отменена, а в первом варианте эта отмета отложена будет на еще один такт.

 

этот стил автомата весьма неудобен. попробуйте переписать его с использованием переменных процессса вместо сигналов - это те что с оператором = работают а не <=

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

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


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

Ну значит так. В первом примере когда есть разница происходит в

 

первом такте: устанавливается NUM0 = 1 или 2, но прибавления или вычитания не происходит, т.к. на этом такте ещё NUM0 = 0, и выравниваются значения l_enc0 <= {encd[1],encd[0]}

второй такт: NUM0 = либо ноль, если снова не произошла разница , либо всё как в 1 такте, и происходит прибавление или вычитание(из предыдущего такта)

Т.е. алгоритм на каждом такте сравнивает состояния между тактами, а вычисление происходит на отставание на один такт.

 

 

А во втором:

первом такте: устанавливается NUM0 = 1 или 2, но прибавления или вычитания не происходит, т.к. на этом такте ещё NUM0 = 0, и не выравниваются значения l_enc0 <= {encd[1],encd[0]}(И из-за этого сравнение во втором такте будет не с тем что было в первом, а с тем что было в 0 такте)(работать должно наоборот - хуже, а не лучше)

 

второй такт:В операторе CASE NUM0 = остаётся тем же, т.к. не выравниваются значения l_enc0 <= {encd[1],encd[0]} если снова не произошла разница ,а если произошло изменение, то NUM0 = 0, т.к. относительно значения 0 такта будет или 2-я разница или равенство(т.е пропуск одного изменения), происходит прибавление или вычитание(из предыдущего такта), а потом уже обнуление(оно нужно для того, чтобы не происходило повторное прибавление или вычитание, т.к. операторе CASE NUM0 = остаётся тем же)

 

 

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

Однако на деле всё наоборот. Уже голову всю сломал :)

 

Для уточнения: две строки num0 <= 0 во втором примере можно убрать и работать будут без пропусков, просто будет прибавлять и отнимать значение 2 раза, ну соответственно можно на 2 поделить и всё.

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

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


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

Сделано по синхронной схеме. CLK - порядка 20МГц, а сигналы энкодера 20-30 Кгц.

сигналы энкодера идут с внешних ног плиса?

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


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

Да

а через пару регистров пропустили перед подачей на комбинационную логику ? грей греем, но реклокнуть то надо

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


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

Нет, сразу на триггеры.

Я просто на плис не так давно пишу, может чего не знаю, а в чём фишка?

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


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

Нет, сразу на триггеры.

еще раз: на триггеры или сразу на case ({l_enc0,encd[1],encd[0]})?

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


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

Просто по логике вещей, приходит сигнал в некий момент времени, я его опрашиваю в нужные мне моменты, просто частота опроса на несколько порядков выше, да и всё вроде. Зачем ещё регистры.....

Сразу на схему case ({l_enc0,encd[1],encd[0]})

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

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


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

Просто по логике вещей, приходит сигнал в некий момент времени, я его опрашиваю в нужные мне моменты, просто частота опроса на несколько порядков выше, да и всё вроде. Зачем ещё регистры.....

вы "опрашиваете" его в обоих примерах асинхронно. Но в коде 2, моменты принятия решений таковы, что метастабильное состояние, вызванное асинхронным опросом, маскируется и не влияет. Пропустите сигналы энкодеров хотя бы через триггеры в IO падах.

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


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

за тем что if в ПЛИС выполняется или не выполняется не разом как в проце, а для каждого элемента под if отдельно

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


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

Пытаюсь , значит, описать счётчик для инкрементального энкодера.

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

Обычно обработка реализуется на FSM (конечном автомате). Советую сразу к нему и перейти, будет лучше всем….

Начните с построения графа состояний FSM, учитывая при этом, что энкодер может считать в обоих направлениях…

А уже после графа код на verilog...

 

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


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

Извините, ежели чего туповатого спрашиваю, просто хотел бы разобраться. Я ж не волшебник,я только учусь :).

 

Пропустите сигналы энкодеров хотя бы через триггеры в IO падах.

 

Вот этого я не понимаю как делать.

Пропустите сигналы энкодеров хотя бы через триггеры в IO падах.

У меня

input: [9:0] enc

ну и сразу на схему.

 

Подскажите как написать то что вы имели ввиду.

 

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

 

Я вот не согласен в обоих примерах асинхронно!!!!! Естественно проблема в переходном процессе, и логическое отличие двух примеров в том, что первый пример на каждом CLK сравнивает с состоянием на предыдущем такте, в во втором примере, пророй сравнивается с состоянием на один такт до предыдущего(тот случай, когда на первом и на втором тактах происходит изменение).

Т.е. в эти случаи счётчик не будет изменяться. Может это и работает, но не понятно почему... Ну да ладно.

 

У меня конечно же вопрос в том, почему не правильно работает первый пример???

 

Ибо если сигнал допустим на enc0 идёт из нуля в единицу с переходным процессом, и схема отрабатывает то что в момент перехода он несколько раз прыгает назад в ноль и возвращается в конечном итоге в 1, то просто многократно происходит прибавление и вычитание единички. Но в конце переходного процесса результат должен быть одинаков, и соответствовать этому переходу.

 

за тем что if в ПЛИС выполняется или не выполняется не разом как в проце, а для каждого элемента под if отдельно

 

Я так понял что это про if из которых case состоит.

(В этом есть рациональное зерно...).

Однако - точно такая же конструкция стоит и во втором примере, который работает правильно. Чем тогда можно это аргументировать.

Типа в первом примере эти if так работают, а в этом сяк.

 

 

 

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

Обычно обработка реализуется на FSM (конечном автомате). Советую сразу к нему и перейти, будет лучше всем….

Начните с построения графа состояний FSM, учитывая при этом, что энкодер может считать в обоих направлениях…

А уже после графа код на verilog...

 

Спасибо....

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

Если где ошибаюсь, ткните мордочкой :).

 

http://club.shelek.ru/viewart.php?id=369

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

 

за тем что if в ПЛИС выполняется или не выполняется не разом как в проце, а для каждого элемента под if отдельно

 

Ну вот этот фактор походу сильно влияет в данном случае. Сделал вот так

always@(negage clk)

encA[1:0] <= {encd[1],encd[0]}

 

и заменил сигналы на encA[1],encA[0]. И первый вариант заработал. Огромное спасибо.............

Буду теперь знать.

 

А второй вариант, из-за

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

Пропустите сигналы энкодеров хотя бы через триггеры в IO падах.

 

И последний вопрос связанный с этим ( триггеры в IO падах). Как это использовать.... Подскажите.

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

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


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

Ну вот этот фактор походу сильно влияет в данном случае. Сделал вот так

always@(negage clk)

encA[1:0] <= {encd[1],encd[0]}

 

и заменил сигналы на encA[1],encA[0]. И первый вариант заработал. Огромное спасибо.............

Буду теперь знать.

 

Ох.....

Хотел по быстрому, опять надо по долгому.

if, case, не важно,

 

вот возьмем такую схему

 

always @(posege clk)
   begin
      A <= in1;
      B <= in1;
   end

 

Полагаю что в вашем идеальном мире, А и В всегда будут равны, правильно? А вот в нашем жестоком мире FPGA все не так.

 

элемент А и В находятся в разных частях ПЛИС, сигнал со входа in к ним идет разное время, как и сигнал clk, и может так оказаться что если in меняется из 0 в 1 рядом с clk, то к одному элементу он успеет добежать в новом виде, а к другому в старом. Это то что в мире FPGA именуют мета-стабильностью (да я знаю что мета-стабильность это другое, но это тоже по привычке все называют также).

 

И такая фигня со всем, когда вы пишите IF или CASE это опять же схемы в разных частях кристалла, и может так случиться что половина блоков пойдет по пути одного условия, а другая по другому. Стандартная ошибка сделать диодик для проверки под if, диод загорается, думает все ок, а другая часть условий не выполняется... новички с ума сходят)....

 

А добавьте что входы у вас еще не по 1 биту, то есть даже значение может придти и захлопнуться не то что вы ждали...

 

борьба с этим простая (для 1 битных сигналов)

 

always @(posedge clk) 
  begin
     r1<=r0;
     r0<=in1;
  end

 

 

r0<= in1 - это один элемент он защелкнет состояние входа и раздаст его всему плис на следующий клок. А среда проследит чтобы все пути успели (в отличии от входного сигнала этот триггер у нее под контролем). Это как раз то что вам советовали хотябы в io захлопнуть.

 

Но есть вторая беда что r0 может поймать метастабильность и захлопнуть ни 0 ни 1, а 0.5, из этого состояния к след клоку он наверняка выйдет, но след часть схемы такое состояние может интерпретировать на свое усмотрение то 0 то 1, и опять же в разных частях по разному, для этого ставят 2 триггер r1 <= r0 ; - это опять один элемент который примет решение 0.5 это 0 или 1, и дальше во всей схеме будет что-то одно... Вот такая вот штука.

Так что вам надо ваши входные сигналы прогнать через 2 триггера, и использовать выход с триггеров чтобы все было классно.

 

Для многомерных сигналов чуть хуже, потому что они могут расходиться, но тут вам поможет код грея

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


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

Ох.....

Хотел по быстрому, опять надо по долгому.

if, case, не важно,

..................................

А вот в нашем жестоком мире FPGA все не так.

спасибо за развернутый ответ. Всё вроде на свои места становиться.

 

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

Да и вроде голова без всякого рода задачек не может уже....... так что сижу четвёртый месяц вникаю.....

 

Всем спасибо за помощь. :)

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


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

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

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

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

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

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

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

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

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

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