Jump to content
    

Синтез задержек большой величины (5ms, 10ms, 50ms, 200ms и более) с использованием минимума ресурсов

Добрый день!

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

В процессе подключения Ethernet контроллера W5500 к FPGA столкнулся с ситуацией, что данному чипу по феншую надо бы формировать ряд достаточно длинных задержек (конкретные величины указаны в заголовке темы). Никаких существенных требований к ним нет - это просто паузы, когда ничего не делаем, т.е. их точность может быть +-километр. Наши узкоглазые братья китайцы (ну или один брат, который писал код)  не стали заморачиваться и поступили так:

 

//Счетчик задержки 50 мс
reg [23:0] Delay50_1;
always @(posedge clk or negedge rst_n)
	if (!rst_n)	Delay50_1 <= 24'd0;
	else if (Hardware_State == Hard_DELAY50)	Delay50_1 <= Delay50_1 + 1'b1;

//Счетчик задержки 200 мс
reg [23:0] Delay200_1;
always @(posedge clk or negedge rst_n)
	if (!rst_n)	Delay200_1 <= 24'd0;
	else if (Hardware_State == Hard_DELAY200)	Delay200_1 <= Delay200_1 + 1'b1;
	else Delay200_1 <= 24'd0;
	
//Счетчик задержки 10 мс
reg [23:0] Delay10_1;
always @(posedge clk or negedge rst_n)
	if (!rst_n)	Delay10_1 <= 24'd0;
	else if (W5500_INIT_State == W5500_INIT_DELAY10)		Delay10_1 <= Delay10_1 + 1'b1;
	else Delay10_1 <= 24'd0;
	
//Счетчик задержки 5 мс
reg [23:0] Delay5_1;
always @(posedge clk or negedge rst_n)
	if (!rst_n)	Delay5_1 <= 24'd0;
	else if (SOCKET_CONN_State == SOCKET_CONN_DELAY5)	Delay5_1 <= Delay5_1 + 1'b1;
	else Delay5_1 <= 24'd0;

Как говорится от души, когда кремния много и его не жалко...

Вот здесь https://www.fpga4fun.com/Counters1.html нашел предложение как можно счетчик немного поджать по ресурсам. В моем оформлении:

 

//https://www.fpga4fun.com/Counters1.html
`define SMOLL_RESURSES
module FPGA_TOP #(
		parameter CNT_WITH = 19				//2^19 * 20ns = 10,48576 ms 
)(
	input 	clk	,//Clock 50MHz
	input 	rst_n	,//RESET
	output 	tick
);

`ifdef SMOLL_RESURSES
	reg [CNT_WITH-1:0] cnt;
	wire [CNT_WITH:0] cnt_next = cnt + 1'b1;

	always @(posedge clk or negedge rst_n)
	if(!rst_n )
		cnt <= 'd0;
	else 
		cnt <= cnt_next[CNT_WITH-1:0];
		
		assign tick = cnt_next[CNT_WITH];

`else
	reg [CNT_WITH:0] cnt;
	
    	always @(posedge clk or negedge rst_n)
	if(!rst_n )
			cnt <= 'd0;
	else 
		cnt <= cnt + 1'b1;
			
		assign tick = &cnt;	
`endif

endmodule

Действительно, вместо 

Total logic elements - 27    Total registrs - 20

получаем

Total logic elements - 20    Total registrs - 19

Вроде как не очень много всего 7 элементов, но с другой стороны, если счетчиков будет 4, то выигрыш уже 28, а если их разрядность будет больше, то разница становится еще заметнее. При условии, что весь проект занимает порядка 600-700 логических элементов тратить столько просто на пустое ожидание...Не то чтобы прямо критично, но как-то это мне кажется не очень красивым.

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

Собственно вопрос к уважаемому сообществу, кто-как решает такого рода проблемы и приходилось ли кому заморачиваться с оптимизацией всего этого дела в плане занимаемых ресурсов. Может кто еще какие хитрые способы знает как можно добиться нужного эффекта или может поделиться своими соображениями и/или их реализацией. Буду благодарен.

Спасибо. 

 

 

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

1 hour ago, tems-ya said:

Вроде как не очень много всего 7 элементов

О да, сэкономили 7 ячеек из 10K...2M  имеющихся ...

Но если уж так "жаба давит": 

