Forum: FPGA, VHDL & Co. Pulsweitenmodulation


von nobody (Gast)


Lesenswert?

Hallo Leute,

ich bin neu in VHDL Programmieren und habe bei der Frage den Kopf 
zerbrochen, leider funktioniert mein Programm nicht. Ich möchte aber 
auch nicht blind aus dem Internet irgendetwas zusammenbasteln sondern 
mein Code funktionieren bringen.
Es muss ein Signal mit Pulseweiten Modulation erzeugt werden, das 39% 
duty cycle hat. Das FPGA hat ein 50 MHz Clock und die Frequenz des PWM 
Signals soll 100 kHz sein. Was mache ich da falsch???

Der Code:
1
library IEEE;
2
use IEEE.std_logic_1164.all;
3
4
entity pwm is
5
    port(   CLK    : in    std_logic;
6
            O      : out   std_logic);
7
end pwm;
8
     
9
architecture behavior of pwm is
10
signal newClock : std_logic := '1';   
11
constant clock_freq : integer := 500; 
12
constant duty: integer := 0.39*clock_freq/2;  
13
begin 
14
  process  (CLK)  
15
  variable counter : integer range 0 to ((clock_freg/2)-1):= 0;
16
  begin
17
  if CLK = '1' and CLK'event then
18
    if(counter = duty-1) then  
19
      newClock <= not newClock;
20
      counter = 0;
21
    elsif (counter < duty -1) then
22
      counter = counter +1;
23
    end if;
24
    end if;  
25
  end process;
26
end behavior;

von Sigi (Gast)


Lesenswert?

nobody schrieb:
> constant duty: integer := 0.39*clock_freq/2;

1. Damit wird die DutyCycle-Länge zu 0.39/2.
2. Du setzt nirgends das Signal "O"
(3. verwende besser Signale statt Variablen)

"O" kann z.B. so gesetzt werden:
1
  ..
2
  if CLK = '1' and CLK'event then
3
    if(counter = duty-1) then
4
      newClock <= not newClock;
5
      counter = 0;
6
      O <= '1';     -- !!!!!!!!!!
7
    elsif (counter < duty -1) then
8
      counter = counter +1;
9
      O <= '0';     -- !!!!!!!!!!
10
    end if;
11
  end if;
12
  ..

von Sigi (Gast)


Lesenswert?

grosser Fehler, ist schon spät, korrekt z.B.:
1
  constant duty: integer := 0.39*clock_freq;
2
  signal pwm : std_logic := '0';
3
4
  process  (CLK)
5
  variable counter : integer range 0 to clock_freg-1 := 0;
6
  begin
7
    if CLK = '1' and CLK'event then
8
9
      if(counter = duty-1) then
10
        pwm <= '1';
11
      end if;
12
13
      if(counter = clock_freg-1) then
14
        newClock <= not newClock;
15
        counter = 0;
16
        pwm <= '0';
17
      elsif (counter < duty -1) then
18
        counter = counter +1;
19
      end if;
20
21
    end if;
22
  end process;
23
24
  O <= pwm;

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


Angehängte Dateien:

Lesenswert?

nobody schrieb:
> ich bin neu in VHDL Programmieren und habe bei der Frage den Kopf
> zerbrochen, leider funktioniert mein Programm nicht.
Überleg mal, warum es VH-D-L heißt und nicht VH-P-L...

> leider funktioniert mein Programm nicht.
Was funktioniert denn an deiner Beschreibung nicht?
Welche Fehlermeldungen bekommst du?
Was erwartest du?
Was passiert stattdessen?
Wie hast du das festgestellt?
Wie sieht deine Testbench aus?
(gerade so eine PWM ist ja die dankbarste und simpelste Anwendung für 
eine Testbench: Takt anlegen und Waveform ansehen...)

> constant duty: integer := 0.39*clock_freq/2;
Ich kann mir gut vorstellen, dass schon das shiefgeht. Denn VHDL hat 
eine strenge Typenkontrolle. Ohne die Operatoren zu überladen wirst du 
nicht einen integer mit einem float multiplizieren und anschließend 
zuweisen können...

> counter = 0;
Und das geht natürlich auch schief. Ein "=" ist der Vergleichsoperator 
in VHDL...

> variable counter : integer range 0 to ((clock_freg/2)-1):= 0;
clock_freg?
Sag mal, hast du diese Beschreibung überhaupt mal durch den 
Syntax-Check gelassen?

>   newClock <= not newClock;
So werden in einem FPGA keine Takte erzeugt. Nimm stattdessen einen 
Clock-Enable.

