Forum: FPGA, VHDL & Co. Uart Daten werden Falsch übertragen


von Maximilian S. (max_8549)


Lesenswert?

Guten Tag,

ich habe ein Uart für das Arty A7 100t geschrieben.
Mit dem Tool HTerm kann ich Daten problemlos empfangen allerdings werden 
die Daten Falsch ans Arty gesendet.
Ich habe über den PMOD ausgang ein Externes LEDPMOD mit 8 LED's aber es 
Leuchtet immer nur die achte LED.

Der Baudgenerator erzeugt den Takt von 19200Hz und die Baudrate von 
19200 ist auch in HTerm eingestellt.
In der Simulation läuft alles wie es soll.

Anbei der Code:
Uart Main:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
-- Uncomment the following library declaration if instantiating
6
-- any Xilinx leaf cells in this code.
7
--library UNISIM;
8
--use UNISIM.VComponents.all;
9
10
entity Uart is
11
    generic(
12
        DBIT: integer:=8;
13
        Div_Baud: integer:= 10417
14
    );
15
    port(
16
        clk         :   in      std_logic;
17
        reset       :   in      std_logic;
18
        
19
        send        :   in      std_logic;
20
        din         :   in      std_logic_vector(7 downto 0);
21
        
22
        TXb         :   out     std_logic;
23
        TXdone      :   out     std_logic;
24
        
25
        RXb         :   in      std_logic;
26
        received    :   out     std_logic := '0';
27
        dout        :   out     std_logic_vector(7 downto 0)
28
     );
29
end Uart;
30
31
architecture Behavioral of Uart is
32
component Clock_MGMT
33
port(-- Clock in ports
34
    -- Clock out ports
35
    clk_out          : out    std_logic;
36
    -- Status and control signals
37
    resetn             : in     std_logic;
38
    clk_in1           : in     std_logic
39
    );
40
end component;
41
component BaudGen is
42
   generic(
43
   divider: integer := 10417
44
);
45
port(
46
   clk, reset: in std_logic;
47
   clk_tick: out std_logic
48
);
49
end component;
50
component Uart_RX is
51
    generic(
52
       DBIT: integer:=8     -- # data bits
53
    );
54
   port(
55
       clk, reset: in std_logic;
56
       RX_tick: in std_logic;
57
       RXD: in std_logic;
58
       RX_done_tick: out std_logic;
59
       RX_Data: out std_logic_vector(7 downto 0)
60
);
61
end component;
62
63
component Uart_TX is
64
    generic(
65
       DBIT: integer:=8     -- # data bits
66
    );
67
    port(
68
       clk, reset: in std_logic;
69
       TX_Start : in std_logic;
70
       TX_tick: in std_logic;
71
       TX_Data: in std_logic_vector(7 downto 0);
72
       TX_done_tick: out std_logic;
73
       TXD: out std_logic
74
    );
75
end component;
76
77
signal tx_clk_tick, rx_clk_tick, sig_clk: std_logic := '0';
78
begin
79
80
C_MGMT: Clock_MGMT
81
   port map ( 
82
  -- Clock out ports  
83
   clk_out => sig_clk,
84
  -- Status and control signals                
85
   resetn => reset,
86
   --locked => locked,
87
   -- Clock in ports
88
   clk_in1 => clk
89
);
90
91
BaudRateTX: BaudGen 
92
    generic map(
93
        divider => Div_Baud
94
    )
95
    port map (
96
        clk => sig_clk,
97
        reset => reset,
98
        clk_tick =>tx_clk_tick
99
    );
100
101
BaudRateRX: BaudGen 
102
    generic map(
103
        divider => Div_Baud
104
    )
105
    port map (
106
        clk => sig_clk,
107
        reset => reset,
108
        clk_tick =>rx_clk_tick
109
    );
110
    
111
UART_TX_I:  Uart_TX
112
    generic map(
113
        DBIT => DBIT
114
    )
115
    port map (
116
        clk => sig_clk,
117
        reset => reset,
118
        TX_Start => send,
119
        TX_tick => tx_clk_tick,
120
        TX_Data => din,
121
        TX_done_tick => TXdone,
122
        TXD => TXb  
123
    );
124
    
125
UART_RX_I:  Uart_RX
126
    generic map(
127
        DBIT => DBIT
128
    )
129
    port map (
130
        clk => sig_clk,
131
        reset => reset,
132
        RX_tick => rx_clk_tick,
133
        RXD => RXb,
134
        RX_done_tick => received,
135
        RX_Data => dout
136
    );
137
end Behavioral;

BaudGenerator:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
-- Uncomment the following library declaration if instantiating
6
-- any Xilinx leaf cells in this code.
7
--library UNISIM;
8
--use UNISIM.VComponents.all;
9
10
11
entity BaudGen is
12
generic(
13
   divider: integer := 10417 -- 200MHz => 19200Hz
14
);
15
port(
16
   clk, reset: in std_logic;
17
   clk_tick: out std_logic
18
);
19
end BaudGen;
20
21
architecture Behavioral of BaudGen is
22
   signal count    :   integer range 0 to (divider/2)-1;