....
localparam                 CNT_5MS_WH = clog2(W5500_INIT_DELAY5MS);
localparam [CNT_5MS_WH:0 ] DIV_5MS_N  = (1<<CNT_5MS_WH) - W5500_INIT_DELAY5MS + 1;

reg                  tick; 
reg [CNT_5MS_WH-1:0] cnt;
....
if (!rst_n)
   {tick, cnt} <= DIV_5MS_N;
else 
   {tick, cnt} <= tick ? DIV_5MS_N : {tick, cnt} + 1'b1;
....


И  если функционал позволяет и допустима точность "+-километр" то строить дерево счётчиков/делителей.
Сначала счётчик на "километр" (например на 1ms), а затем уж мало разрядные счётчики тиков "километров" на 5 на 10 ...   

Share this post


Link to post
Share on other sites

1 hour ago, tems-ya said:

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

  1. У каждой ПЛИС есть внутренний RC генератор для загрузки прошивки. Частотой около 120МГц с возможностью деления до 128 - сделайте счётчик на нём.
  2. А лишняя PLL есть? За сколько она лочится?
  3. Внешняя RC цепочка между ногами ?
  4. У меня написан модуль Pause( C, R, CE, D, S, E) который задерживает прохождение строба S->E на 0.02/0.12/1.2/30 мсек в зависимости от D(0..3). Внутри есть параметр задающий частоту C. Для частоты C=30МГц модуль занимает 36 регистров и 44 LUT. Состоит из последовательно соединённых счётчиков-делителей на FREQ=30, и 20,6,10,25 плюс небольшая логика какой из счётчиков последний. Судя по отчётам может работать на GW2A на частоте 340МГц. Просто мне иногда надо чтобы проект и на 120МГц работал, и боюсь 24 битные счётчики тогда на DSP модулях придётся делать...

Pause.png.21e2f1921fa8d8300eddb127f839a8e6.png

Share this post


Link to post
Share on other sites

В 21.11.2024 в 21:20, _4afc_ сказал:
  1. У каждой ПЛИС есть внутренний RC генератор для загрузки прошивки. Частотой около 120МГц с возможностью деления до 128 - сделайте счётчик на нём.

А можете поподробнее? Применял Cyclone II, Cyclone V E и Cylcone 10 LP. Не помню про такую возможность.

Share this post


Link to post
Share on other sites

Особо одарённые не указывают фирму производителя микросхем - как следствие каждый думает "о своём"

Share this post


Link to post
Share on other sites

Спасибо, всем откликнувшимся, особенно RobFPGA - за самый компактный по ресурсам вариант да еще и с начальной предустановкой!

Хотел эту идею немного причесать, но застрял в самом  неожиданном месте 

module ZAD_MS #(
		parameter PARAM_ZAD_MS = 200,
		parameter CLK_IN_HZ = 50_000_000
)(
	input 	clk   ,		//Clock 50MHz
	input 	rst_n ,		//RESET

	output reg 	tick
);

	//проблема в этой строке...
	localparam	integer			CUR_CNT = CLK_IN_HZ*PARAM_ZAD_MS/1000;			// величина счетчика, соответсвующая требуемой задержке

	localparam					CNT_WH = $clog2(CUR_CNT);						//сширина счечика, сколько разрядов нужно, чтобы сформировать требуемую задержку
	localparam [CNT_WH:0 ] INIT_CNT  = (1<<CNT_WH) - CUR_CNT + 1;				// (1<<CNT_WH) = 2^CNT_WH = MAX_CNT = 2^19 = 524_288 

	reg [CNT_WH-1:0] cnt;


	always @(posedge clk or negedge rst_n)
	if (!rst_n)
		{tick, cnt} <= INIT_CNT;
	else 
		{tick, cnt} <= tick ? INIT_CNT : {tick, cnt} + 1'b1;


endmodule

 Камрады, как правильно реализовать описать параметр CUR_CNT коде выше, чтобы он работал для любых значений задержек. Qurtus 17 - сейчас при PARAM_ZAD_MS > 40 перестает работать....

Спасибо. 

Share this post


Link to post
Share on other sites

On 11/25/2024 at 4:29 PM, tems-ya said:

Камрады, как правильно реализовать описать параметр CUR_CNT коде выше, чтобы он работал для любых значений задержек.

Проще всего так:

