Hallo iedereen

Probleem:
=========

Ik heb een schakelaar die wordt aangekoppeld aan een FPGA unit en daar moet code worden voor geschreven voor het ontdenderen van die schakelaar. Heb niet echt een idee op welke manieren je dat kan doen in VHDL

Weet uit de digitale technieken dat je kan ontdenderen met een timer, door een latch.

Hoe moet je dat schrijven in VHDL

Ik heb enkele ideeén hoe je het kan doen maar ben niet zeker als het juist is

Een n teller gebruiken die het kloksignaal van 50MHz deelt tot 50Hz

Een Latch gebruiken met een SR Flip Flop

Vraag 1:

Kan iemand mij een voorbeeldcode geven hoe je een ontdender code schrijft in VHDL in behavaiol en waar ik in die code mijn drukknop moet programmeren?

Vraag 2:

Hoe kan je een klokdeler maken want moet twee snelheden instellen één van bvb 2Hz en één van 1Hz

Kan iemand mij helpen?

Ik denk dat je hier wel wat voorbeelden uit kunt halen.
(excuses voor de lange post)

Vraag 1: Ontdenderen:


-- Module:	debounce

-- omschrijving:

-- naam file:	debounce.vhd
-- project:	****** ;)
-- auteur:	Hiddink
-- datum:	16-3-2005
-- versie:	V0.01
-- revisie:	zie: --& in de kantlijn, of tussen --&1.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;

ENTITY debounce IS
	PORT (	sample, in_put : IN std_logic := '0';
		out_put : OUT std_logic := '0' );

END debounce;

ARCHITECTURE core OF debounce IS

SIGNAL	ffa : integer range 0 to 31 ;

BEGIN

PROCESS (sample, in_put)

BEGIN

IF sample'EVENT and sample = '1' THEN
	IF in_put = '1' THEN
		IF ffa < 31 THEN -- de_bounce_length*2
			ffa <= ffa + 1 ;
		END IF;
	ELSE
		IF ffa > 0 THEN
			ffa <= ffa - 1 ;
		ELSIF ffa > 15 THEN -- de_bounce_length = 16
			ffa <= 31; -- de_bounce_lenght *2
		END IF;
	END IF;
END IF;

IF ffa > 15 THEN -- de_bounce_length = 15
	out_put <= '1';
ELSE
	out_put <= '0';
END IF;
END PROCESS;

END core;

Vraag 2: Deler:


-- Module: 	divider

-- omschrijving:

-- details: 

-- ingangsfrequentie: 10MHz
-- uitgansfrequentie (clk_timer): 500Hz

-- clk_int:
-- afhankelijk van de ingangen in_a, in_b en in_c.
-- de combinatie die gebruikt worden zijn 000, 001, 010, 011 en 100 (cba).
-- de combinaties van de ingangen hebben een ander deeltal van de ingangsfrequentie 
-- tot gevolg. Minimaal (code: 000) is het deeltal 512, maximaal (code: 100) is het
-- deeltal 32.

-- naam file:	divider.vhd
-- project:	***** ;)
-- auteur:	Hiddink
-- datum:	14-3-2005
-- versie:	V0.01
-- revisie:	zie: --& in de kantlijn, of tussen --&1.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;
USE ieee.std_logic_unsigned.ALL;

ENTITY divider IS
	PORT (	clk_input, in_a, in_b, in_c : IN std_logic := '0';
		clk_timer, clk_int, clk_debounce : OUT std_logic := '0');
END divider;

ARCHITECTURE core OF divider IS

SIGNAL	ffa : integer range 0 to 31 ;
SIGNAL	ffb : integer range 0 to 15 ;
SIGNAL  ffc : integer range 0 to 40 ;

--	START CODE:

BEGIN

PROCESS (clk_input, ffa, ffb, ffc, in_a, in_b, in_c)

BEGIN

IF rising_edge(clk_input) THEN
	IF ffa < 31 THEN
		ffa <= ffa + 1;
	ELSE
		ffa <= 0;
		IF ffb < 15 THEN
			ffb <= ffb + 1;
		ELSE
			ffb <= 0;
			IF ffc < 40 THEN
				ffc <= ffc + 1;
			ELSE
				ffc <= 0;
			END IF;
		END IF;
	END IF;

