Forum: FPGA, VHDL & Co. PWM mit 100% Duty Cycle


von enan (Gast)


Lesenswert?

Hi Leute,
habe ein PWM Modul geschrieben, welches in duty cycle und frequenz 
einstellbar ist. Funktioniert so weit auch alles wie gewünscht. 
Lediglich bei einem duty cycle von 100% (also duty_cycle = x"FF") ist 
das PWM Signal nicht dauerhaft 1. Das kommt daher, dass der counter 
duty_c zuerst mit dem endwert verglichen wird und dann erhöht. Jemand ne 
idee wie man die 100% duty cycle noch hinbiegen kann?

und hier der vollständige code:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.all;
3
use IEEE.std_logic_unsigned.all;
4
use IEEE.numeric_std.all;
5
6
7
entity PWM is 
8
    Port (en : in STD_LOGIC;
9
        clk : in STD_LOGIC;
10
        reset : in STD_LOGIC;
11
        duty_cycle : in  STD_LOGIC_VECTOR (7 downto 0);
12
        freq : in  STD_LOGIC_VECTOR (7 downto 0);
13
        pwm : out  STD_LOGIC);
14
end PWM;
15
16
architecture Behavioral of PWM is
17
18
SIGNAL duty_c    :  STD_LOGIC_VECTOR(7 DOWNTO 0);
19
SIGNAL cnt      :  STD_LOGIC_VECTOR(7 DOWNTO 0);
20
SIGNAL ce      :  STD_LOGIC;
21
22
begin
23
24
-----------------------------------------------
25
-- Clock enable Generator
26
-----------------------------------------------
27
28
PROCESS (clk)
29
BEGIN
30
  
31
  IF reset = '1' THEN
32
    cnt <= (OTHERS => '0');
33
    ce <= '0';
34
  ELSIF rising_edge(clk) THEN
35
    IF en = '1' THEN
36
      IF cnt = freq THEN  
37
        ce <= '1';
38
        cnt <= (OTHERS => '0');
39
      ELSE
40
        ce <= '0';
41
        cnt <= cnt + '1';
42
      END IF;
43
    ELSE
44
      cnt <= (OTHERS => '0');
45
      ce <= '0';
46
    END IF;
47
  END IF;
48
  
49
END PROCESS;
50
51
------------------------------------------------
52
-- PWM Signal Erzeugung
53
------------------------------------------------
54
PROCESS (reset, clk, ce)
55
BEGIN
56
57
  IF reset = '1' THEN
58
    duty_c <= (OTHERS => '0');
59
    pwm <= '0';
60
  ELSIF rising_edge(ce) THEN
61
    IF (en = '1') THEN
62
      IF  (duty_c < duty_cycle) THEN
63
        pwm <= '1';
64
      ELSE
65
        pwm <= '0';
66
      END IF;
67
    duty_c <= duty_c + '1';
68
    ELSE 
69
      pwm <= '0';
70
    END IF;
71
  END IF;
72
  
73
END PROCESS;
74
75
end Behavioral;

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


Lesenswert?

> use IEEE.STD_LOGIC_1164.all;
> use IEEE.std_logic_unsigned.all;
> use IEEE.numeric_std.all;
Ach neeeee, warum denn immer?
Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"
Seis drum...


> duty_c <= duty_c + '1';
Du darfst deinen Zähler nicht bis 255 zählen lassen.
Der darf maximal bis 254 zählen...
1
  if (duty_c=254) then
2
      duty_c <= (others =>'0');
3
  else
4
      duty_c <= duty_c + '1';
5
  end if;

BTW: Ich hasse solche implizite Überläufe (z.B. von x"FF" nach x"00"). 
Das lässt sich nur sehr schlecht simulieren und gestaltet die 
Fehlersuche trickreich. Deshalb nehme ich für Zähler immmer gleich einen 
Integer mit dem passenden Range...
http://www.lothar-miller.de/s9y/categories/47-PWM

von berndl (Gast)


Lesenswert?

enan schrieb:
> ELSIF rising_edge(ce) THEN

Aua, auch noch eine Pseudoclock...

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


Lesenswert?

berndl schrieb:
> auch noch eine Pseudoclock...
Böse, böse...  :-o

von enan (Gast)


Lesenswert?

Hey,
danke für die nette und kompetente Hilfe Lothar!
Die STD_LOGIC_ARITH library verwende ich doch allerdings garned... ?

Hab den duty cycle counter geändert und so funktionierts. Hab mir auch 
zuvor schon den Artikel auf deiner Homepage über PWM und Taktteiler 
durchgelesen. Wollte es im Prinzip auch so realisieren aber ich wollte 
den duty cycle von außen einstellbar haben und deshalb konnt ich keine 
constant oder integer nehmen. Bin beim Versuch den duty cycle vector in 
ne integer zu wandeln und damit zu zählen nicht weiter gekommen. Ist 
aber nicht so wichtig.

Ich weiß selbst, dass es kein gutes tun ist rising_edge(ce) zu 
verwenden. Falls jemand ne bessere Lösung dafür hat wär ich dankbar.

Zum Schluß noch ein Lob an dich und deine Homepage Lothar. Find ich 
persönlich klasse gemacht. Dankeee

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


Lesenswert?

enan schrieb:
> Die STD_LOGIC_ARITH library verwende ich doch allerdings garned... ?
Warum dann die /use IEEE.std_logic_unsigned.all/?

enan schrieb:
> Falls jemand ne bessere Lösung dafür hat wär ich dankbar.
1
:
2
:
3
  ELSIF rising_edge(clk) THEN  -- clk ist der einzige Clock im Design
4
   if ce='1' then              -- ce heißt Clock-Enable
5
    IF (en = '1') THEN
6
      :
7
    END IF;
8
   end if;                     -- ce
9
  END IF;
10
:
11
:

von enan (Gast)


Lesenswert?

Okay, die lib ist raus geflogen!

wenn ich nur clk in die sensitivity list packe dann hat mein PWM Puls 
die exakt gleiche Zeitdauer wie ce, also einen systemtakt. Habs schon 
ausprobiert und so wars nicht gedacht :-)

von enan (Gast)


Lesenswert?

Hab das Ei gefunden, jetzt läufts.

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.