> Ich möchte aber auch nicht blind aus dem Internet irgendetwas
> zusammenbasteln
Ich habe "deine"  Beschreibung mal ein wenig angepasst und bekomme damit 
die gewünschte PWM raus. Sieh es dir einfach mal an. Du musst es ja 
nicht kopieren...
1
library IEEE;
2
use IEEE.std_logic_1164.all;
3
4
entity pwm is
5
    port(   CLK    : in    std_logic;
6
            O      : out   std_logic);
7
end pwm;
8
     
9
architecture behavior of pwm is
10
constant clock_freq : integer := 500; 
11
constant duty: integer := 199;  
12
signal counter : integer range 0 to clock_freq := 0;
13
begin 
14
15
  -- PWM-Rampenzähler
16
  process  (CLK)  begin
17
    if CLK = '1' and CLK'event then
18
      if (counter = clock_freq) then  
19
        counter <= 0;
20
      else 
21
        counter <= counter +1;
22
      end if;  
23
    end if;  
24
  end process;
25
26
  -- PWM Vergleicher  
27
  O <= '1' when counter<duty else '0';
28
29
end behavior;
Und sieh dir mal meine beiden Kommentare an. Genau das hatte ich im 
Kopf, als ich diese PWM beschrieben habe: ich brauche einen Zähler für 
die "Rampe" und einen Vergleicher. Und wenn ich mir das bildlich 
vorstellen kann, nur dann kann ich es auch beschreiben...

BTW1: was meinst du eigentlich mit "PWM-Takt soll 100kHz sein"? Soll 
sich die PWM dann mit 100kHz wiederholen, oder sollen diese "100kHz" 
nochmal vom PWM-Zähler heruntergeteilt werden, so dass bei einer 
8-Bit-PWM dann am Ausgang 390Hz herauskommen?

BTW2: ein paar Zeilen über jeder Texteingabebox sthet das hier:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
...
4
Formatierung (mehr Informationen...)
5
...
6
    [vhdl]VHDL-Code[/vhdl]
Probiert das mal aus...

von Jan (Gast)


Lesenswert?

Lothar M. schrieb:
> architecture behavior of pwm is
> constant clock_freq : integer := 500;
> constant duty: integer := 199;
> signal counter : integer range 0 to clock_freq := 0;
> begin

Ich glaube
1
 constant duty: integer := 199
 muss 195 sein um genau die 39% duty cycle zu erhalten oder?

Gruß Jan

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


Lesenswert?

Jan schrieb:
> 199  muss 195 sein um genau die 39% duty cycle zu erhalten oder?
Kann gut sein. Man kann das auch ausrechnen lassen. Dazu braucht mal 
dann aber noch ein paar Konvertierungen und Casts... ;-)
1
library IEEE;
2
use IEEE.std_logic_1164.all;
3
4
entity pwm is
5
    port(   CLK    : in    std_logic;
6
            O      : out   std_logic);
7
end pwm;
8
     
9
architecture behavior of pwm is
10
constant f_clk  : integer := 50000000;
11
constant f_pwm  : integer := 100000;
12
constant r_pwm  : integer := f_clk/f_pwm;
13
14
constant duty   : integer := integer(0.39*real(r_pwm)); 
15
16
signal counter  : integer range 0 to r_pwm-1 := 0;
17
18
begin 
19
20
  process  (CLK)  begin
21
    if CLK = '1' and CLK'event then
22
      if (counter = r_pwm-1) then  
23
        counter <= 0;
24
      else 
25
        counter <= counter +1;
26
      end if;  
27
    end if;  
28
  end process;
29
  
30
  O <= '1' when counter<duty else '0';
31
32
end behavior;

von nobody (Gast)


Lesenswert?

Hallo,

Der Fehler mit Fliesskommazahl und integer habe ich später auch gemerkt, 
na ja dumm gelaufen. Tut mir leid, dass ich euch mit so einem öden 
Fehler beschäftigt habe, inklusive syntax Fehler und die Zuweisung des 
Ausgangssignals!
Verstehe aber nicht warum die Variante mit 39*clock_freq/200 nicht 
funktionieren würde.

Danke für die Korrekturen,
nobody.

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


Lesenswert?

nobody schrieb:
> Verstehe aber nicht warum die Variante mit 39*clock_freq/200 nicht
> funktionieren würde
Wer sagt das das nicht ginge?
Die Formel würde doch (hinreichend genau) funktionieren...

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.