-- 1200 bps

	IF in_a = '1' AND in_b = '1' AND in_c = '1' THEN
		IF ffa = 31 AND ffb = 15 THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

	IF in_a = '0' AND in_b = '1' AND in_c = '0' THEN
		IF ffa = 31 AND ffb = 15 THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

	IF in_a = '1' AND in_b = '0' AND in_c = '0' THEN
		IF ffa = 31 AND ffb = 15 THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

	IF in_a = '0' AND in_b = '0' AND in_c = '0' THEN
		IF ffa = 31 AND ffb = 15 THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

-- 2400 bps

	IF in_a = '0' AND in_b = '1' AND in_c = '1' THEN
		IF ffa = 31 AND (ffb = 7 OR ffb = 15) THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

-- 4800 bps

	IF in_a = '1' AND in_b = '0' AND in_c = '1' THEN
		IF ffa = 31 AND (ffb = 3 OR ffb = 7 OR ffb = 11 OR ffb = 15) THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

-- 9600 bps

	IF in_a = '0' AND in_b = '0' AND in_c = '1' THEN
		IF ffa = 31 AND (ffb = 1 OR ffb = 3 OR ffb = 5 OR ffb = 7 OR ffb = 9 OR ffb = 11 OR ffb = 13 OR ffb = 15) THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;

-- 19200 bps

	IF in_a = '1' AND in_b = '1' AND in_c = '0' THEN
		IF ffa = 31 THEN
			clk_int <= '1';
		ELSE
			clk_int <= '0';
		END IF;
	END IF;


	IF ffa = 31 AND ffb = 15 AND ffc = 40 THEN 
		clk_timer <= '1';
	ELSE
		clk_timer <= '0';
	END IF;

	IF ffa = 31 THEN 
		clk_debounce <= '1';
	ELSE
		clk_debounce <= '0';
	END IF;
	
END IF;

END PROCESS;

END core;

in verilog dan maar :p



module debounce(input clock,reset,in,
                output reg out);

parameter threshold = 4'd9; // deze mag niet hoger zijn dan 4 bit ! ik zet hem op 9 voorloopig
reg [4:0] bounce;

always @(posedge clk,posedge reset)
if (reset) begin
   bounce <=4'b0;
   out <=0;
   end
else begin
   if (in and (bounce <>threshold)) bounce <= bounce +1;
   if (!in and (bounce <>0)) bounce <= bounce-1;
   if (bounce=0) out <=0;
   if (bounce=threshold) out <=1;
end
endmodule

dit ding is een symmetrische debouncer.
het is eigenlijk niks anders dan een up/down counter die gelimiteerd is tussen '0' en de waarde van 'threshold'

bij elke clockpuls wordt de ingang gesampled. als die hoog is gaat de teller omhoog. als di laag is gaat de teller omlaag.
als de teller nul bereikt schakelt de uitgang laag.
als de teller 'threshold' bereikt gaat de uitgang hoog.

je kan de 'gevoeligheid' instellen door de waarde van threshold aan te passen

Op 6 november 2007 16:04:35 schreef free_electron:
in verilog dan maar :p



module debounce(input clock,reset,in,
                output reg out);

parameter threshold = 4'd9; // deze mag niet hoger zijn dan 4 bit ! ik zet hem op 9 voorloopig
reg [4:0] bounce;

always @(posedge clk,posedge reset)
if (reset) begin
   bounce <=4'b0;
   out <=0;
   end
else begin
   if (in and (bounce <>threshold)) bounce <= bounce +1;
   if (!in and (bounce <>0)) bounce <= bounce-1;
   if (bounce=0) out <=0;
   if (bounce=threshold) out <=1;
end
endmodule

dit ding is een symmetrische debouncer.
het is eigenlijk niks anders dan een up/down counter die gelimiteerd is tussen '0' en de waarde van 'threshold'

bij elke clockpuls wordt de ingang gesampled. als die hoog is gaat de teller omhoog. als di laag is gaat de teller omlaag.
als de teller nul bereikt schakelt de uitgang laag.
als de teller 'threshold' bereikt gaat de uitgang hoog.

je kan de 'gevoeligheid' instellen door de waarde van threshold aan te passen

Verdikkie Free dat is een leuke methode daar. :)

je weg en weer looplichtje :

Op 6 november 2007 16:34:11 schreef MagicBox:
[...]

Verdikkie Free dat is een leuke methode daar. :)

