Forum: FPGA, VHDL & Co. VHDL Text für die Ertönung eines 1 kHz Tons


von Slam J. (slamjam)


Lesenswert?

Hallo!

Ich kenne mich nicht gut aus mit VHDL und bin fast fertig mit meiner 
Synthesis meines VHDL Textes, bis mir grad einfiel, dass ich den Teil 
mit der Ertönung eines 1kHz Tons für eine halbe Sekunde beim Drücken 
einer Taste vergessen habe.

Es handelt sich um ein Xilinx Board der Reihe Spartan3 mit einem 
XC3S700A!

Ich bin für jede Hilfe dankbar!

von Duke Scarring (Gast)


Lesenswert?

Zwei Zähler, einen der 2kHz macht und damit Deinen Piepser toggelt und 
den zweiten, der nach einer halben Sekunde den ersten Zähler das enable 
wegnimmt.

Duke

von Marc (Gast)


Lesenswert?

Platzsparender kann man das Ganze auch in ein paar SRL16E integrieren.

Beispiele hierfür sind auf dieser PDF (Stichwort: Puls-Generator):
http://www.xilinx.com/support/documentation/white_papers/wp271.pdf

Gruß Marc

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Platzsparender ...
Bei Teilern von z.B. 50MHz nach 2kHz (=25000) und dann von 1ms nach 
500ms (=500) würde ich das so nicht sagen. Das wird für einen kleinen 
Teiler von 260 in dem WP271 in Frage gestellt. Allerdings sei so eine 
Schieberegister-Lösung eventuell einfacher und praktischer:
1
This solution is larger than the counter-based pulse generator, 
2
but the simplicity of this technique makes it practical.

von Marc (Gast)


Lesenswert?

Du hast Recht, der Multi-stage Divider im Beispiel ist vorallem für 
kleine Divisionen gut geeignet. Da hier aber nur ein Summer angesteuert 
werden soll und Synkronität mit den 50MHz am Ausgang vernachlässigt 
werden kann, ist es möglich diesen so umzuformen, dass er in diese 
Anwendung genau hineinpasst.
Dein Zitat stammt übrigens aus dem Hot-Counter (viele FF in einer 
Schleife). Den meinte ich nicht.

Um auf dein Beispiel einzugehen:

 50 MHz / 25  =>  2 SRL16
  2 MHz / 10  =>  1 SRL16
200 KHz / 10  =>  1 SRL16
 20 KHz / 10  =>  1 SRL16
  2 KHz

Beispiel-Code:
1
entity Div_25k is
2
    Port ( CLK_IN : in  STD_LOGIC;
3
           CLK_OUT : buffer STD_LOGIC);
4
end Div_25k;
5
6
architecture Behavioral of Div_25k is
7
  signal Stage_1 : std_logic_vector(24 downto 0) := "0000000000000000000000001";
8
  signal Stage_2 : std_logic_vector(9 downto 0) := "0000011111";
9
  signal Stage_3 : std_logic_vector(9 downto 0) := "0000011111";
10
  signal Stage_4 : std_logic_vector(9 downto 0) := "0000011111";
11
begin
12
13
  process(CLK_IN,Stage_1(24),Stage_2(9),Stage_3(9))
14
  begin
15
    if rising_edge(CLK_IN) then
16
      Stage_1 <= Stage_1(23 downto 0) & Stage_1(24);
17
    end if;
18
    if rising_edge(Stage_1(24)) then
19
      Stage_2 <= Stage_2(8 downto 0) & Stage_2(9);
20
    end if;
21
    if rising_edge(Stage_2(9)) then
22
      Stage_3 <= Stage_3(8 downto 0) & Stage_3(9);
23
    end if;
24
    if rising_edge(Stage_3(9)) then
25
      Stage_4 <= Stage_4(8 downto 0) & Stage_4(9);
26
    end if;
27
  end process;
28
  
29
  CLK_OUT <= Stage_4(9);
30
31
end Behavioral;

Verbrauch: 5 SRL16 ~ 4 SLICEs nach Synthese (natürlich mit Warnung auf 
skew)

Hab mal probehalber den selben Divider mit einen normalen Counter ( + 
Compare ) syntetisiert und kahm allein hierfür auf 13 SLICEs.

Der Divider von 1 KHz auf 500 Hz braucht in beiden Fällen nur 1 LUT.

Platzsparender ... ?
Antwort: JA, man muss aber bedenken, dass diese Art von Divider nicht
             für alles geeignet ist und auch einige Probleme mit sich
             bringen kann.

Ob man das Ganze noch als einfach und praktisch ansehen kann, ist die 
andere Frage ;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ob man das Ganze noch als einfach und praktisch ansehen kann, ist die
> andere Frage ;-)
So einen asynchronen Zähler würde ich bestenfalls machen, wenn ich 
wirklich kein einziges FF mehr freihabe.. :-o


