12. NYOMÓGOMBOK ÉS KAPCSOLÓK PERGÉSMENTESÍTÉSE A FEJLESZTŐLAPON 1
Az FPGA eszközök bemeneti jeleit gyakran mechanikai kapcsolókkal hozzuk létre. Használható váltókapcsoló, amely a nulla és az egyes logikai szintnek megfelelő értékek közül az egyiket továbbítja az FPGA adott kivezetésére vagy egyetlen érintkezővel épített kapcsoló, amely a tápfeszültséggel- és a felhúzó/lehúzó ellenállással definiált szintet az ellenkező logikai értékre húzza bekapcsoláskor. 2
Minden esetben számítanunk kell a mechanikai érintkező pergésére, ami abból áll, hogy a logikai szint, kapcsolás közben, nem egyszer módosul, hanem többször oda-vissza vált (ábra), mire megnyugszik. 3
A kapcsoló pergése sok esetben a digitális berendezés téves működéséhez vezet. Például, ha egy lefutó élre működő számláló bemenetére vezetjük a fenti jelet, az egy helyett hetet fog lépni. Ráadásul a pergés egyedi, nem ismétlődő jelenség, így a berendezés válasza is esetrőlesetre változó. Ilyesmi, természetesen, nem engedhető meg, a digitális berendezésektől hibátlan és ismételhető viselkedést várunk el. 4
Az alábbi példában olyan megoldást mutatunk be, amely a kapcsoló egy aktiválásakor / deaktiválásakor egy felfutó vagy lefutó élt hoz létre, figyelmen kívül hagyva az FPGA bemeneti jelének a kapcsoló okozta pergését. Ezt a feladatot mindjárt a jel fogadását követően kell megoldani, hogy a további fokozatok működése zavartalan legyen. 5
12.1. ÚJ PROJEKT LÉTREHOZÁSA Az új projekt létrehozása ugyanúgy történik, ahogy azt a 10.1 pontban láttuk. A beállítások ablakban (Project Settings) a korábban megnyitott projekt beállításai jelennek meg. Ha nem akarunk áttérni másik FPGA eszközre, akkor nem kell semmit igazítani a beállításokon. 6
12.2. FELADAT DEFINIÁLÁSA A Basys2 fejlesztőlapon négy nyomógomb található az alábbi bekötésben: 7
Ezek közül a BTN0 jelölésű nyomógombot fogjuk használni. Az R42 ellenálláson keresztül a VCC3V3 táp magas logikai szintre húzza a nyomógomb és az ellenállás közötti pontot. Az IC8A logikai inverter ilyenkor alacsony logikai szintet hoz létre, ezt a BTN0 bemenetre továbbítja. Az R29 ellenállás és a C63 kondenzátor aluláteresztő szűrőként viselkedik. 8
A gomb minden lenyomásakor egy belső decimális számlálónak egyet kell felfelé számlálnia, a tartalmat a DSP0 kijelzőn kell megjeleníteni. Pergésmentesítés nélkül a számláló össze-vissza számlálna, mert egy-egy gombnyomáskor egynél több (változó számú) impulzus érkezne a számláló bemenetére. 9
A pergésmentesítés megoldására számos javaslatot találunk a szakirodalomban. Az itt leírt megoldás digitális átlagolásnak felel meg. A nyomógombbal képzett bemeneti jelet az órajel minden felfutó élénél beolvassuk, összesen fél millió alkalommal egy kiértékeléshez. Tekintettel az 50 MHz-es órajelre, minden 10 ms-os intervallum végén történik egy kiértékelés. 10
Ha a beolvasott érték az adott órajel periódusban logikai egyes, eggyel növeljük egy belső számláló tartalmát, nulla esetére tartjuk az addig elért értéket. Ha az intervallum (10 ms) végén az átlagolást végző számláló tartalma 250.000 vagy annál nagyobb, tekinthető úgy, hogy a kapcsoló megnyugodott a magas logikai szinten, ill. közel van a megnyugváshoz. Kisebb tartalom esetén a logikai szintet alacsonynak nyilvánítjuk. A belső számláló tehát a gombnyomásokat számlálja. 11
12.3. TERV HDL LEÍRÁSA A pergésmentesítést végző egység és a decimális számláló Verilog nyelvi leírását alább láthatjuk. A leírás kezdetén deklaráljuk az adathordozókat, majd példányosítjuk az órajel modult. Ez esetben nem szükséges sem az órajel frekvenciájának növelése sem a csökkentése, ugyanakkor az egész terv egy órajel tartományban (domén) működhet, ami jelentősen egyszerűsíti a leírást. 12
A kijelző AN1, AN2, AN3 vezérlőjeleit egyesre kell állítani, hogy csak a jobb oldali kijelző legyen aktív, ezen kívánjuk megjeleníteni a számláló tartalmát (DSP0). Az első always eljárásban végezzük a szegmenseket meghajtó jelek (DSP0_To_Display) képzését a számláló pillanatnyi tartalma alapján. Nem szükséges ezt másodpercenként ötven milliószor végezni (ezt jelenti az érzékenységi listában a posedge Clk50MHz), ez adja a legegyszerűbb HDL leírást és szintetizálandó hálózatot. 13
Az első always eljárást követő deklarációk a második eljárásban szereplő adathordozókat deklarálják. A második always eljárás végzi a nyomógomb állapotának átlagolását. Az átlagolást 10ms-ig végezzük, remélve, hogy a kapcsoló pergése ennél gyorsabb, így az átlagolt jel monoton lesz (az egymás utáni értékek nem fognak le-fel ugrálni). 14
Az átlagolási periódust a cnt_10ms számláló határozza meg: 50MHz-es órajel mellett az 500.000-es modulusú számláló számlálási periódusa 10ms. Az átlagolás abból áll, hogy az említett periódus alatt megszámláljuk a nyomógombról érkező egyeseket. Ha ezek többségben vannak, úgy tekinthetjük, hogy a gomb meg lett nyomva (Btn0=1 b1). Ilyenkor (a Btn0 jel felfutó élénél) növelni kell eggyel a DSP0 számláló tartalmát. 15
module Pergesmentesites( output reg [7:0] DSP0_To_Display, output AN0, AN1, AN2, AN3, input ibtn0, input iclk50mhz); DCM_Module DCM_Module_inst(iClk50MHz,Clk50MHz); reg [3:0] DSP0 = 0; assign AN0 = 0; assign AN1 = 1'd1; assign AN2 = 1'd1; assign AN3 = 1'd1; 16
always@(posedge Clk50MHz) begin case(dsp0) 4'd0: DSP0_To_Display <= ~(8'b0011_1111); 4'd1: DSP0_To_Display <= ~(8'b0000_0110); 4'd2: DSP0_To_Display <= ~(8'b0101_1011); 4'd3: DSP0_To_Display <= ~(8'b0100_1111); 4'd4: DSP0_To_Display <= ~(8'b0110_0110); 4'd5: DSP0_To_Display <= ~(8'b0110_1101); 4'd6: DSP0_To_Display <= ~(8'b0111_1101); 4'd7: DSP0_To_Display <= ~(8'b0000_0111); 17
4'd8: DSP0_To_Display <= ~(8'b0111_1111); 4'd9: DSP0_To_Display <= ~(8'b0110_1111); endcase end reg [3:0] buf_btn0 = 0; reg [18:0] cnt_10ms = 0, Av_Btn0 = 0; reg Btn0 = 0, 18
Prev_Btn0 = 0; always@(posedge Clk50MHz) begin buf_btn0 <= {buf_btn0[2:0], ibtn0}; cnt_10ms <= cnt_10ms + 1'b1; if(cnt_10ms == 19'd500_000) 19
begin Av_Btn0 <= 0; Btn0 <= (Av_Btn0 >= 18'd250_000)? 1'b1 : 0; Prev_Btn0 <= Btn0; if({btn0, Prev_Btn0} == 2'b10) if(dsp0== 4'd9) DSP0 <= 0; else DSP0 <= DSP0 + 1'd1; end 20
else begin if(buf_btn0[3] == 1'b1) Av_Btn0 <= Av_Btn0 + buf _Btn0[3]; end end endmodule 21