www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Uart in Vhdl -- Anfänger


Autor: kalle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

ich versuche seit zwei Tagen in VHDL eine UART zu entwickeln
( nur Daten empfangen ). Bin ein Anfänger in sachen FPGA und VHDL.
Ich habe nun den untenstehenden Code geschrieben und in Modelsim
getestet wo er wunderbar funktioniert. Aber im FPGA (Xilinx Spartan3 
@50Mhz)
läuft nichts. Die Zeichen vom PC (Terminal) kommen an. Wenn ich die
RX Leitung und TX Leitung im FPGA verbinde habe ich ein Echo. Daran
liegts nicht.

Ich hoffe der Code ist verständlich. Vielleicht etwas wirr. Die Zähler 
die
ich benutze um die Baudrate (Takt) zu erzeugen und um die empfangende
Bits zu zählen werden je über ein DFF synchron resettet. Deswegen
einmal rising_edge und einmal falling_edge.

Was mache ich Falsch. In der Sim. funktionierts.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity UART_RXCON is
    Port ( rx_line : in  STD_LOGIC;
           clk : in  STD_LOGIC;
           run : out  STD_LOGIC;
        Data : out STD_LOGIC_VECTOR (9 downto 0));
end UART_RXCON;

architecture Behavioral of UART_RXCON is
    signal start : STD_LOGIC := '0';
    signal RX_reg : STD_LOGIC_VECTOR (9 downto 0) := "0000000000";
    
    signal bit_syncclr : STD_LOGIC := '0';
    signal bit_count : integer range 0 to 15 := 0;
    
    signal uclk_count : integer range 0 to 511 := 0;
    signal uclk_syncclr : STD_LOGIC := '0';
begin
  process (clk)
  begin
    if falling_edge(clk) then
      -- start FF --
      start <= ((not start) and (not rx_line)) or ((not  bit_syncclr) and start);
      ----------------
      -- bit_counter -
      if bit_syncclr = '0' then
        if uclk_count = 217 then
          bit_count <= bit_count + 1;
        end if;
      else
        bit_count <= 0;
      end if;
      ----------------
      -- uclk_syncclr ----
      if uclk_count = 434 then --434
        uclk_syncclr <= '1';
      else
        uclk_syncclr <= '0';
      end if;
      --------------------
      -- RX_reg ----------
      if uclk_count = 217 then
        RX_reg(9 downto 1) <= RX_reg(8 downto 0);
        RX_reg(0) <= rx_line;
      end if;
      --------------------
    end if;
    if rising_edge(clk) then
      -- bit_syncclr FF --
      if bit_count = 10 then
        bit_syncclr <= '1';
      else
        bit_syncclr <= '0';
      end if;
      --------------------
      -- uclk_counter ----
      if uclk_syncclr = '1' or start = '0' then
        uclk_count <= 0;
      else
        uclk_count <= uclk_count + 1;
      end if;
      --------------------  
    end if;
  end process;

  Data <= RX_reg;
  run <= start;
  
end Behavioral;

mfg

Autor: Iulius (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> die Zähler die
>> ich benutze um die Baudrate (Takt) zu erzeugen und um die empfangende
>> Bits zu zählen werden je über ein DFF synchron resettet. Deswegen
>> einmal rising_edge und einmal falling_edge.

völlig egal wie du das begründest, 2 Flanken sind hierfür komplett 
überflüssig.

Versuch dir stattdessen gleich mal anzueignen das vernünftig zu 
beschreiben.

Du brauchst im prinzip nicht mehr als einen buadratenzähler der als 
enable fungiert und ein schieberegister mit positionszähler der beim 
überlauf den baudratenzähler resettet(übrigens auf die mitte das bits 
und nicht auf 0)

Spar dir die zusätzlichen signale, denn sie führen zu nichts und machen 
das alles nur unnötig umständlich und unübersichtlich.


Ansonsten kann man dir leider nicht helfen.

Was funktioniert denn nicht ?

Kommen die bits verkehrt rein ?
reagiert run nicht ?

wie prüfst du das überhaupt ?

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

Bewertung
0 lesenswert
nicht lesenswert
Deine Verknoterei vom Bit-Scheiben und Bitdauer-Zählen ist extrem 
ungünstig. Du hast doch Glück: du bist nicht der erste, der sowas machen 
soll. Sieh dir doch mal an, wie das z.B. in uC realisiert ist.

Und heraus kommt dann z.B. sowas:
http://www.lothar-miller.de/s9y/categories/42-RS232
oder sowas:
http://www.lothar-miller.de/s9y/categories/49-RS232-IO

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: kalle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So danke erstmal für die Antwort.

Das Problem ist das das Signale "start" nicht wieder auf null gesetzt
wird. Gut ok ich muss das nochmal überdenken. Ich finde die 
Programmierung
auch etwas konfus.

Mein Problem ist, dass ich nicht genau weiß wie so ein Reset deines
Zahlers funktioniert.
Im Klartext:
Der Zähler nimmt den Wert z.B. 100 an. Bei 100 will ich ihn Resetten 
(auf null). Das der Zähler == 100 ist wird durch eine Logikschaltung 
realisiert,
naja wie auch sonst. Ok nun wird der Zähler auf Null gesetzt. Was aber 
auch bedeutet das die Vergleichsschaltung keine 1 ( Zahler == 100) am 
Ausgang erzeugt. Es kann ja nun passieren das nicht der gesamte Zähler 
(alle DFF)
auf Null gehen sonder nur einige. Zahler == 100 währe dann nicht mehr 
erfüllt. Deswegen habe ich diese zwei Flanken + FF benutzt um dieses 
Problem zu umgehen.
Nun die Frage: Wie gehts besser?

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

Bewertung
0 lesenswert
nicht lesenswert
> Deswegen habe ich diese zwei Flanken + FF benutzt um dieses
> Problem zu umgehen.
> Nun die Frage: Wie gehts besser?
Das Problem besteht nur in deinem Kopf. Beim Zählerstand 99 wird z.B. 
mit steigender Taktflanke auf den Wert 100 hochgezählt. Jetzt kommt die 
Kombinatorik (Vergleicher), der auf Zähler == 100 vergleicht und 
feststellt, dass der Endwert erreicht ist. Deshalb legt er jetzt den 
neuen Zählerwert 0 an die Zählereingänge an, der dann mit der nächsten 
steigenden Taktflanke übernommen wird.

Mein Postulat:
In einem idealen FPGA-Design gibt es genau 1 Takt, der auf 1 Flanke 
senitiv ist. Und dazu 0 Reset-Signale.

Autor: kalle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So habe jetzt einfach mal alles wie in C gemacht
und mich an dem Inhalt der Seite orientiert:
http://www.lothar-miller.de/s9y/categories/49-RS232-IO

Es läuft ;)