23
   signal tmp      :   STD_LOGIC := '0';
24
25
begin
26
   -- register
27
   process(clk,reset)
28
   begin
29
    if (reset = '0') then
30
        tmp <= '0';
31
        count <= 0;
32
    elsif rising_edge(clk) then
33
        if (count = (divider/2)-1) then
34
            tmp <= NOT(tmp);
35
            count <= 0;
36
        else
37
            count <= count + 1;
38
        end if;
39
    end if;
40
    end process;
41
clk_tick <= tmp;
42
43
end Behavioral;

Uart_RX:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
-- Uncomment the following library declaration if instantiating
6
-- any Xilinx leaf cells in this code.
7
--library UNISIM;
8
--use UNISIM.VComponents.all;
9
10
entity Uart_RX is
11
    generic(
12
        DBIT: integer :=8
13
    );
14
    port(
15
        clk, reset      :   in  std_logic;
16
        RX_tick         :   in  std_logic;
17
        RXD             :   in  std_logic;
18
        
19
        RX_done_tick    :   out std_logic;
20
        RX_Data         :   out std_logic_vector(7 downto 0)
21
    );
22
end Uart_RX;
23
24
architecture Behavioral of Uart_RX is
25
type s_type is (idle, start, data, stop);
26
   signal s_reg, s_next: s_type;
27
   signal TickCnt_reg, TickCnt_next: unsigned(3 downto 0);
28
   signal DataBitCnt_reg, DataBitCnt_next: unsigned(2 downto 0);
29
   signal data_reg, data_next: std_logic_vector(7 downto 0);
30
31
begin
32
33
   process(clk,reset)
34
   begin
35
      if reset='0' then
36
         s_reg <= idle;
37
         TickCnt_reg <= (others=>'0');
38
         DataBitCnt_reg <= (others=>'0');
39
         data_reg <= (others=>'0');
40
      elsif rising_edge(clk) then
41
         s_reg <= s_next;
42
         TickCnt_reg <= TickCnt_next;
43
         DataBitCnt_reg <= DataBitCnt_next;
44
         data_reg <= data_next;
45
      end if;
46
   end process;
47
   process(s_reg,TickCnt_reg,DataBitCnt_reg,data_reg,RX_tick,RXD)
48
   begin
49
      s_next <= s_reg;
50
      TickCnt_next <= TickCnt_reg;
51
      DataBitCnt_next <= DataBitCnt_reg;
52
      data_next <= data_reg;
53
      rx_done_tick <='0';
54
      case s_reg is
55
         when idle =>
56
            if RXD='0' then
57
               s_next <= start;
58
               TickCnt_next <= (others=>'0');
59
            end if;
60
         when start =>
61
            if (RX_tick = '1') then
62
               if TickCnt_reg=7 then
63
                  s_next <= data;
64
                  TickCnt_next <= (others=>'0');
65
                  DataBitCnt_next <= (others=>'0');
66
               else
67
                  TickCnt_next <= TickCnt_reg + 1;
68
               end if;
69
            end if;
70
         when data =>
71
            if (RX_tick = '1') then
72
               if TickCnt_reg=7 then
73
                  TickCnt_next <= (others=>'0');
74
                  data_next <= RXD & data_reg(7 downto 1) ;
75
                  if DataBitCnt_reg=(DBIT-1) then
76
                     s_next <= stop ;
77
                  else
78
                     DataBitCnt_next <= DataBitCnt_reg + 1;
79
                  end if;
80
               else
81
                  TickCnt_next <= TickCnt_reg + 1;
82
               end if;
83
            end if;
84
         when stop =>
85
            if (RX_tick = '1') then
86
               if TickCnt_reg=(7) then
87
                  s_next <= idle;
88
                  rx_done_tick <='1';
89
               else
90
                  TickCnt_next <= TickCnt_reg + 1;
91
               end if;
92
            end if;
93
      end case;
94
   end process;
95
   RX_Data <= data_reg;
96
end Behavioral;

Wo könnte der Fehler liegen?

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


Lesenswert?

Maximilian S. schrieb:
> ich habe ein Uart für das Arty A7 100t geschrieben.
Was sagt die Simulation?
Denn gerade eine RS232-Schnitts lässt sich wunderbar simulieren.
Dort ist ein simpler Stimuliegenerator dafür:
http://www.lothar-miller.de/s9y/archives/60-RS232-IO.html#extended
Ich würde das noch nicht "Testbench" nennen, weil es nur für die 
Waveform taugt und keine automatischen Vergleiche durchgeführt werden.

Die Beschreibung muss ich mir später anschauen, wegen der ausufernden 
Zwei-Prozess-Schreibweise wird das länger dauern. Bis dahin kannst du ja 
mal simulieren und dir das da ansehen:
http://www.lothar-miller.de/s9y/archives/48-RS232.html

Es ist übrigens sehr spannend, das RXD Signal völlig asynchron ohne 
Eintakten in einer FSM zu verwenden. Du wirst da ab&zu eigenartige 
Sachen erleben.
Siehe 
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html

von Gustl, der Echte! (Gast)


Angehängte Dateien:

