Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> VHDL

So erstellen Sie einen PWM-Controller in VHDL

Pulsweitenmodulation (PWM) ist eine effiziente Möglichkeit, analoge Elektronik von rein digitalen FPGA-Pins aus zu steuern. Anstatt zu versuchen, die analoge Spannung zu regulieren, schaltet PWM den Versorgungsstrom schnell bei voller Leistung zum analogen Gerät ein und aus. Diese Methode gibt uns eine präzise Kontrolle über den gleitenden Durchschnitt der Energie, die dem Verbrauchergerät zur Verfügung gestellt wird.

Beispiele für Anwendungsfälle, die gute Kandidaten für PWM sind, sind Audiomodulation (Lautsprecher), Lichtintensitätssteuerung (Lampen oder LEDs) und Induktionsmotoren. Letzteres umfasst Servomotoren, Computerlüfter, Pumpen, bürstenlose Gleichstrommotoren für Elektroautos und die Liste geht weiter.

Siehe auch:
RC-Servocontroller mit PWM von einem FPGA-Pin

Wie PWM funktioniert

Indem wir die Stromversorgung eines Geräts mit hoher Frequenz ein- und ausschalten, können wir den durchschnittlichen Strom, der durch das Gerät fließt, genau steuern. Die folgende Abbildung zeigt die Grundlagen der Funktionsweise von PWM. Der PWM-Ausgang steuert einen Binärschalter, der die Leistung entweder auf 100 % oder 0 % setzen kann. Durch schnelles Wechseln zwischen den beiden Extremen ist der Durchschnitt des gleitenden Fensters eine Funktion der Zeit, die in jedem der Zustände verbracht wird.

Einschaltdauer

Das Tastverhältnis ist der Schlüssel zur Steuerung der Leistung, die dem analogen Gerät in PWM zugeführt wird. Der Begriff Arbeitszyklus bedeutet, wie viel Zeit der PWM-Ausgang in der Position ON verbringt. Es ist üblich, die Einschaltdauer als Prozentsatz zu beschreiben, wie in der Abbildung unten gezeigt. In meinem VHDL-Beispiel werde ich jedoch später in diesem Artikel eine vorzeichenlose Binärzahl verwenden. Für uns ist es sinnvoller, eine Binärzahl zu verwenden, die die volle Auflösung des Arbeitszyklus in unserer VHDL-Implementierung darstellen kann.

Bei einem Arbeitszyklus von 0 würde der PWM-Ausgang kontinuierlich in der AUS-Position bleiben, während er bei 100 % ununterbrochen in der EIN-Position bleiben würde. Der Genauigkeitsgrad, den der PWM-Controller auf den Nutzlasteffekt ausüben kann, steht in direktem Zusammenhang mit der Länge des PWM-Zählers. Wir werden sehen, wie das im VHDL-Code funktioniert, wenn wir später in diesem Artikel einen PWM-Controller implementieren.

Die Formel zum Umwandeln der binären Darstellung des Arbeitszyklus in einen Prozentsatz ist unten gezeigt.

\mathit{duty\_cycle\_percentage} =\frac{\mathit{commanded\_duty\_cycle} * 100}{2^\mathit{pwm\_bits} - 1}

PWM-Frequenz

Wenn wir über die PWM-Schaltfrequenz sprechen, meinen wir, wie oft der PWM-Ausgang zwischen den Zuständen EIN und AUS wechselt, wie lange es dauert, bis der PWM-Zähler umläuft. Wie immer ist die Frequenz der Kehrwert der vollen PWM-Periode:

\mathit{pwm\_freq} =\frac{1}{\mathit{pwm\_period}}

