Jump to content

    
Sign in to follow this  
agathodaimon

Семисегментный индикатор, странное поведение

Recommended Posts

1 hour ago, Flip-fl0p said:

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

Не cразу понял, что у меня лишнее звено to_integer(DATA) с последующим преобразованием в hex, когда можно было сразу писать x"integer", надо избавляться от старых привычек.

Edited by Nemos760

Share this post


Link to post
Share on other sites

В общем, подправил немного код. Теперь он выглядит так:

module helloworlds (
	input [3:0]btn, output [3:0]led ,
	output reg [3:0] digits,
	output reg [7:0] dots,
	output speaker,
	output reg strobe,
	input clk);
	assign led[0] = btn[0];
		
	reg [23:0]CTCQ;
	reg [16:0]CTFQ;
	reg [16:0]freq;
	reg [1:0]dig = 2'd0;
	reg [3:0]curr_digit;
	reg [15:0]CNT = 16'ha5a5;
	//reg strobe = 1;
	reg [7:0]strobe_ct = 0;
	always @(posedge clk)
	begin
		CTCQ <= CTCQ + 1'd1;

		strobe_ct <= strobe_ct + 1'd1;
		
		if(strobe_ct > 8'hf0) begin
			strobe <= 0;
		end else begin
			strobe <= 1;
		end
		
	//
	//     ___
	//  b | g | f
	//    |___|
	//    | a |
	//  c |___| e
	//		  d
		if (strobe)
		begin
			case(curr_digit)// ABCDEFG
				4'h0: dots = ~7'b0111111;
				4'h1: dots = ~7'b0000110;
				4'h2: dots = ~7'b1011011;
				4'h3: dots = ~7'b1001111;
				4'h4: dots = ~7'b1100110;
				4'h5: dots = ~7'b1101101;
				4'h6: dots = ~7'b1111101;
				4'h7: dots = ~7'b0000111;
				4'h8: dots = ~7'b1111111;
				4'h9: dots = ~7'b1101111;
				4'ha: dots = ~7'b1110111;
				4'hb: dots = ~7'b1111100;
				4'hc: dots = ~7'b0111001;
				4'hd: dots = ~7'b1011110;
				4'he: dots = ~7'b1111001;
				4'hf: dots = ~7'b1110001;
			endcase
		end else begin
			dots = ~7'b0000000;
		end
	end
	
	always @(posedge strobe) 
	begin
		dig <= dig + 1'd1;
		curr_digit <= CNT >> (dig * 4);
		case(dig)
			2'd0:
				digits = ~4'd1;
			2'd1:
				digits = ~4'd2;
			2'd2:
				digits = ~4'd4;
			2'd3:
				digits = ~4'd8;
		endcase
	end

	always @(posedge CTCQ[23]) CNT <= CNT + 1'd1;

endmodule

По временной диаграмме должно быть все хорошо и наложения должны пропасть:

image.thumb.png.585c35c496b7ba8cf234579e5a3887cf.png

Однако реально нажелезяке продолжаю видеть старое поведение.

Сегодня попробую пример тов. Flip-fl0p. Может что-то проясниться у меня.

Share this post


Link to post
Share on other sites
10 часов назад, agathodaimon сказал:

В общем, подправил немного код. Теперь он выглядит так:

По временной диаграмме должно быть все хорошо и наложения должны пропасть:

 

Однако реально нажелезяке продолжаю видеть старое поведение.

Сегодня попробую пример тов. Flip-fl0p. Может что-то проясниться у меня.

В Вашем коде много недостатков.

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

2. Нет нормальных названий сигналов. Сигналы должны быть понятными. Вот что значит регистр CTCQ ?  По коду видно, что это счетчик, а что он считает. Зачем он нужен ?

3. Смешано все в одной куче. Разбейте схему на логически законченные блоки. 

4. На вход тактовой частоты подается сигнал с счетчика. Думаю в Вашем случае это ошибка....

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

Share this post


Link to post
Share on other sites

Ничего не изменилось, потому что ничего не меняли. Требуемые для отображения данные по-прежнему отсутствуют в заголовке модуля и создаются внутри него асинхронным генератором случайных чисел. Таким же кривым остался и строб, с F1 по 00 включительно, т.е. на выходе гашение данных соответственно с F2 по 01 включительно, что прекрасно видно даже на такой картинке. А уж частота 200 кГц для выводов ПЛИС, нагруженных на ёмкости слонового размера светодиодов на другой стороне платы — ну это запредельно круто.

Share this post


Link to post
Share on other sites
15 минут назад, agathodaimon сказал:

издержки С программиста :biggrin:

Так FPGA - это больше схемотехника. И думать надо по-другому. А когда рисуете схемы на бумаге карандашом - становится сразу проще. Советую. У меня обычно уходит много бумаги времени прежде чем я приступаю к написанию кода. 

Share this post


Link to post
Share on other sites
On 11/28/2020 at 9:59 AM, Plain said:

Требуемые для отображения данные по-прежнему отсутствуют в заголовке модуля и создаются внутри него асинхронным генератором случайных чисел

почему отсутствуют-то?

Данные для отображения содержаться в регистре CNT, который путем сдвига на 4 бита, преобразуется в число для каждого сегмента. Изначальное значение этого регистра задается при его объявлении, а инекремент происходит при просчете счетчика CTCQ.

On 11/28/2020 at 9:59 AM, Plain said:

А уж частота 200 кГц для выводов ПЛИС, нагруженных на ёмкости слонового размера светодиодов на другой стороне платы — ну это запредельно круто.

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

14 minutes ago, Flip-fl0p said:

У меня обычно уходит много бумаги времени прежде чем я приступаю к написанию кода. 

А на сколько детально вы рисуете схемы? Наверное, если бы я рисовал схему сейчас, то в моей схеме бы присутствовал один блок, с входим тактовой частоты и выходом на семисегментный индикатор)