Lesenswert?

- "Clock_MGMT" fehlt, aber der ist sowieso hier überflüssig.
- "Uart_TX" fehlt ebenfalls, wird hier aber auch nicht benötigt.
- Testbench fehlt ebenfalls und gerade diese wäre hier schon sehr 
interessant gewesen.
- Im Toplevel "Uart" gibt es den Port
reset       :   in      std_logic;
daraus wird nicht ersichtlich, dass das ein active-low Reset ist. Oder 
du hast das NOT Gatter bei der Verdrahtung mit "Clock_MGMT" vergessen. 
Wobei deine Komponente "Uart_RX" ebenfalls
clk, reset      :   in  std_logic;
hat aber einen active-low Reset erwartet.
- Es heißt UART.
- Da sind viele Leerzeilen ohne Grund.
- Simuliere das doch mal ernsthaft, da sieht man das "received" wild 
zappeln und falsche Daten an "dout".

Alles Gute, alles Liebe (-:

von Christoph Z. (christophz)


Lesenswert?

Maximilian S. schrieb:
> Wo könnte der Fehler liegen?

Du gehst davon aus, dass der Baudrate Generator im Sender und Empfänger 
gleich schnell und zur gleichen Zeit schalten (synchron sind). Du 
wolltest aber einen UART bauen -> Das A steht für asynchronous.

Wie ich von anderen gelernt habe, macht man üblicherweise Überabtastung 
(also z. B. mit vierfacher Baudrate) und eine Flankenerkennung beim 
Startbit.

von Duke Scarring (Gast)


Lesenswert?

Christoph Z. schrieb:
> Wie ich von anderen gelernt habe, macht man üblicherweise Überabtastung
> (also z. B. mit vierfacher Baudrate) und eine Flankenerkennung beim
> Startbit.
Überabtastung muss nicht sein, die einfachste Variante reicht:
Flankenerkennung auf's Startbit, 1,5 Bitzeiten warten (=Mitte vom ersten 
Datenbit), dann 8 mal ein Bit einlesen und jeweils eine volle Bitzeit 
warten, fertig.
Anschließend noch eine Bitzeit warten (dann ist man in der Mitte vom 
Stoppbit) und dann kann es wieder von vorn losgehen.

Duke

von reminder (Gast)


Lesenswert?

Maximilian S. schrieb:
> Anbei der Code:

Wichtige Regeln - erst lesen, dann posten!
...........
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

von Matthias (Gast)


Lesenswert?

Hi,

ich habe einen funktionierenden 12MBAUD-UART für das ARTY A7.
Bei Interesse kann ich ihn hier rein stellen, er kann auf verschiedene 
Baudraten eingestellt werden, sowie auf 1 oder 2 Stop-Bits. Ebenso kann 
die Parität aktiviert/deaktiviert werden.

Grüße, Matthias

von Maximilian S. (max_8549)


Lesenswert?

Sorry dass ich jetzt erst zurückschreibe.
Problem lag daran, dass ich die Flanke abgefragt habe beim empfangen. 
Mitte abgefragt und dann lief es. Musste das Arty A7 heute leider wieder 
zurück geben. Gehörte der Uni und wurde nur für dieses Modul benötigt.

Danke euch auf jeden Fall für die Antworten.

von Tim (Gast)


Lesenswert?

Duke Scarring schrieb:
> Überabtastung muss nicht sein, die einfachste Variante reicht:
> Flankenerkennung auf's Startbit, 1,5 Bitzeiten warten (=Mitte vom ersten
> Datenbit), dann 8 mal ein Bit einlesen und jeweils eine volle Bitzeit
> warten, fertig.[...]

Und wie erkennt man die Flanke ohne Überabtastung? Genau, mit 
Überabtastung :)

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


Lesenswert?

Maximilian S. schrieb:
> und dann lief es.
Wundert mich ein wenig bei dem Baudratengenerator:
1
:
2
    elsif rising_edge(clk) then
3
        if (count = (divider/2)-1) then
4
            tmp <= NOT(tmp);
5
            count <= 0;
6
        else
7
            count <= count + 1;
8
        end if;
9
    end if;
10
    end process;
11
clk_tick <= tmp;
12
:
13
:
14
        clk_tick =>rx_clk_tick
15
:
16
:
17
        RX_tick => rx_clk_tick,
18
:
19
:
20
            if (RX_tick = '1') then
21
:
Denn der gibt ja etliche (genau divider/2) clk-Zyklen lang einen aktiven 
Clock-Enable aus. Normalerweise ist ein Clock-Enable immer nur 1 
Taktzyklus lang aktiv:
1
:
2
    elsif rising_edge(clk) then
3
        if count = divider-1 then
4
            clk_tick  <= '1';
5
            count <= 0;
6
        else
7
            clk_tick  <= '0';
8
            count <= count + 1;
9
        end if;
10
    end if;
11
    end process;
12
:
13
:
14
        clk_tick =>rx_clk_tick
15
:
16
:
17
        RX_tick => rx_clk_tick,
18
:
19
:
20
            if (RX_tick = '1') then
21
:

: Bearbeitet durch Moderator
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.