module ZAD_MS #(
		parameter PARAM_ZAD_MS = 200,
		parameter CLK_IN_KHZ = 50_000
)(...);

localparam	CUR_CNT = CLK_IN_KHZ*PARAM_ZAD_MS;			// величина счетчика, соответствующая требуемой задержке

 

Но можно и так:

module ZAD_MS #(
		parameter PARAM_ZAD_MS = 200,
		parameter CLK_IN_HZ = 50_000_000
)(...);

localparam	CUR_CNT = CLK_IN_HZ/1000*PARAM_ZAD_MS;			// величина счетчика, соответствующая требуемой задержке

Share this post


Link to post
Share on other sites

если убрать integer он вроде перестанет быть 32х битным

localparam CUR_CNT = CLK_IN_HZ*PARAM_ZAD_MS/1000;

 

 

Share this post


Link to post
Share on other sites

On 11/25/2024 at 10:30 AM, dinam said:

А можете поподробнее? Применял Cyclone II, Cyclone V E и Cylcone 10 LP. Не помню про такую возможность.

Ну а как они по вашему грузятся сами? Читайте AN 496: Using the Internal Oscillator Intel® FPGA IP

 

Share this post


Link to post
Share on other sites

1 час назад, _4afc_ сказал:

Ну а как они по вашему грузятся сами? Читайте AN 496: Using the Internal Oscillator Intel® FPGA IP

Согласно документу, который вы привели и вашим словам Cyclone II не могут грузится, а они у меня нормально конфигурируются. 😊 Cyclone V E я осваивал тогда, когда и в помине производитель не предоставлял такую возможность. Да, с Cylcone 10 LP не увидел такую возможность, тут признаю. Но для меня слишком уж частота неопределенная, указывается только верхняя граница.

Share this post


Link to post
Share on other sites

51 minutes ago, dinam said:

Согласно документу, который вы привели и вашим словам Cyclone II не могут грузится, а они у меня нормально конфигурируются. 😊 Cyclone V E я осваивал тогда, когда и в помине производитель не предоставлял такую возможность. Да, с Cylcone 10 LP не увидел такую возможность, тут признаю. Но для меня слишком уж частота неопределенная, указывается только верхняя граница.

Intel/AMD предоставляют такую возможность в виде костыля торчащего из упрятанного блока конфигурации ПЛИС - поэтому попытайтесь посмотреть настройки соответствующего IP.

У GoWin/Lattice - это отдельные, хорошо описанные блоки, в том числе и дополнительные на 10кГц.

Share this post


Link to post
Share on other sites

Использование  внутреннего генератора клока для конфига в качестве "медленного" клока для формирования больших задержек в дизайне для экономии ячеек  плохая идея. 
Мало того что этот клок не на столько уж медленен что бы много сэкономить,  так он еще и будет асинхронен к основному клоку(ам) вашего  дизайна,  и гуляет от температуры и вольтажа  "+-километр".

Да и вообще, идея экономии "на спичках" в "общем", без учёта конкретики дизайна плохо работает.
В одном месте упоролись и сэкономили 7 "спичек"/ячеек, а в соседнем месте дизайна из за этой экономии потеряли целый ящик КЦ ...    

Share this post


Link to post
Share on other sites

15 часов назад, RobFPGA сказал:

...

Вы совершенно правы. Но смотрите, Handbook Cyclone III имеет первую ревизию 2007г. А в  AN 496: Using the Internal Oscillator Intel® FPGA IP Cyclone III впервые упоминается спустя 10! лет. Наверное, технически такая возможность имелась, но на фиг ни кому была не нужна из-за проблем с её применением. Но похоже всё кто-то нашелся, кому она пригодилась именно в  FPGA (не CPLD) и он убедил Intel открыть и задокументировать такую возможность. Я так думаю, что лучше иметь возможность, но не использовать её, чем иметь необходимость, но не иметь возможности 😊

Share this post


Link to post
Share on other sites

В 21.11.2024 в 15:30, tems-ya сказал:

В процессе подключения Ethernet контроллера W5500 к FPGA столкнулся с ситуацией, что данному чипу по феншую надо бы формировать ряд достаточно длинных задержек

Нужность задержек отдельный вопрос, но какие с ними могут проблемы, когда эта ИС требует такты 25 МГц, или сама их даёт.

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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.

×
×
  • Create New...