het probleem van de meeste debouncers is dat ze maar reageren op de eerste edge alleen. bij het terug verbreken van het conatct ontdenderen ze niet. en dan krijg je vodden.
boveniden gaat ook de pulsduur om zeep.

stel je hebt dit soort signaal


  _   ____   _   ________________________   _     __
_| |_|    |_| |_|                        |_| |___|  |___

de meeste debouncers maken er dit van


  _   ____   _   ____________________   _     ___
_| |_|    |_| |_|                    |_| |___|   |___
                _____________________           _
_______________|                     |_________| |____

de counter methode maakt er dit van


  _   ____   _   _________________   _      ___
_| |_|    |_| |_|                 |_| |____|   |___
           ________________________________   
__________|                                |______

tis moeilijk te tekenen maar dat ding 'integreert' eigenlijk de dendering. als je een dendertrein bekijkt dan zie je dat daar een bepaald verloop in zit.
de pulslengte wordt uitgemiddeld.

schakelbare 2 deler


module div2 (input clk,reset,select,
             output out);
reg ticktock;

always @(posedge clk,posedge reset)
   if (reset) ticktock <=0;
   else ticktock <= !ticktock;

always 
    if (select) out = ticktock;
    else out = clk; 

endmodule

Op 6 november 2007 16:47:39 schreef free_electron:
schakelbare 2 deler

Mwhaaaaaah, de clk in de combinatoriek gebruiken, hij doet het weer! Ik vind het nog steeds een slechte gewoonte. Ik doe het zo:


module div2 (input clk,reset,select,
             output out);
reg div2_en;

always @(posedge clk,posedge rst)
   if (rst) div2_en <= 0;
   else div2_en <= !div2_en;

always @(posedge clk,posedge rst)
    if (rst) out <= 0;
    else begin
       // doe hier alles wat op clk moet
       if (div2_en) begin
           //doe hier alles wat op clk/2 moet;\
       end
    end
endmodule

ipv

Je hebt nu maar een clk waar alle FFs op lopen.

Kan je dat eens schrijven in VHDL versta geen Virolog

Hmm, ik hoop dat je dat uitgang signaal dat niet gebruikt als klok voor andere flip-flops, anders maakt het natuurlijk nog niks uit of je nu synchroon of asynchroon de klok deelt.

Als je een klok wil vertragen gebruik je of meerdere klok-domeinen ( Moet je wel weten wat je doet, en alles synchronizeren), of je gebruikt een klok enable.

Dit voorkomt ook al die mooie gated-clock waarschuwingen van je synthesizer.

Op 6 november 2007 16:44:05 schreef free_electron:
[...]

het probleem van de meeste debouncers is dat ze maar reageren op de eerste edge alleen. bij het terug verbreken van het conatct ontdenderen ze niet. en dan krijg je vodden.
boveniden gaat ook de pulsduur om zeep.

De code die ik postte doet precies dat. Ontdenderen bij de opgaande flank en ontdenderen bij de neergaande flank.
De aangevoerde klok moet ongeveer 1 kHz zijn.

Bart

Kan je eens een ontdender routine schrijven door gebruik van een Timer want ik moet starten van een clock van 50MHz en het ontdenderen is 20 ms

Ik heb al zitten zoeken hoe je dat moet doen maar vind het niet direct

Ik weet dat we bij de stijgende flank een timer moeten starten en deze stoppen als we een dalende flank detecteren maar hoe doe je dat in VHDL?

Waar moet ik nu eigenlijk de pinnen programmeren van die drukknop, die fysieke pinnen weet ik wel

Graag een berichtje terug

Kan je ook eens zeggen hoe ik 2 snelheden kan maken als je drukt op eerste knopje moet hij naar links lopen en met ander knopje naar rechts?

Gewoon principe van bvb een 4 LEDS looplicht

Op 6 november 2007 20:26:53 schreef Stephane1976:
Kan je dat eens schrijven in VHDL versta geen Virolog