Die ideale PWM-Frequenz hängt davon ab, welche Art von Gerät Sie steuern. Jede Zahl, die größer als ein paar hundert Hertz ist, sieht für das bloße Auge wie eine stabile Lichtquelle aus, wenn der Verbraucher eine LED ist. Bei einem bürstenlosen Gleichstrommotor liegt der Sweet Spot im Bereich von mehreren zehn Kilohertz. Stellen Sie die Frequenz zu niedrig ein, und es kann zu physischen Vibrationen kommen. Mit einer zu schnellen Oszillation verschwenden Sie Energie.

Zu beachten ist, dass die analoge Leistungselektronik nicht so schnell ist wie der digitale FPGA-Pin. Ein typisches PWM-Setup verwendet Leistungs-MOSFETs als Schalter, um den Strom zu steuern, der durch das analoge Gerät fließt.

Betrachten Sie das im Bild gezeigte Schema. Es ist Teil der LED-Treiberschaltung, die in meinem Dot-Matrix-VHDL-Kurs für Fortgeschrittene verwendet wird. Der FPGA-Pin steuert das Gate des MOSFET und fungiert als Leistungsschalter für die In-Serie-LED. Bei einer höheren Schaltfrequenz verbringt der Transistor mehr Zeit damit, weder vollständig geöffnet noch vollständig geschlossen zu sein. Das führt zu Energieverschwendung und übermäßiger Wärmeerzeugung im MOSFET.

PWM-Generatormodul

Lassen Sie uns eine standardmäßige, generische Implementierung eines PWM-Controllers in VHDL erstellen. Was ich mit Standard meine ist, dass dies dem entspricht, was die meisten erfahrenen VHDL-Designer erstellen würden, wenn Sie sie bitten würden, einen PWM-Controller in VHDL zu schreiben. Es ist generisch in dem Sinne, dass die PWM-Frequenz an die meisten Anwendungen angepasst werden kann.

Um unseren PWM-Generator auf einem echten FPGA zu testen, benötigen wir neben dem PWM-Controller noch ein paar weitere Module. Ich werde diese später vorstellen, wenn ich das PWM-Modul verwende, um die Beleuchtung einer LED auf dem Lattice iCEstick FPGA-Entwicklungsboard zu steuern. Aber lassen Sie uns zuerst über das PWM-Generatormodul sprechen.

PWM-Moduleinheit

Um das Modul anpassbar zu machen, habe ich einen generischen Port hinzugefügt, mit dem Sie zwei Konstanten zum Zeitpunkt der Instanziierung angeben können.

Der erste namens pwm_bits , bestimmt die Länge des internen PWM-Zählers. Diese Konstante legt die Bitlänge fest, nicht den maximalen Zählerwert. Sie können die PWM-Frequenz nicht als eine bestimmte Anzahl von Taktperioden angeben. Aber normalerweise müssen wir die PWM-Frequenz nicht mit 100 % Genauigkeit einstellen. Die ideale PWM-Frequenz ist eher ein Bereich, der gut funktioniert, als eine genaue Zahl.

Die andere generische Konstante heißt clk_cnt_len . Es gibt die Länge eines zweiten Zählers an, der die PWM-Frequenz effektiv senkt. Es fungiert als Taktteiler, ohne jedoch tatsächlich ein abgeleitetes Taktsignal zu erzeugen. Beachten Sie, dass ihm ein Standardwert von 1 zugewiesen ist. Wenn Sie diese Konstante auf 1 setzen, wird der Taktteiler deaktiviert und die zusätzliche Logik, die ihn handhabt, entfernt.

Ich werde dies erläutern und die Formel zur Berechnung der genauen PWM-Frequenz später im Artikel vorstellen.

entity pwm is
  generic (
    pwm_bits : integer;
    clk_cnt_len : positive := 1
  );
  port (
    clk : in std_logic;
    rst : in std_logic;
    duty_cycle : in unsigned(pwm_bits - 1 downto 0);
    pwm_out : out std_logic
  );
end pwm;

Da es sich um ein vollständig synchrones Modul handelt, sind die ersten beiden Signale die Uhr und das Zurücksetzen.