> Der Divider von 1 KHz auf 500 Hz braucht in beiden Fällen nur 1 LUT.
Es ging ursprünglich um 1ms (= 1kHz) und 500ms (= Piepdauer)  ;-)

von Slam J. (slamjam)


Angehängte Dateien:

Lesenswert?

Danke erst mal für die Tips!

Ich weiß jetzt nicht genau, ob ich das Prellen meines Schalters (in dem 
Fall der Taste "south") mitberücksichtigen muß. Die Prellzeit beträgt 
200ms.


Für das Prellen habe ich:



FOLGEZUSTANDSBERECHNUNG: process (taste,ZUSTAND)
  begin
    case ZUSTAND is
    when A => if A = '1' THEN FOLGEZUSTAND <= B;
      else FOLGEZUSTAND <= A;
      end if ;
      F <= '0', ci <= '0';
    when B => if co = '1' THEN FOLGEZUSTAND <= C;
      else FOLGEZUSTAND <= B;
      end if;
      F <= '0', ci <= '1';
    when C => THEN FOLGEZUSTAND <= D;
      F <= '1', ci <= '1';
    when D => A = '0' THEN FOLGEZUSTAND <= E;
      else FOLGEZUSTAND <= D;
      end if ;
      F <= '0', ci <= '0';
    when E => if co = '1' THEN FOLGEZUSTAND <= F;
      else FOLGEZUSTAND <= E;
      end if ;
      F <= '0', ci <= '1';
    when F => THEN FOLGEZUSTAND <= A;
      F <= '0',ci <= '1';
    end case;
  end process FOLGEZUSTANDSBERECHNUNG;

FOLGEZUSTANDSBERECHNUNG: process (taste,ZUSTAND)
  begin
    case ZUSTAND is
    when A => if B = '1' THEN FOLGEZUSTAND <= B;
      else FOLGEZUSTAND <= A;
      end if ;
      F <= '0', ci <= '0';
    when B => if co = '1' THEN FOLGEZUSTAND <= C;
      else FOLGEZUSTAND <= B;
      end if;
      F <= '0', ci <= '1';
    when C => THEN FOLGEZUSTAND <= D;
      F <= '1', ci <= '1';
    when D => B = '0' THEN FOLGEZUSTAND <= E;
      else FOLGEZUSTAND <= D;
      end if ;
      F <= '0', ci <= '0';
    when E => if co = '1' THEN FOLGEZUSTAND <= F;
      else FOLGEZUSTAND <= E;
      end if ;
      F <= '0', ci <= '1';
    when F => THEN FOLGEZUSTAND <= A;
      F <= '0',ci <= '1';
    end case;
  end process FOLGEZUSTANDSBERECHNUNG;


ZUSTANDSAUSGABE: process (ZUSTAND)
  begin
    CASE ZUSTAND is
      when A => STATE <= "000";
      when B => STATE <= "001";
      when C => STATE <= "010";
      when D => STATE <= "100";
      when E => STATE <= "101";
      when F => STATE <= "110";
    end case;
  end process ZUSTANDSAUSGABE;


Irgendwelche Anmerkungen oder Tips?

 Wie gesagt soll beim Drücken der Taste south für eine halbe Sekunde ein 
1kHz-Ton ertönen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

1
 FOLGEZUSTANDSBERECHNUNG: process (taste,ZUSTAND)
Unvollständige Sensitivliste, B und co fehlen --> fehlerhafte Simulation

Aber das ist nicht so schlimm. Schlimm ist der Aufwand, den du treibst. 
Eine Abfrage auf eine steigende bzw. fallende Flanke geht ganz einfach 
mit einem Schieberegister:
http://www.lothar-miller.de/s9y/categories/5-Entprellung