@Lothar :
Vielleicht sollte man ergänzent noch sagen, dass
der Zählerstand null (auf/nach) der fallenden
Flanke übernommen wird und bei steigender Flanke
am Ausgang anliegt ( 2 x D Latch ).
Wobei auch hier noch Timingprobleme(meiner Meinung) auftreten können.
Aber gut ich will jetzt keine große Diskusion lostreten.

Hier der Code:
entity UART_RXCON is
    Port ( rx_line : in  STD_LOGIC;
           clk : in  STD_LOGIC;
           run : out  STD_LOGIC;
        Data : out STD_LOGIC_VECTOR (9 downto 0));
end UART_RXCON;

architecture Behavioral of UART_RXCON is
    signal start : STD_LOGIC := '0';
    signal RX_reg : STD_LOGIC_VECTOR (9 downto 0) := "0000000000";
    
    signal bit_count : integer range 0 to 15 := 0;
    
    signal bittakt : integer range 0 to 511 := 294;
    
begin
  process (clk)
  begin
    if rising_edge(clk) then
      -- start FF --
      start <= ((not start) and (not rx_line)) or start;
      --------------
      if start = '1' then 
        if bittakt = 0 then
          bittakt <= 77;
          
          RX_reg(9 downto 1) <= RX_reg(8 downto 0);
          RX_reg(0) <= rx_line;
          
          bit_count <= bit_count + 1;
          if bit_count = 9 then
            start <= '0';
            bit_count <= 0;
            bittakt <= 294;
          end if;
        else
          bittakt <= bittakt + 1;
        end if;
      end if;
    end if;
  end process;

  Data <= RX_reg;
  run <= start;
  
end Behavioral;

Was mich etwas verwundert ist das ich "if bit_count = 9" anstatt 10
schreiben muss (Empfange sonst 11 Bits). Naja werd ich schon rausfinden.
Danke für die hilfe.

mfg

Autor: D. I. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weil 0-9 Zehn Schritte sind

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

Bewertung
0 lesenswert
nicht lesenswert
> Es läuft ;)
Schön.

> dass der Zählerstand null (auf/nach) der fallenden Flanke übernommen wird
Er wird eigentlich nicht auf, bei oder nach der Flanke übernommen, 
sondern wegen der Flanke. Und ein FPGA ist so gebaut, dass der gesamte 
Baustein (solange die Timingbedingungen eingehalten werden) genau mit 
der Flanke den Zustand am Eingang der D-FFs (das sind keine Latches) auf 
den Ausgang durchdschaltet.

> Aber gut ich will jetzt keine große Diskusion lostreten.
Das wirst du auch nicht schaffen   ;-)
Wie gesagt: du selbst mußt noch dahinterkommen wie das mit dem Takt 
jetzt in der Realität funktioniert. Das FPGA kann das schon.

>> das ich "if bit_count = 9" anstatt 10 schreiben muss
> Weil 0-9 Zehn Schritte sind
Das sollte dir übrigens bei allen Zählern bewusst sein: 0 ist auch ein 
Zählschritt. Ein Zähler, der z.B. auf 3 zählt, braucht 4 Takte: 
0,1,2,3,0,1,2,3,0,1,2,3...

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.