www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Abtastung PWM Signal mit VHDL


Autor: ronny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo...
Habe eine Frage zur Weiterverarbeitung eines PWM-Signals.
Habe einen Sensor der ein PWM Signal ausgibt. Dieses möchte ich mit 
einer bestimmten Frequenz abtasten, um somit einen Wert zuerhalten den 
ich weiterverarbeiten kann. Derzeit habe ich ein PWM-Signal mit einer 
Pulsbreite von 1ms und einer Periodendauer von 20ms.
Ich habe mir gedacht ich lasse einen Zähler mit einer Frequenz von 1MHz 
hochzählen solange der Puls anliegt. Und kann somit weiterarbeiten. 
Allerdings habe ich noch keine Möglichkeit gefunden wie ich den Wert 
speichern kann, da ja vom Sensor gleich wieder eine Veränderung 
übermittelt werden kann.

Vielleicht kann mir jemand einen guten ratschlag geben.

Hänge meine Idee einfach mal mit dazu.

Gruß Ronny

-- STANDARD LIBRARIES --
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;

-- BEGIN OF ENTITY --
ENTITY Sensor_REG IS
  -- GLOBAL VARIABLE MAX-COUNT (Periodendauer 20 ms) --
  PORT (
  -- GLOBAL CLOCK OF MAX II ALTERA --
    glb_clk:  IN BIT;
  -- CLOCK FOR DISTANCE MEASUREMENT 1 MHz --
    en:      IN STD_LOGIC;
  -- GLOBAL RESET USER PUSH BUTTON S1 --
    nReset:   IN BIT;
  -- RESULT works --
  --readyREG:   IN BIT;
  -- PULS WIDE --
    data_in:  IN BIT;
  -- DATA OUT --
    wide_out:  OUT INTEGER range 0 to 2**12-1
    );
END Sensor_REG;
-- END OF ENTITY --

-- BEGIN OF ARCHITECTURE --
ARCHITECTURE Result OF Sensor_REG IS
TYPE STATE_TYPE IS (POWER_ON_DELAY, INITIALIZE);
SIGNAL state: STATE_TYPE;
BEGIN

PROCESS (glb_clk, nReset, en, data_in)
  variable count: integer range 0 to 2**12-1:= 0;
  BEGIN
    IF (nReset = '0') THEN
    count    := 0;
    state    <= POWER_ON_DELAY;
  -- GENERATING NEW CLOCK --
    ELSIF (glb_clk'EVENT AND glb_clk='1') THEN
  -- START OF INITIALIZATION --
    IF en = '1' THEN
    CASE state IS
        -- BEGINNING OF INITIALIZATION --
  WHEN POWER_ON_DELAY=>
     IF data_in = '1' THEN
        count := count + 1;
     ELSE
        wide_out <= save;
        state<=INITIALIZE;
     END IF;
  WHEN INITIALIZE=>
        wide_out <= count;
        count := 0;
        state <= POWER_ON_DELAY;
                          END case;
      ELSE
       count := count;
    END IF;
  END IF;
  END PROCESS;
END Result;
-- END OF ARCHITECTURE --

Autor: Tim R. (vref)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, prinzipiell würde ich dein PWM Signal als Trigger nehmen und deine 
Speicheroperation darauf synchronisieren.
Bei positiver PWM Flanke resettest du deinen 1 MHz Zähler, bei negativer 
Flange nimmst du den aktuellen Zählerwert und machst deine 
Speicheroperation (wohin auch immer...)
So hast du immer die aktuelle Pulsbreite verarbeitet.

Autor: Tim R. (vref)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ich vhdl nicht mag, weil ich es nicht lesen kann, hier mein Ansatz in 
verilog:

input         clk_1mhz;
input         pwm_in;
output [13:0] data_out;


reg [13:0] data_out_reg;
reg [13:0] counter;
reg        pwm_in_buf;

always @ (negedge clk_1mhz)
begin
  pwm_in_buf <= pwm_in;
end

always @ (posedge clk_1mhz)
begin
  // reset counter at pwm_in negedge else increment
  counter <= (pwm_in & ~pwm_in_buf) ? 0 : counter + 1;
end

always @ (negedge pwm_in)
begin
  data_out_reg <= counter;
end

assign data_out = data_out_reg;




Wenn deine Pulsbreite doch mal breiter sein sollte als 1ms, muss dein 
Zähler übrigens 14 Bit breit werden, da 1 MHz / 50 einen Maximalwert von 
20000 ergibt, und das passt in 12 Bit ja nicht rein.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu deinem Code::
Statt  PROCESS (glb_clk, nReset, en, data_in)
reicht PROCESS (glb_clk, nReset)


Ich würde es so machen:

PROCESS (glb_clk)
variable datainlast: bit;   -- fuer Flankenauswertung
variable count2: integer range 0 to 2**12-1:= 0;
BEGIN
    IF rising_edge(glb_clk) THEN
       IF (nReset = '0') THEN          -- synchroner Reset (wenn schon)
          count    := 0;
       ELSIF (en = '1') THEN
          datainlast <= data_in;
          IF data_in = '1' THEN        -- zaehlen solange High
             count1 := count1 + 1;
          ELSIF datainlast = '1' THEN  -- fallende Flanke
             wide_out <= count1;
          END IF;
       END IF;
    END IF;
END PROCESS;


@Tim R.
>always @ (negedge pwm_in)
ist eine zweite Taktdomäne.
Macht bei FPGAs fast ausschliesslich Probleme.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Zurücksetzen vom Counter hat noch gefehlt.
Und dann ersetzen wir sämtliche count1 und count2 durch count,
dann gehts ;-)

