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


von kalle (Gast)


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.
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.STD_LOGIC_ARITH.ALL;
4
use IEEE.STD_LOGIC_UNSIGNED.ALL;
5
6
entity UART_RXCON is
7
    Port ( rx_line : in  STD_LOGIC;
8
           clk : in  STD_LOGIC;
9
           run : out  STD_LOGIC;
10
        Data : out STD_LOGIC_VECTOR (9 downto 0));
11
end UART_RXCON;
12
13
architecture Behavioral of UART_RXCON is
14
    signal start : STD_LOGIC := '0';
15
    signal RX_reg : STD_LOGIC_VECTOR (9 downto 0) := "0000000000";
16
    
17
    signal bit_syncclr : STD_LOGIC := '0';
18
    signal bit_count : integer range 0 to 15 := 0;
19
    
20
    signal uclk_count : integer range 0 to 511 := 0;
21
    signal uclk_syncclr : STD_LOGIC := '0';
22
begin
23
  process (clk)
24
  begin
25
    if falling_edge(clk) then
26
      -- start FF --
27
      start <= ((not start) and (not rx_line)) or ((not  bit_syncclr) and start);
28
      ----------------
29
      -- bit_counter -
30
      if bit_syncclr = '0' then
31
        if uclk_count = 217 then
32
          bit_count <= bit_count + 1;
33
        end if;
34
      else
35
        bit_count <= 0;
36
      end if;
37
      ----------------
38
      -- uclk_syncclr ----
39
      if uclk_count = 434 then --434
40
        uclk_syncclr <= '1';
41
      else
42
        uclk_syncclr <= '0';
43
      end if;
44
      --------------------
45
      -- RX_reg ----------
46
      if uclk_count = 217 then
47
        RX_reg(9 downto 1) <= RX_reg(8 downto 0);
48
        RX_reg(0) <= rx_line;
49
      end if;
50
      --------------------
51
    end if;
52
    if rising_edge(clk) then
53
      -- bit_syncclr FF --
54
      if bit_count = 10 then
55
        bit_syncclr <= '1';
56
      else
57
        bit_syncclr <= '0';
58
      end if;
59
      --------------------
60
      -- uclk_counter ----
61
      if uclk_syncclr = '1' or start = '0' then
62
        uclk_count <= 0;
63
      else
64
        uclk_count <= uclk_count + 1;
65
      end if;
66
      --------------------  
67
    end if;
68
  end process;
69
70
  Data <= RX_reg;
71
  run <= start;
72
  
73
end Behavioral;

mfg

von Iulius (Gast)


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 ?

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


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

von Alex (Gast)


Lesenswert?


von kalle (Gast)


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?

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


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.

von kalle (Gast)


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:
1
entity UART_RXCON is
2
    Port ( rx_line : in  STD_LOGIC;
3
           clk : in  STD_LOGIC;
4
           run : out  STD_LOGIC;
5
        Data : out STD_LOGIC_VECTOR (9 downto 0));
6
end UART_RXCON;
7
8
architecture Behavioral of UART_RXCON is
9
    signal start : STD_LOGIC := '0';
10
    signal RX_reg : STD_LOGIC_VECTOR (9 downto 0) := "0000000000";
11
    
12
    signal bit_count : integer range 0 to 15 := 0;
13
    
14
    signal bittakt : integer range 0 to 511 := 294;
15
    
16
begin
17
  process (clk)
18
  begin
19
    if rising_edge(clk) then
20
      -- start FF --
21
      start <= ((not start) and (not rx_line)) or start;
22
      --------------
23
      if start = '1' then 
24
        if bittakt = 0 then
25
          bittakt <= 77;
26
          
27
          RX_reg(9 downto 1) <= RX_reg(8 downto 0);
28
          RX_reg(0) <= rx_line;
29
          
30
          bit_count <= bit_count + 1;
31
          if bit_count = 9 then
32
            start <= '0';
33
            bit_count <= 0;
34
            bittakt <= 294;
35
          end if;
36
        else
37
          bittakt <= bittakt + 1;
38
        end if;
39
      end if;
40
    end if;
41
  end process;
42
43
  Data <= RX_reg;
44
  run <= start;
45
  
46
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

von D. I. (Gast)


Lesenswert?

Weil 0-9 Zehn Schritte sind

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


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...

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.