Die dritte Eingabe in der Portdeklarationsliste ist der Arbeitszyklus. Wie Sie dem obigen VHDL-Code entnehmen können, ist die Länge des duty_cycle Signal folgt den pwm_bits generische Konstante. Das bedeutet, dass die pwm_bits Konstante bestimmt, wie genau Sie die Stromversorgung des analogen Geräts regulieren können.

Das letzte Signal auf der Entität ist pwm_out . Das ist das PWM-modulierte Steuersignal, das Sie zu einem FPGA-Pin leiten und mit dem Gate Ihres MOSFET verbinden.

Interne Signale des PWM-Moduls

Das PWM-Modul enthält nur zwei interne Signale. Der erste ist der PWM-Zähler, der identisch mit dem duty_cycle ist Eingang. Genau wie letztere, die pwm_bits Die Konstante bestimmt auch die Länge dieses Signals.

signal pwm_cnt : unsigned(pwm_bits - 1 downto 0);
signal clk_cnt : integer range 0 to clk_cnt_len - 1;

Das zweite interne Signal heißt clk_cnt , und wie der Name schon sagt, dient es zum Zählen von Taktzyklen. Es ist vom Integer-Typ und wenn Sie clk_cnt_len festlegen bis 1, wird der Zählbereich zu (0 bis 0) ausgewertet – nur die Zahl 0.

PWM-Taktzykluszählerprozess

Der Prozess, der den Taktzähler implementiert, ist unkompliziert. Wenn das Modul nicht zurückgesetzt ist, zählt die Logik die Taktzyklen kontinuierlich und springt beim maximalen Wert von clk_cnt auf Null zurück Integer kann enthalten.

CLK_CNT_PROC : process(clk)
begin
  if rising_edge(clk) then
    if rst = '1' then
      clk_cnt <= 0;
      
    else
      if clk_cnt < clk_cnt_len - 1 then
        clk_cnt <= clk_cnt + 1;
      else
        clk_cnt <= 0;
      end if;
      
    end if;
  end if;
end process;

Beachten Sie, dass bei Verwendung des Standardwerts 1 für clk_cnt_len generisch sollte dieser Prozess während der Synthese verdampfen. Die interne if-Anweisung ist immer falsch, weil 0 < 1 - 1 ist falsch. Der Wert von clk_cnt ist dann immer 0. Die meisten Synthesetools erkennen das und optimieren den gesamten Prozess weg.

PWM-Ausgabeprozess

Der Prozess, der das PWM-Ausgangssignal einstellt, steuert auch den PWM-Zähler. Er erhöht den PWM-Zähler, wenn der Taktzykluszähler 0 ist. So funktioniert der PWM-Frequenzbegrenzungsmechanismus.

Ursprünglich wollte ich nur if clk_cnt = 0 then schreiben in Zeile 9, aber ich habe festgestellt, dass das Synthesetool nicht die gesamte Logik im Zusammenhang mit dem Taktzähler entfernt hat, als ich die Standardeinstellung clk_cnt_len verwendet habe Wert 1. Jedoch einschließlich clk_cnt_len in der if-Anweisung hat es geschafft. Es sollte keine nachteiligen Auswirkungen auf die Synthese haben, da clk_cnt_len ist eine Konstante. Das Synthesetool kann seinen Wert zur Kompilierzeit ermitteln und dann entscheiden, ob der Inhalt des Prozesses redundant ist oder nicht.