blijkbaar versta je geen vhdl ook ...
50MHz en je moet 20mS kunnen vangen. 1mS is 1 khz. 20 mS is dus 50 Hz ... dus je hebt al in ieder geval een 1 miljoen deler nodig ....
je zou dan een 2 teller kunnen maken. 00 0`1 doen niks maar 10 is uitgang hoog .. en 00 is uitgang laag.

dus met 2 flifplops ben je er.

je probleme heeft niks te maken met verilog of vhdl. desnoods maak je dat met TTL of CMOS citjes , een schema of met losse transistoren als het moet. het punt is dat je de opgave niet snapt en zolang je niet begrijpt wat je moet doen kan je het niet in code gieten. eerst TTL en dan VHDL... tzal veel beter gaan.

analyseer de opgave eens.

uw 20mS heb ik al opgelost.

een debouncer heb ik ook al gegeven. ik heb uitgelegd hoe je met een up.down counter een debouncer kan maken.

je weg en weer lopen : gebruik een drukknop om een t-flipflop te laten omkippen. afhankelijk van de stand van die t-flipflop schakel je ene counter in upcount of downcount. en 2 snelheden is kwestie van de clocksnelheid van die counter aan te passen.

Op 6 november 2007 20:26:53 schreef Stephane1976:
Kan je dat eens schrijven in VHDL versta geen Virolog

In VHDL is het bijna precies zo. Je moet alleen de "always @" vervangen door een


process(clk, rst) begin
  if (rst='1') bla bla
  elsif (clk'event and clk='1') bla bla
  end if;
end process;

pfew, m'n VHDL is nogal stroef na een paar jaar :-)

Verilog en VHDL verschillen niet zoveel als je het principe van FE's schakeling snapt.

Dat blijkt ook uit uw signatuur ;)

Slordig. Maar scherp opgelet!

Tot mijn grote verbazing heb ik laatst een projectje gedaan waarbij ik gewoon op 1kHz de schakelaar sample, en gewoon op iedere (opgaande) flank reageer. Aangezien er niet alleen een ledje aan en uit moest, maar een teller door de gebruiker op de juiste waarde moet worden ingesteld, is het voor de gebruiker belangrijk dat ie niet 2, 3 of 4 flanken ziet als je op het knopje drukt. Het lijkt toch prima te werken. :-) Kortom ontdenderen was niet nodig. Kost alleen maar code. Doen we wel als het WEL nodig is...

kost geen code ... dendersysteem past in 2 of 3 LE's... als je er 15000 hebt. no problemo...

Op 6 november 2007 22:01:35 schreef Stephane1976:
Bart

Kan je eens een ontdender routine schrijven door gebruik van een Timer want ik moet starten van een clock van 50MHz en het ontdenderen is 20 ms

Ik heb al zitten zoeken hoe je dat moet doen maar vind het niet direct

Ik weet dat we bij de stijgende flank een timer moeten starten en deze stoppen als we een dalende flank detecteren maar hoe doe je dat in VHDL?

Waar moet ik nu eigenlijk de pinnen programmeren van die drukknop, die fysieke pinnen weet ik wel

Graag een berichtje terug

Kan je ook eens zeggen hoe ik 2 snelheden kan maken als je drukt op eerste knopje moet hij naar links lopen en met ander knopje naar rechts?

Gewoon principe van bvb een 4 LEDS looplicht

Wat je het beste kunt maken is een clokced event. In de kop staat dan altijd:

IF sample'EVENT and sample = '1' THEN

Daaronder kun je alles plaatsen wat je maar wilt.
In het geval van een deler vanuit 50 MHz, kun je het beste een teller ontwerpen zoals je zou doen in software. Je wilt dan bijv. naar 1 kHz.
Je wilt de klok dus delen door 50000.

Dat is dus een 16 bits teller die je elke klok verhoogd. Op 0 maak je de uigang laag en op 25000 maak je de uitgang hoog. Op 50000 reset je de teller.

Die module of process kun je dan koppelen aan de ontdender shakeling.

Wat de voorbeeldcode doet is reageren op de ingang.
Als de ingang '1' is dan wordt een teller verhoogd. Als de waarde van de teller bijv. 15 of 20 is (na 20ms dus) dan wordt de ingang doorgezet.
De truuk is om de teller door te laten lopen tot het dubbele van die waarde, tot 30 of 40 dus.
Als de ingang '0' is wordt de teller weer verlaagd.
Als de tellerwaarde onder de 15 of 20 komt, dan wordt e uitgang '0'.

Je hebt dus 2 modules nodig:

1. om je klok te delen naar een frequentie van 1 kHz.
2. een teller om de ingang te ontdenderen.

Je hoeft dus geen timer te starten op de opgaande flank. Je 'sampelt' 1000x per seconde de ingang en zo bepaal je of de schakelaar gedrukt is of niet.

De werking is hetzelfde.

Voor je uiteindelijke schakeling (looplicht) heb je nog wel wat meer modules nodig. Als je met modules werkt, dan hoef je de code maar eenmaal te schrijven.

Even een oud topic oprakelen, maar ik ben me in de VHDL aan het storten, en ik kon deze even niet volgen:

Op 6 november 2007 13:58:48 schreef Bart Hiddink:


    IF ffa > 0 THEN
      ffa <= ffa - 1 ;
    ELSIF ffa > 15 THEN -- de_bounce_length = 16
      ffa <= 31; -- de_bounce_lenght *2
    END IF;

Na die eerste IF komt hij toch alleen bij de ELSIF op het moment dat ffa > 0 niet waar is? Dus dan heeft die ffa > 15 conditie toch geen enkele nut, immers, als ffa > 0 niet waar is, dan moet ffa wel kleiner-of-gelijk zijn aan 0.

Ik zie overigens wel in waarom de code gewoon werkt * , ben zelfs niet helemaal zeker van de bedoeling van die stuk code wat m.i. nooit uitgevoerd zal worden. Een soort hysterese inbouwen ofzo? Iemand die mij dit kan uitleggen? (Bart zelf??)

edit
* Nee, ik zie op het eind de conditie


IF ffa > 15 THEN -- de_bounce_length = 15
	out_put <= '1';
ELSE
	out_put <= '0';
END IF;

dus hij kan alsnog gaan klapperen. Die rare ELSIF zal dus toch iets moeten gaan doen lijkt het, maar ik heb het gevoel dat dit stuk code niet helemaal zuiver is.

zondagavond-schoppie


IF sample'EVENT and sample = '1' THEN
	IF in_put = '1' THEN
		IF ffa < 31 THEN -- de_bounce_length*2
			ffa <= ffa + 1 ;
		END IF;
	ELSE
		IF ffa > 0 THEN
			ffa <= ffa - 1 ;
		ELSIF ffa > 15 THEN -- de_bounce_length = 16
			ffa <= 31; -- de_bounce_lenght *2
		END IF;
	END IF;
END IF;

als de ingang hoog is : en de teller is kleinre dan 31 : tel op.
die teller loopt dus tot 31.

als deingang laag is:
als de teller groter is dan 0 : aftellen.
als de teller groter is dan 15 .. laden met 31 ...

daar is inderdaad iets niet juist ...
da werkt niet.

Hm, gelukkig; ben ik dus toch niet gek. (Nee, niet inkoppen ;)) Ik heb inmiddels wat herschreven, maar vind het er nog niet optimaal uitzien na synthese.

Free, ik zou jouw code graag met de RTL viewer bekijken, maar krijg errors bij het compilen en kan zelf geen Verilog:

Error (10170): Verilog HDL syntax error at temp_debounce_test.v(13) near text "and";  expecting ")", or "?", or binary operator
Error (10170): Verilog HDL syntax error at temp_debounce_test.v(14) near text "and";  expecting ")", or "?", or binary operator
Error (10170): Verilog HDL syntax error at temp_debounce_test.v(15) near text "="
Error (10170): Verilog HDL syntax error at temp_debounce_test.v(16) near text "="

[Bericht gewijzigd door Jochem op (65%)]

verdikke. ik zat zeker nog half te slapen ..



module debounce(input clock,reset,in,
                output reg out);

parameter threshold = 4'd9; // deze mag niet hoger zijn dan 4 bit ! ik zet hem op 9 voorloopig
reg [4:0] bounce;

always @(posedge clk,posedge reset)
if (reset) begin
   bounce <=4'b0;
   out <=0;
   end
else begin
   if (in & (bounce <>threshold)) bounce <= bounce +1;
   if (!in & (bounce <>0)) bounce <= bounce-1;
   if (bounce=0) out <=0;
   if (bounce=threshold) out <=1;
end
endmodule

vervang die 'and' door & en tis opgelost

Ik kwam toevallig in dit topic terecht en heb geen kennis van VHDL. Ik gebruik al wel een tijdje heel succesvol een debounce algorithme wat is afgeleid uit dit artikel pagina 21. Roep gewoon debounce aan in een loop met 5ms vertraging, dit geeft een responsetijd van 50 a 60 ms. Je kunt in kritische gevallen ook een interrupt genereren die elke zoveel ms een check doet en actie onderneemt als er een toets is ingedrukt.