Und die Geschichte mit dem Debuggen über
ZUSTANDSAUSGABE: process (ZUSTAND)
geht auch wesentlich kompakter. Siehe 
http://www.lothar-miller.de/s9y/categories/37-FSM
Also einfach so:
1
   STATE  <= std_logic_vector(to_unsigned(ZUSTAND'pos(ZUSTAND),3));

Dazu solltest du aber die
1
use IEEE.numeric_std.ALL;
verwenden, sonst braucht du andere Umwandlungsroutinen von Integer nach 
Vektor.

von Marc (Gast)


Lesenswert?

> Es ging ursprünglich um 1ms (= 1kHz) und 500ms (= Piepdauer)  ;-)

Misst, da haste mich erwicht XD
Hast aber recht, selbst ich verwende solche Sachen nur in 
Ausnahmefällen.

Verkehrt ist es sicherlich nicht, sowas im Hinterkopf zu haben ^_^

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Wie gesagt soll beim Drücken der Taste south für eine halbe Sekunde
> ein 1kHz-Ton ertönen.
1
 signal count500us : integer range 0 to 24999; -- bei 50MHz : pro halbe ms --> 25000 Takte
2
 signal count500ms : integer range 0 to 1000;   
3
4
 process begin
5
    wait until rising_edge(clk);
6
    if (count500us < 24999) then 
7
       count500us <= count500us+1; 
8
    else 
9
       if (count500ms < 1000) then
10
           beeper <= not beeper;
11
           count500ms <= count500ms+1;
12
       else
13
           beeper <= '0';
14
       end if;
15
    end if;
16
    if taster_flanke = '1' then 
17
       count500us <= 0;
18
       count500ms <= 0; 
19
    end if;
20
 end process;

von Marc (Gast)


Lesenswert?

Setz noch nach dieser Zeile:
1
if (count500ms < 1000) then
diese Zeile ein:
1
  count500us <= 0;
Dann dürfte es funktionieren (ein Summer mit 25 MHz funktioniert 
schlecht)


bitte nicht böse sein

von Slam J. (slamjam)


Lesenswert?

Hallo!


Ich hab deins so übernommen und dann so hingeschrieben:

signal count500us : std_logic_vector range 0 to 24999; -- bei 50MHz : 
pro halbe ms --> 25000 Takte
signal count500ms : std_logic_vector range 0 to 1000;

 process begin
    wait until rising_edge(clk);
    if (count500us < 24999) then
       count500us <= count500us+1;
    else
       if (count500ms < 1000) then
           beeper <= not beeper;
           count500ms <= count500ms+1;
       else
           beeper <= '0';
       end if;
    end if;
    if bcd_south = '1' then
       count500us <= 0;
       count500ms <= 0;
    end if;
 end process;




Synthesize war in Ordnung, nur ein paar Warnungen!


Vielen herzlichen Dank

von Slam J. (slamjam)


Lesenswert?

Hab den Kommentar von Marc erst nach meinem letzten Kommentar gelesen!

Ist das so richtig, meine Marc's Aussage?

von Slam J. (slamjam)


Lesenswert?

signal count500us : std_logic_vector integer range 0 to 24999; -- bei 
50MHz : pro halbe ms --> 25000 Takte
 signal count500ms : std_logic_vector integer range 0 to 1000;

 process begin
    wait until rising_edge(clk);
    if (count500us < 24999) then
       count500us <= count500us+1;
    else
       if (count500ms < 1000) then
           count500us <= 0;
           beeper <= not beeper;
           count500ms <= count500ms+1;
       else
           beeper <= '0';
       end if;
    end if;
    if bcd_south = '1' then
       count500us <= 0;
       count500ms <= 0;
    end if;
 end process;


So in etwa?

von Marc (Gast)


Lesenswert?

müsste jetzt so richtig sein

Grüße Mark

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

@ Slam Jam
> Ich hab deins so übernommen
Hast du jetzt tatsächlich anderthalb Tage gewartet, bis einer eine 
Lösung hinkritzelt?  :-o

> Ist das so richtig, meine Marc's Aussage?
Wird schon stimmen...  :-o
Aber ich denke, du solltest das einfach mal so ein wenig mental 
nachvollziehen. Warum meint Marc wohl, dass es sinnvoll wäre, beim 
Überlauf den Zähler auch mal zurückzusetzen?

> Synthesize war in Ordnung, nur ein paar Warnungen!
Ja klar, du verwendest ja auch die alten Synopsys-Libs.

@ Marc
Du hast recht, die Zeile fehlt, aber das stimmt nicht:
> ein Summer mit 25 MHz funktioniert schlecht
Denn es ist komplizierter.
Der Zähler count500us wird als 15-Bit Zähler realisiert. Also würde von 
25000 bis 32767 der Beeper mit jedem Takt toggeln, dann aber von 0 bis 
24999 wieder Ruhe geben. Weil bis dahin aber schon längst der count500ms 
fertig ist, ist fast schlagartig nach dem Piepsanfang schon wieder 
Ruhe...

von Marc (Gast)


Lesenswert?

nicht ganz...

Auch wenn hier ein 15-bit Counter drin steckt, so wird count500us nur 
dann incrementiert, wenn
> count500us < 24999
ist.

d.h.

dein Code wird, sobalt taster_flanke auf '0' fällt, count500us auf 24999 
raufzählen und dann, sobalt er da angekommen ist, den Beeper 1000 mal 
mit voller Geschwindigkeit toggeln.
Eben bis count500ms die 1000 erreicht hat.

Danach ist Ruhe.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Danach ist Ruhe.
Gut so ;-)

von Marc (Gast)


Lesenswert?

X-D

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.