PWM_PROC : process(clk)
begin
  if rising_edge(clk) then
    if rst = '1' then
      pwm_cnt <= (others => '0');
      pwm_out <= '0';

    else
      if clk_cnt_len = 1 or clk_cnt = 0 then

        pwm_cnt <= pwm_cnt + 1;
        pwm_out <= '0';

        if pwm_cnt = unsigned(to_signed(-2, pwm_cnt'length)) then
          pwm_cnt <= (others => '0');
        end if;

        if pwm_cnt < duty_cycle then
          pwm_out <= '1';
        end if;

      end if;
    end if;
  end if;
end process;

Wenn clk_cnt_len größer als 1 ist, wird pwm_cnt Das Signal verhält sich wie ein freilaufender Zähler und erhöht sich, wenn clk_cnt ist 0. Es ist ein vorzeichenloser Typ, der automatisch auf 0 zurückgesetzt wird, wenn er überläuft. Aber wir müssen sicherstellen, dass es den höchsten Wert überspringt, bevor es auf Null umbricht.

In Zeile 14 im obigen Code überprüfe ich, ob der Zähler auf seinem zweithöchsten Wert steht. Wenn ja, setzen wir es an dieser Stelle auf 0. Ich verwende einen Trick, der funktioniert, egal wie lange die pwm_cnt Signal ist. Durch die Verwendung des to_signed Funktion erstelle ich eine neue vorzeichenbehaftete Konstante mit der gleichen Länge wie pwm_cnt , aber mit dem Wert -2.

Die vorzeichenbehaftete Zahl -2 in VHDL und Computern im Allgemeinen ist immer eine Reihe von Einsen und eine 0 ganz rechts. Das liegt daran, wie die Zeichenerweiterung funktioniert. Lesen Sie mehr darüber in meinem früheren Tutorial:

So verwenden Sie signierte und unsignierte Daten in VHDL

Indem wir schließlich den signierten Typ in einen unsignierten Typ umwandeln, erhalten wir den zweithöchsten Wert von pwm_cnt halten kann.

In Zeile 18 prüfen wir, ob der freilaufende PWM-Zähler größer als der Tastverhältniseingang ist. Wenn dies zutrifft, setzen wir den PWM-Ausgang auf „1“, da wir uns in der EIN-Periode des Tastverhältnisses befinden.

Deshalb mussten wir den PWM-Zähler bei seinem zweithöchsten Wert auf 0 zurücksetzen. Wenn der PWM-Zähler den höchstmöglichen Wert erreichen könnte, den das Tastverhältnis haben kann, wäre es nicht möglich, das Tastverhältnis auf 100 % einzustellen. Die pwm_cnt < duty_cycle Zeile wäre immer falsch, wenn pwm_cnt war auf seinem Maximalwert.

Dies ist sinnvoll, da wir zusätzlich zu den Zwischenschritten des Tastverhältnisses die vollständigen AUS- und EIN-Zustände darstellen müssen. Stellen Sie sich diese pwm_bits vor ist der Satz auf 2, und führen Sie die gesamte Zählsequenz als mentale Übung durch, um zu sehen, was ich meine!

\mathit{pwm\_hz} =\frac{\mathit{clk\_hz}}{(2^\mathit{pwm\_bits} - 1) * \mathit{clk\_cnt\_len}}

Unter Berücksichtigung dieser Tatsachen können wir die oben gezeigte Formel zur Berechnung der genauen PWM-Frequenz ableiten. Während clk_hz ist die Frequenz des FPGA-Systemtakts, die anderen beiden Variablen sind die generischen Eingangskonstanten.

Oberes Modul

Um das PWM-Modul auf echter Hardware zu testen, habe ich eine Implementierung erstellt, die die Beleuchtung der Power-On-LED auf dem Lattice iCEstick regelt. Ich verwende dieses erschwingliche FPGA-Entwicklungsboard sowohl in meinem VHDL-Fast-Track-Anfängerkurs als auch in meinem Dot-Matrix-FPGA-Kurs für Fortgeschrittene.

Das obige Bild zeigt die Vorderseite des über USB steckbaren iCEstick mit der durch den Pfeil gekennzeichneten Betriebs-LED. Auf dem iCEstick befinden sich fünf sternförmig angeordnete LEDs. Die Betriebs-LED ist grün, während die anderen rotes Farblicht abgeben. Auf dem iCEstick gibt es einen eigenen FPGA-Pin für jede der LEDs. Die genauen PIN-Nummern für die Steuerung finden Sie im iCEstick-Benutzerhandbuch.

Das folgende Diagramm zeigt, wie die Submodule im oberen Modul angeschlossen sind. Wir haben bereits über das PWM-Modul gesprochen, und ich werde die Zähler- und Reset-Module später in diesem Artikel kurz beschreiben.

Oberste Modulentität

Anstatt die Konstanten im obersten Modul fest zu codieren, deklariere ich sie als Generika auf der Entität der obersten Ebene. Dann vergebe ich Standardwerte, die für den iCEstick geeignet sind. Ein Vorteil dieses Ansatzes besteht darin, dass Sie diese Werte in der Testbench überschreiben können, um die Simulation zu beschleunigen. Ich weise den Generika nichts zu, wenn ich das Design synthetisiere. Somit landen die korrekten Standardwerte im gerouteten Design.

Wir werden pwm_bits weitergeben und clk_cnt_len zu den gleichnamigen Generika auf der PWM-Modul-Entität. Die Taktfrequenz des iCEstick-Oszillators beträgt 12 MHz. Mithilfe der zuvor vorgestellten Formel können wir diese Werte einsetzen, um die PWM-Frequenz zu berechnen:\frac{12e6}{(2^8 - 1) * 47} \approx 1 \mathit{kHz}

entity pwm_led is
  generic (
    pwm_bits : integer := 8;
    cnt_bits : integer := 25;
    clk_cnt_len : positive := 47
  );
  port (
    clk : in std_logic;
    rst_n : in std_logic; -- Pullup

    led_1 : out std_logic;
    led_2 : out std_logic;
    led_3 : out std_logic;
    led_4 : out std_logic;
    led_5 : out std_logic
  );
end pwm_led;

Sie haben vielleicht bemerkt, dass es eine dritte Konstante gibt, cnt_bits , in der Generics-Deklaration im obigen Code. Es steuert die Länge eines selbstwickelnden Sägezahnzählers. Wir werden diesen zusätzlichen Zähler verwenden, um ein allmähliches Aufleuchten der Einschalt-LED zu erzeugen, damit wir das PWM-Modul in Echtzeit beobachten können.

Wir werden die hohen Bits dieses neuen Zählers mit dem Tastverhältniseingang des PWM-Moduls verbinden. Da dieser Zähler Taktzyklen zählt, werden die cnt_bits Generic bestimmt die Pulsfrequenz der Power-On-LED. Die Formel, die eine Funktion der Taktfrequenz und der Zählerlänge ist, ist unten gezeigt.

\frac{2^{\mathit{cnt\_bits}}}{\mathit{clk\_hz}} =\frac{2^{25}}{12e6} \approx 2,8 \mathit{Hz}

In der Portdeklaration habe ich den Reset-Eingang mit _n nachgestellt , was anzeigt, dass der externe Reset eine negative Polarität hat. Wir werden das Lattice FPGA so konfigurieren, dass es einen internen Pull-Up-Widerstand an diesem Pin verwendet.

Schließlich können Sie sehen, dass ich alle auf dem iCEstick vorhandenen LEDs in der Portdeklaration aufgelistet habe. Wir werden nur LED Nummer 5 verwenden, aber wir müssen die anderen LEDs aktiv ansteuern. Wenn sie nicht angeschlossen sind, leuchten sie in einem schwachen Rot.

Wenn Sie sich den VHDL-Code und die Einschränkungsdateien genauer ansehen möchten, geben Sie Ihre E-Mail-Adresse in das unten stehende Formular ein. Sie erhalten eine Zip-Datei mit dem vollständigen Code mit ModelSim- und Lattice iCEcube2-Projekten.

Interne Signale des oberen Moduls

Ich halte meine Top-Module gerne frei von RTL-Logik. Es ist ein Konzept, das als Strukturmodul bezeichnet wird . Meiner Erfahrung nach ist es einfacher, ein strukturiertes VHDL-Projekt zu verwalten, wenn Sie die RTL-Logik trennen und verbinden. Der folgende Code zeigt die Signaldeklarationen im obersten Modul und die gleichzeitigen Signalzuweisungen.

architecture str of pwm_led is

  signal rst : std_logic;
  signal cnt : unsigned(cnt_bits - 1 downto 0);
  signal pwm_out : std_logic;

  alias duty_cycle is cnt(cnt'high downto cnt'length - pwm_bits);

begin

  led_1 <= '0';
  led_2 <= '0';
  led_3 <= '0';
  led_4 <= '0';

  led_5 <= pwm_out;

Zuerst deklarieren wir ein Reset-Signal, das unsere nicht-invertierte, synchrone Version des externen Resets sein wird.

Das zweite deklarierte Signal mit dem Namen cnt , ist der unendlich umlaufende Taktzykluszähler. Es ist ein unsignierter Typ, der den Status unserer LED-Intensitäts-Sägezahnwelle zu jedem beliebigen Zeitpunkt enthält.

Als nächstes kommt pwm_out Signal. Wir hätten den pwm_out anschließen können Signal vom PWM-Modul direkt an die led_5 Ausgabe, aber ich wollte pwm_out beobachten im Simulator. Das Synthesetool findet heraus, dass die beiden Signale zum selben Netz gehören. Es kostet keine zusätzlichen Ressourcen.

Abschließend kommt die Deklaration des duty_cycle Vektor – dieses Mal habe ich den Alias verwendet Schlüsselwort, anstatt ein neues Signal zu erstellen. VHDL-Aliase funktionieren ähnlich wie Makros in C. Wenn wir den duty_cycle verwenden Name von nun an ersetzt der Compiler die hohen Bits von cnt Vektor.

Nach dem Beginn Schlüsselwort weisen wir das pwm_out zu Signal an led_5 Ausgang. Alle anderen LEDs sind fest auf „0“ verdrahtet, um zu verhindern, dass sie rotes Licht leuchten.

Instanziierungen

Bevor wir externe Signale innerhalb des FPGA verwenden, müssen wir sie immer mit der internen Systemuhr synchronisieren. Andernfalls können Metastabilitätsprobleme auftreten, Probleme, die schwer zu debuggen sind.

RESET : entity work.reset(rtl)
  port map (
    clk => clk,
    rst_n => rst_n,
    rst => rst
  );

Der externe Reset ist keine Ausnahme, aber da ich keine RTL-Logik im Strukturmodul der obersten Ebene zulasse, implementieren wir den Reset-Synchronizer als eigenständiges Modul.

Die nächste Instanziierung ist das PWM-Modul, wie im folgenden Codeausschnitt gezeigt. Bei der Instanziierung des PWM-Moduls verwenden wir den duty_cycle Alias ​​für die Zuweisung der höchstwertigen Bits des cnt Vektor zum duty_cycle Eingang. Dadurch wird die Helligkeit der LED intensiviert, bis der Zähler seinen Maximalwert erreicht. Wenn cnt springt auf Null zurück, die LED erlischt kurz und der Zyklus wiederholt sich.

PWM : entity work.pwm(rtl)
  generic map (
    pwm_bits => pwm_bits,
    clk_cnt_len => clk_cnt_len
  )
  port map (
    clk => clk,
    rst => rst,
    duty_cycle => duty_cycle,
    pwm_out => pwm_out
  );

Die dritte und letzte Instanziierung im oberen Modul ist der Taktzykluszähler, wie unten gezeigt. Um dieses Modul generischer zu machen, habe ich ein count_enable eingefügt Signal. Aber in diesem Design setzen wir es auf eine konstante „1“, weil wir jeden Taktzyklus zählen möchten.

COUNTER : entity work.counter(rtl)
  generic map (
    counter_bits => cnt'length
  )
  port map (
    clk => clk,
    rst => rst,
    count_enable => '1',
    counter => cnt
  );

Hinterlassen Sie Ihre E-Mail-Adresse im untenstehenden Formular, wenn Sie den vollständigen VHDL-Code für dieses Projekt benötigen.

Simulation des PWM-LED-Pulsierens

Ein wesentlicher Vorteil der Anpassung der Zählerlängen durch Generika besteht darin, dass Sie die Simulation beschleunigen können. Meistens sind wir daran interessiert, die Übergänge und Ereignisse in unserer Logik zu testen. Wir sind nicht so scharf darauf, durch einen ultralangen Zähler zu laufen, während nichts anderes im Design passiert.

Mit Generika können wir diese Dinge nicht-invasiv von der Prüfbank aus ändern. Der folgende Code zeigt die Werte, die ich der generischen Karte beim Instanziieren des PWM-Moduls in der Testbench zugewiesen habe.

DUT : entity work.pwm_led(str)
  generic map (
    pwm_bits => 8,
    cnt_bits => 16,
    clk_cnt_len => 1
  )

Wenn wir die Verwendung dieser Konstanten in ModelSim simulieren, reicht es aus, 1400 Mikrosekunden bei 100 MHz zu laufen, um zwei vollständige PWM-Zyklen anzuzeigen. Hätten wir die realen Werte verwendet, müssten wir knapp 6 Sekunden simulieren. Das sind 32 Millionen Taktzyklen von fast nichts als Zählen. In ModelSim würde es ewig dauern.

Das Bild unten zeigt die Wellenform der PWM-Simulation in ModelSim. Ich habe das Format des duty_cycle geändert Signal vom Standardnummerntyp in eine analoge Wellendarstellung umwandeln. Sie können dies in ModelSim tun, indem Sie mit der rechten Maustaste auf das Signal in der Wellenform klicken und Format->Analog (custom)… auswählen , und stellen Sie die Pixelhöhe und den Datenbereich so ein, dass sie mit den Mindest- und Höchstwerten Ihres Signals übereinstimmen.

In der Wellenform können wir sehen, warum es ein Sägezahnsignal genannt wird. Der freilaufende Wickelzähler gleicht den Zähnen eines Sägeblattes.

Beachten Sie, wie die Dauer der hohen Perioden des PWM-Ausgangs (led_5 ) nimmt zu, wenn das Tastverhältnis wächst. Wir können auch diese led_5 sehen ist an der Spitze des Sägezahns ganz kurz eine durchgehende „1“. Das ist, wenn der Arbeitszyklus 255 ist, der maximale Wert.

Wenn wir die zusätzliche if-Anweisung im PWM-Modul nicht hinzugefügt haben, diejenige, die pwm_cnt umschließt bei seinem zweithöchsten Wert auf Null zurückfallen, würden wir das nicht sehen. Wir würden niemals die maximale Leistung erreichen können. Dies ist ein häufiger Fehler bei der Implementierung von PWM-Generatoren. Ich habe es auch ein- oder zweimal gemacht.

Die FPGA-Implementierung

Das Design habe ich auf dem Lattice iCEstick mit iCEcube2, der Designsoftware von Lattice, umgesetzt. Die folgende Auflistung zeigt die nach Ort und Route gemeldete Ressourcennutzung. Auch wenn das iCE40-FPGA winzig ist, verwenden das PWM und die unterstützenden Module nur 5 % der verfügbaren LUTs.

Resource Usage Report for pwm_led 

Mapping to part: ice40hx1ktq144
Cell usage:
GND             3 uses
SB_CARRY        31 uses
SB_DFF          5 uses
SB_DFFSR        39 uses
SB_GB           1 use
VCC             3 uses
SB_LUT4         64 uses

I/O ports: 7
I/O primitives: 7
SB_GB_IO       1 use
SB_IO          6 uses

I/O Register bits:                  0
Register bits not including I/Os:   44 (3%)
Total load per clock:
   pwm_led|clk: 1

@S |Mapping Summary:
Total  LUTs: 64 (5%)

Nachdem ich den Programmier-Bitstream in iCEcube2 generiert hatte, habe ich den eigenständigen Lattice Diamond-Programmierer verwendet, um das FPGA über USB zu konfigurieren.

Die GIF-Animation unten zeigt, wie das Sägezahnwellen-Tastverhältnissignal die Einschalt-LED auf dem iCEstick verhält. Sie leuchtet mit zunehmender Intensität bis zum cnt Zähler wickelt. Dann wird das Tastverhältnis zu Nullen und die LED erlischt kurz. Danach wiederholt sich der Zyklus endlos.

Der iCEstick ist ein kostengünstiges und vielseitiges FPGA-Entwicklungsboard. Es ist gut für Anfänger, aber auch für fortgeschrittene Embedded-Projekte geeignet. Darüber hinaus ist die Lattice-Software unkompliziert und einfach zu bedienen. Deshalb setze ich den iCEstick sowohl in meinem VHDL-Einsteigerkurs als auch im Aufbaukurs FPGA ein.

Wenn Sie bereits einen iCEstick besitzen, können Sie das untenstehende Formular verwenden, um das iCEcube2-Projekt herunterzuladen.

Sinuswellen-Arbeitszyklus für LED-Atmungseffekt

Jetzt wissen Sie, wie Sie die Beleuchtung einer LED mit PWM steuern können.

Die in einem Sägezahnwellenmuster pulsierende LED ist wohl cooler als eine einfache AN/AUS-Blinkanwendung. Das ist eine typische erste Aufgabe für VHDL-Studenten, und ich bin sicher, dass Sie schon einmal eine LED zum Leuchten gebracht haben.

Das LED-Blinken wird jedoch noch beeindruckender, wenn Sie eine Sinuswelle zur Steuerung des Arbeitszyklus verwenden. Die GIF-Animation unten zeigt unser PWM-Modul, das die LED mit einer sinusförmigen Intensitätsvariation über die Zeit pulsiert.

Ich bin mir sicher, dass Sie diese Art von „Atmungseffekt“ bei LEDs schon einmal gesehen haben. So verhält sich die Benachrichtigungs-LED auf meinem Handy, und ich finde, es sieht natürlich aus, weil es keine abrupten Änderungen der Lichtintensität gibt.

In meinem nächsten Blogbeitrag zeige ich Ihnen, wie Sie einen Sinusgenerator erstellen, indem Sie Block-RAM in FPGAs verwenden. Und wir werden die pwm_led modifizieren Modul, um die LED auf dem iCEstick mit sinusförmiger Intensität zu pulsieren.

Klicken Sie hier, um zum nächsten Blogbeitrag zu gelangen:
Wie man einen atmenden LED-Effekt mit einer im Block-RAM gespeicherten Sinuswelle erzeugt

Siehe auch:
RC-Servocontroller mit PWM von einem FPGA-Pin


VHDL

  1. PWM Power Controller
  2. So erstellen Sie eine Liste von Zeichenfolgen in VHDL
  3. So erstellen Sie eine Tcl-gesteuerte Testbench für ein VHDL-Code-Sperrmodul
  4. So stoppen Sie die Simulation in einer VHDL-Testbench
  5. So generieren Sie Zufallszahlen in VHDL
  6. So erstellen Sie einen Ringpuffer-FIFO in VHDL
  7. So erstellen Sie eine selbstüberprüfende Testbench
  8. So erstellen Sie eine verknüpfte Liste in VHDL
  9. So verwenden Sie eine Prozedur in einem Prozess in VHDL
  10. Wie lade ich einen Kondensator auf?