:
          ELSIF datainlast = '1' THEN  -- fallende Flanke
             wide_out <= count;
             count <= 0;              -- zurücksetzen
          END IF;
:

Autor: Tim R. (vref)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>always @ (negedge pwm_in)
>>ist eine zweite Taktdomäne.
>Macht bei FPGAs fast ausschliesslich Probleme.

stimmt. kein guter ansatz.

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Macht bei FPGAs fast ausschliesslich Probleme.
>stimmt. kein guter ansatz.

Bei der Beachtung rudimentärer Designrichtlinien macht das gar keine 
Probleme.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Bei der Beachtung rudimentärer Designrichtlinien
>macht das gar keine Probleme.

pwm_in ist asynchron zu glb_clk.
So definiere ich ein Problem.

Wenn für dich "rudimentäre Designrichtlinien" so definiert sind, dass 
pwm_in vorher auf glb_clk synchronisiert wurde, dann gebe ich dir Recht.

Autor: Harald (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
-es ist doch egak, wie Du es machts: Am Ende wird Deine PWM mit der 
Taxtfrequenz des FPGA quantisiert.

Autor: Tim R. (vref)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Harald:
Ne, Lothar hat da schon ganz recht.
Es ist nicht sichergestellt, dass pwm_in nicht gleichzeitig mit einem 
counter increment eine negative flanke hat, und in dem Fall ist unklar, 
in welchem Zustand der counter ist.
= Problem.
Man kann das natürlich lösen, aber da ja bereits eine funktionierende 
VHDL Lösung da steht, verzichte ich darauf.

Autor: Ronny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey  Lothar Miller (lkmiller)...

Habe deinen Code probiert, und der funktioniert sehr gut. Danke nochmal. 
Hat mir sehr weiter geholfen. HAbe dabei auch meinen eigenen Fehler 
erkannt. So hatte ich es mir gedacht. In der Simulation zählt der 
wunderbar hoch und ich könnte mit dem Zählerstand weiter arbeiten. 
Allerdings wenn ich mein weiteres Programm, zum Beispiel die LCD anzeige 
mit einbinde, kann ich die Ausgabedaten nicht nutzen (wide_out). Kann 
das sein das diese Daten nicht lange genug anliegen, zur Verfügung 
stehen, und ich diese vielleicht nochmal speichern muss. Ciao

Autor: Ronny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey  Lothar Miller (lkmiller)...

Ich habe da nochmal eine Frage zu deinem Syntax.
Du nutzt ja "datainlast", wo du nochmal eine Flanke abfragst, mit 
welchem Hintergrund benötige ich die genau. Ciao

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ronny wrote:
> Habe deinen Code probiert, und der funktioniert sehr gut.
Das wundert mich fast etwas...
Der ist ja ko***bel...
Wieso hatte ich bei meinem ersten Post eigentlich variable drin?
Das müssen signale sein, ich hasse variable...
Da kam sicher vom copy&paste :-(
Und den reset habe ich jetzt auch pensioniert, das geht auch ohne.
Jetzt gefällt mir der code besser....
:
signal dsr: std_logic_vector(3 downto 9);   -- fuer Flankenauswertung
signal count: integer range 0 to 2**12-1:= 0;
:
PROCESS (glb_clk)
BEGIN
    IF rising_edge(glb_clk) THEN
       IF (en = '1') THEN              -- 1MHz
          dsr <= dsr(2 downto 0) & data_in;  -- Schieberegister
          IF (data_in='1') THEN        -- zaehlen solange High
             count <= count + 1;
          END IF;
          IF (dsr="1100") THEN         -- fallende Flanke
             wide_out <= count;        -- Ausgabewert aktualisieren
             count <= 0;               -- und Zähler löschen
          END IF;
       END IF;
    END IF;
END PROCESS;
:

> Ich habe da nochmal eine Frage zu deinem Syntax.
> Du nutzt ja "datainlast", wo du nochmal eine Flanke abfragst, mit
> welchem Hintergrund benötige ich die genau. Ciao
Die Idee ist, nur bei der fallenden Flanke den Ausgabewert 
abzuspeichern.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>um Beispiel die LCD anzeige mit einbinde,
>kann ich die Ausgabedaten nicht nutzen (wide_out).
>Kann das sein das diese Daten nicht lange genug anliegen,
>und ich diese vielleicht nochmal speichern muss.
Klar: das Display weiß nichts von der PWM und andersrum genauso. Die 
beiden laufen einfach nur irgendwie vor sich hin.
Deshalb musst du die Daten für die Ausgabe noch einmal 
zwischenspeichern, oder das Abspeichern nach wide_out anderweitig mit 
der Ausgabe synchronisieren.

Autor: Ronny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi.....

Bei dieser Zeile: "dsr <= dsr(2 downto 0) & data_in;" kommt folgende 
Meldung:
Error (10327): VHDL error at Sensor_Reg.vhd(82): can't determine 
definition of operator ""&"" -- found 0 possible definitions

Kann das daran liegen das da versucht wird einen Std_Logic_Vector mit 
einer Bit Variable zu verknüpfen?

Wenn ich das & durch ein AND ersetze. Dabei bin total überfordert :)
Error (10476): VHDL error at Sensor_Reg.vhd(82): type of identifier 
"data_in" does not agree with its usage as std_logic_vector type


Wenn ich die & Operation herausnehme, kann ich compilieren allerdings 
bekomme ich noch ein Warning:
Bei dieser Zeile " IF (dsr="1100") THEN " kommt diese Meldung:
Warning (10620): VHDL warning at Sensor_Reg.vhd(86): comparison between 
unequal length operands always returns FALSE

Total unverständlich. Vielleicht sagt es dir etwas.

Ciao

Autor: Joko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi..

  "&" ist eine "Anhängung", keine "Verundung".
  Lösung: erst data_in nach std_logic konvertieren:

   "lesenswert":
       http://dz.ee.ethz.ch/support/ic/hdl/vhdlsources.en.html


Gruß
Joko

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Kann das daran liegen das da versucht wird einen Std_Logic_Vector mit
>einer Bit Variable zu verknüpfen?
Ja, du mußt data_in noch konvertieren/casten.
>Lösung: erst data_in nach std_logic konvertieren:
Oder noch besser:
verwende nur std_logic(_vector) und integer, und das Leben wird einfach.
Gut, das wird nicht immer klappen, aber den Versuch ist es wert...

Der &-Operator ist (wie von Joko schon gesagt) eine Concatenation, keine 
logische Operation.

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wenn ich die & Operation herausnehme, kann ich compilieren allerdings
>bekomme ich noch ein Warning:
>Bei dieser Zeile " IF (dsr="1100") THEN " kommt diese Meldung:
>Warning (10620): VHDL warning at Sensor_Reg.vhd(86): comparison between
>unequal length operands always returns FALSE

Im Code von Lothar hat sich ein kleiner Tippfehler eingeschlichen

>signal dsr: std_logic_vector(3 downto 9);

müsste heissen: signal dsr: std_logic_vector(3 downto 0);

dann müsste die Warnung verschwinden

Gruß Chris

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.