16 minutes ago, Flip-fl0p said:

Так FPGA - это больше схемотехника. И думать надо по-другому.

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

Share this post


Link to post
Share on other sites
15 минут назад, agathodaimon сказал:

Данные для отображения содержаться в регистре CNT, который

Вы не знаете, в каком месте кристалла синтезатор положил curr_digit, а в каком dots, и какие задержки получились между их тактовыми — так вот, в худшем случае, данные на входах dots могут исчезать раньше, чем требуется, и вперемешку, в зависимости от тепловых волн, пульсаций питания и т.п., поэтому на его выходах будет случайное число.

Share this post


Link to post
Share on other sites
40 минут назад, agathodaimon сказал:

почему отсутствуют-то?

Данные для отображения содержаться в регистре CNT, который путем сдвига на 4 бита, преобразуется в число для каждого сегмента. Изначальное значение этого регистра задается при его объявлении, а инекремент происходит при просчете счетчика CTCQ.

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

А на сколько детально вы рисуете схемы? Наверное, если бы я рисовал схему сейчас, то в моей схеме бы присутствовал один блок, с входим тактовой частоты и выходом на семисегментный индикатор)

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

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

Модуль верхнего уровня CONTROLLER_4X_7SEGM, который имеет 4 входа данных (каждый вход данные для соответствующего сегмента) и 2 выхода данных. Один выход - код семисегментного индикатора. Второй - выбор индикатора.

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

И второй модуль - это BINARY_TO_7SEGM_CODER кодер из 4 битового двоичного числа в код семисегментного индикатора. 

В итоге мы имеем блок CONTROLLER_4X_7SEGM которому достаточно подать на входы данные, которые мы хотим зажечь на соответствующих сегментах. Ему все равно каким образом эти данные формируются. Он полностью автономен.

Стараюсь модули делать с минимальной связностью. Каждый модуль максимально "тупой" и не знает о существовании других модулей. Ему подали данные на вход, он их обработал и выдал дальше. Это в идеале. Обычно получается чуть сложнее и частенько приходится добавлять доплнительные сигнал в виде ready, busy, done. 

 

7segm.png

Share this post


Link to post
Share on other sites
8 часов назад, Flip-fl0p сказал:

я бы ограничился таким описанием:

До полноценных модулей по-моему ещё далеко, а неполноценными задача решается примерно так:

 

always @(posedge clk)

begin

// делаем три стробированных переноса, т.е. каждый "1" 10 нс, если 100 МГц,
// когда его счётчик, и все до него, равны нулю

 cnt0r <= (cnt0 == 16'd1);
 cnt1r <= (cnt0 == 16'd1) && (cnt1 == 8'd0);
 cnt2r <= (cnt0 == 16'd1) && (cnt1 == 8'd0) && (cnt2 == 2'd0);

// младший счётчик считает всегда

 cnt0 <= cnt0 - 1'b1;

// когда он упёрся, загружаем в него его период и дёргаем следующий счётчик

 if (cnt0r) begin
  cnt0 <= prd0;
  cnt1 <= cnt1 - 1'b1;
 end

// аналогично следующий

 if (cnt1r) begin
  cnt1 <= prd1;
  cnt2 <= cnt2 - 1'b1;
 end

// аналогично, но дальше счётчиков нет, поэтому лишь загрузка последнего

 if (cnt2r) begin
  cnt2 <= prd2;
 end

// второй счётчик создаёт развёртку интервала гашения

 if (cnt0r) begin

// включаем индикацию спустя один его такт после смены разряда дисплея

  if (cnt1 == prd1) begin
   case (mem0[cnt2])
    4'h0: dots <= 7'b1111111;
 ...
    4'hf: dots <= 7'b1111111;
   endcase
  end

// выключаем индикацию за один его такт до смены разряда дисплея

  if (cnt1 == 8'd1) begin
   dots <= 7'b0000000;
  end

 end

// делаем синхронный дешифратор позиции дисплея, учитывая,
// что в третьем счётчике сейчас предыдущее её значение

 if (cnt1r) begin
  case (cnt2)
   2'b00 : digits <= 4'b1000;
   2'b01 : digits <= 4'b0001;
   2'b10 : digits <= 4'b0010;
   2'b11 : digits <= 4'b0100;
  endcase
 end

end

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this