Forum: FPGA, VHDL & Co. RS-232 Sendemodul


von Johannes B. (beyjoh)


Lesenswert?

Hallo allerseits, ich möchte kurz gesagt einen Prozess realisieren, der 
per RS232 Daten versendet. Ich hab also einfach mal drauf los gemacht 
und unten seht ihr was dabei herausgekommen ist. Problem ist jetzt 
folgendes. Wenn ich eine einfache Behavioral Sim mache (ohne 
Testbench-Datei) scheint alles zu funktionieren. Jetzt hab ich mal eine 
Testbench geschrieben, aber alle Ausgänge behalten in der Simulation 
frech einfach ihre Werte, als würde nichts passieren.

Also ich würde mich freuen wenn der ein oder andere mal rüberguckt, 
Tipps oder Vorschläge zum Fehler oder auch allgemeiner Natur hat. Danke 
soweit :)
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
7
entity rs232 is
8
  generic( FTeiler_Vorwahl: natural := 433 );                -- (Takt/BAUD)-1 { (50 MHz/115.200)-1 = 433 }
9
  port(    clk:      in STD_LOGIC;                      -- Basistakt (50 MHz)
10
        Res:      in STD_LOGIC;                      -- Reset
11
        TxD_in:    in STD_LOGIC_VECTOR(7 downto 0);          -- Eingang f. zu sendenden Wert
12
        TxD_Start:  in STD_LOGIC;                      -- Eingang zum Start der Übertragung
13
        TxD:      out STD_LOGIC;                      -- Ausgang TxD
14
        TxD_Busy:  out STD_LOGIC );                    -- Ausgang f. z.B. Sende-LED
15
end rs232;
16
17
architecture Behavioral of rs232 is
18
  signal Intclk: STD_LOGIC := '0';                        -- interner Takt f. Sendeprozess
19
  signal vTxD_Start: STD_LOGIC := '0';                    -- Variable zur Erkennung einer st. Taktflanke
20
  signal BitCount: natural range 0 to 10 := 10;              -- Zählvariable (10 steht für warten)
21
  signal TxD_Buffer: STD_LOGIC_VECTOR(9 downto 0) := "1111111111";  -- Datenpuffer (+ Start- u. Stopbit)
22
begin
23
  
24
  
25
  -- Sendeprozess
26
  Sender:  process(Res, Intclk)
27
          --variable vTxD_Start: STD_LOGIC := '0';                      -- Variable zur Erkennung einer st. Taktflanke
28
          --variable BitCount: natural range 0 to 10 := 10;                -- Zählvariable (10 steht für warten)
29
          --variable TxD_Buffer: STD_LOGIC_VECTOR(9 downto 0) := "1111111111";  -- Datenpuffer (+ Start- u. Stopbit)
30
        begin
31
          
32
          if Res='1' then  -- Reset?
33
          
34
            TxD      <= '1';
35
            TxD_Busy    <= '0';
36
            vTxD_Start  <= '0';
37
            BitCount    <= 10;                    -- 10 steht für warten
38
            TxD_Buffer  <= "1111111111";
39
          
40
          elsif(Intclk'event and Intclk='1') then
41
          
42
            -- steigende Flanke von Start erfassen
43
            if(TxD_Start='1' and vTxD_Start='0') then
44
            
45
              -- Übertragung soll gestartet werden:
46
              -- Zählvariable wird gesetzt und Puffer beschrieben
47
              
48
              BitCount    <= 0;
49
              TxD_Buffer   <= '1' & TxD_in & '0';        -- Stopbit & Datenbits & Startbit
50
              TxD_Busy    <= '1';
51
              
52
            elsif(BitCount < 10) then
53
              
54
              TxD <= TxD_Buffer(BitCount);
55
              
56
              if(BitCount = 9) then
57
                -- letztes Bit gesendet, alles zurücksetzen
58
                
59
                BitCount   <= 10;
60
                TxD_Buffer   <= "1111111111";
61
                TxD_Busy    <= '0';
62
              
63
              else
64
              
65
                BitCount <= BitCount+1;
66
                
67
              end if;
68
            end if;
69
            
70
            vTxD_Start <= TxD_Start;
71
          
72
          end if;
73
        
74
        end process Sender;
75
76
  
77
  -- Frequenzteiler
78
  FTeiler:  process(Res, clk)
79
          variable zaehl: natural range 0 to FTeiler_Vorwahl-1;
80
        begin
81
          if Res='1' then  -- Reset?
82
          
83
            zaehl := FTeiler_Vorwahl-1;
84
            Intclk <= '0';
85
            
86
          elsif(clk'event and clk='1') then
87
          
88
            Intclk <= '0';
89
            if zaehl = 0 then
90
            
91
              zaehl := FTeiler_Vorwahl-1;
92
              
93
            elsif zaehl > (FTeiler_Vorwahl-1)/2 then
94
            
95
              zaehl := zaehl-1;
96
              Intclk <= '1';
97
            
98
            else
99
              
100
              zaehl := zaehl-1;
101
            
102
            end if;
103
          
104
          end if;
105
        end process FTeiler;
106
  
107
end Behavioral;

von Fpgakuechle K. (Gast)


Lesenswert?

Johannes Beyer schrieb:
> Wenn ich eine einfache Behavioral Sim mache (ohne
> Testbench-Datei) scheint alles zu funktionieren.

??? Simulation ohne  Testbench (aka Stimuli) ???


> Jetzt hab ich mal eine
> Testbench geschrieben, aber alle Ausgänge behalten in der Simulation
> frech einfach ihre Werte, als würde nichts passieren.

Mglw. passiert auch nichts in deiner Testbench. Da die Testbench nicht 
vorliegt kann man nichst dazu sagen. Mit welchen Kommandos hast du die 
Simulation gestartet?

Dann sollte man sich mal die Variable zähl anschauen ob sich da was in 
der gewünschten Art und Weise tut.

MfG

von Johannes B. (beyjoh)


Lesenswert?

Ohne Testbench, indem ich einfach die Behavorial Simulation, halt ohne 
vorher eine Testbench zu erstellen, starte. Im Simulator muss man dann 
halt alle Signale manuell setzen. Und so funktioniert es scheinbar auch.

Anschließend habe ich folgende Testbench geschrieben. Die Eingänge 
werden in der Simulation auch wie gewünscht gesetzt. Die Ausgänge 
reagieren jetzt aber plötzlich überhaupt nichtmehr..


Testbench:
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.ALL;
3
 
4
ENTITY Test_Beh IS
5
END Test_Beh;
6
 
7
ARCHITECTURE behavior OF Test_Beh IS 
8
 
9
    -- Component Declaration for the Unit Under Test (UUT)
10
 
11
    COMPONENT rs232
12
    PORT(
13
         clk : IN  std_logic;
14
         Res : IN  std_logic;
15
         TxD_in : IN  std_logic_vector(7 downto 0);
16
         TxD_Start : IN  std_logic;
17
         TxD : OUT  std_logic;
18
         TxD_Busy : OUT  std_logic
19
        );
20
    END COMPONENT;
21
    
22
23
   --Inputs
24
   signal clk : std_logic := '0';
25
   signal Res : std_logic := '0';
26
   signal TxD_in : std_logic_vector(7 downto 0) := (others => '0');
27
   signal TxD_Start : std_logic := '0';
28
29
   --Outputs
30
   signal TxD : std_logic;
31
   signal TxD_Busy : std_logic;
32
33
   -- Clock period definitions
34
   --constant clk_period : time := 10 ns;
35
 
36
BEGIN
37
 
38
  -- Instantiate the Unit Under Test (UUT)
39
   uut: rs232 PORT MAP (
40
          clk => clk,
41
          Res => Res,
42
          TxD_in => TxD_in,
43
          TxD_Start => TxD_Start,
44
          TxD => TxD,
45
          TxD_Busy => TxD_Busy
46
        );
47
48
49
50
  Res <=  '0', 
51
        '1' after 20 us,
52
        '0' after 21 us;
53
  
54
  
55
  -- Sendedauer (1/115200 = 8.68 us)
56
  TxD_in <=  "11111111",
57
          "00100100" after 1.4 us,
58
          "11011011" after 1.8 us,
59
          "00000000" after 12.1 us,
60
          "10110010" after 22 us,
61
          "11111111" after 25 us;
62
          
63
  TxD_Start <=  '0',
64
            '1' after 1.5 us,
65
            '0' after 1.6 us,
66
            '1' after 10 us,
67
            '0' after 12 us,
68
            '1' after 22.1 us,
69
            '0' after 25 us;
70
71
72
  process
73
  begin
74
    clk <= '0';
75
    wait for 10 ns;
76
    clk <= '1';
77
    wait for 10 ns;
78
  end process;
79
80
   -- Clock process definitions
81
   --clk_process :process
82
   --begin
83
  --  clk <= '0';
84
  --  wait for clk_period/2;
85
  --  clk <= '1';
86
  --  wait for clk_period/2;
87
   --end process;
88
 
89
90
   -- Stimulus process
91
   --stim_proc: process
92
   --begin    
93
      -- hold reset state for 100 ns.
94
      --wait for 100 ns;  
95
96
      --wait for clk_period*10;
97
98
      -- insert stimulus here 
99
100
      --wait;
101
   --end process;
102
103
END;

von PittyJ (Gast)


Lesenswert?

Nur mal so als Frage: warum hast du zaehl als Variable implementiert?

  variable zaehl: natural range 0 to FTeiler_Vorwahl-1;

Ich hätte wohl ein Signal genommen. Was spricht für die Variable?

von Johannes B. (beyjoh)


Lesenswert?

Ohne besonderen Grund. Was spricht für ein Signal?

von Fpgakuechle K. (Gast)


Lesenswert?

Johannes Beyer schrieb:
> Ohne besonderen Grund. Was spricht für ein Signal?

Es ist ein signal. Zaehl ist ein digitaler counter, also ein paar FF mit 
Drähten zur Verteilung der elektrischen Signale. Elektrische Signale 
sind nicht unendlich schnell sondern haben eine gewisse 
Verzögerungszeit. Dementsprechend behandelt sie auch der Simulator, es 
wird nicht nur der Wert simuliert (berechnet) sondern auch das zeitliche 
Verhalten. So wird ein neu berechneter Wert erst am ende eines prozesses 
zugewiesen, bei einer variablen sofort.

Es gibt eine einfache Faustregel für die Verwendung von Variablen:
Benutze keine Variablen!

Wenn man einige Erfahrung hat und VHDL soweit versteht, das man keine 
Faustregeln mehr braucht, dann kann man sie in Testbenches verwenden. 
Wenn Du zaehl für den process kapseln willst, dann schreib das in einen 
Block:

1
architecture abc of xyz is
2
signal something: std_logic;
3
--
4
--in der gesamten architecture sichtbare signale
5
begin
6
7
b_teiler:block is
8
 signal lokaler_zahler: std_logic_vector(7 downto 0);
9
begin
10
 process(clk)
11
 begin
12
 --
13
 end process;
14
end block b_teiler;
15
end architecture;

von Achim S. (Gast)


Angehängte Dateien:

Lesenswert?

du legst erst nach 20us einen Reset an, bis dahin sind Teile deiner 
Signale/Variablen auf einem undefinierten Wert.

Nach dem Reset ist alles in einem definierten Zustand, und du versuchst 
mit IntCLK eine Flankenerkennung auf TXDStart zu machen. IntCLK hat aber 
eine Periode von 8,6µs, der High-Puls auf TXDSTart ist nur 2,9µs lang -> 
du verpasst den Highpuls auf TXDStart uns startest nie den Transmitter. 
Deshalb tut sich nichts an den Ausgängen.

Johannes Beyer schrieb:
> Was spricht für ein Signal?

z.B. dass man bei der Simulation das folgende Problem vermeidet:

WARNING: Simulation object /test_beh/uut/:FTeiler/zaehl was not 
traceable in the design for the following reason:
ISim does not yet support tracing of VHDL variables.

Du kannst dir in einer Simulation nicht nur die Ausgänge sondern auch 
die internen Signale anschauen. Damit verstehst du auch sofort, warum 
sich die Ausgänge in deiner Simulation nicht ändern. (Interne Variablen 
lassen sich hingegen zumindest in meiner ISIM-Version nicht anzeigen.)



Unabhängig von den Simulationsproblemen sollte dir für die Synthese klar 
sein, dass du hier ein Logiksignal als Takt missbrauchst:

Johannes Beyer schrieb:
> elsif(Intclk'event and Intclk='1') then

Das kann beim Betrieb im FPGA alle möglichen unschönen Effekte geben. 
Implementiere sowas als ein Clock Enable, nicht als ein mit Logik 
erzeugtes Taktsignal

von dden (Gast)


Lesenswert?

Hallo,
na ja ohne eine clock läuft da ja auch nichts, mal clk in der simulation 
angezeigt?
Für deinen Clk-Stimulus brauchst du noch ein Loop-Statment sonst macht 
er das genau einmal.

Mfg

von Achim S. (Gast)


Lesenswert?

dden schrieb:
> na ja ohne eine clock läuft da ja auch nichts, mal clk in der simulation
> angezeigt?

CLK läuft in der Simu mit einer Periode von 20ns, so wie sich beyjoh das 
gedacht hat.

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


Lesenswert?

Johannes Beyer schrieb:
1
   generic( FTeiler_Vorwahl: natural := 433 ); --  (Takt/BAUD)-1 { (50 MHz/115.200)-1 = 433 }
Lass das doch den Synthesizer rechnen...

> Also ich würde mich freuen wenn der ein oder andere mal rüberguckt,
> Tipps oder Vorschläge ... hat
Sieh dir das mal an:
http://www.lothar-miller.de/s9y/categories/42-RS232

> ich möchte kurz gesagt einen Prozess realisieren, der per RS232 Daten
> versendet.
Das ist eine krude Denkweise. Du kannst Hardware nicht so einfach in 
einzelen Prozesse kapseln. Oft geht das gut, zeimlich oft aber auch 
nicht, und dann stehst du mit dieser "Prozess=Bauteil" Denkweise sauber 
im Regen. Nicht umsonst werden in VHDL ganze Einheiten (entities) als 
Bauteil (components) in anderen Einheiten instantiiert...

Johannes Beyer schrieb:
> Was spricht für ein Signal?
Alles, was gegen eine Variable spricht. Siehe den Klassiker: 
Beitrag "Variable vs Signal"

: Bearbeitet durch Moderator
von Johannes B. (beyjoh)


Lesenswert?

Ah es lag tatsächlich daran dass TxD_Start zu kurz 1 war - dummer 
Fehler^^

Danke für die Hilfe und auch die anderen Tipps :)

von Johannes B. (beyjoh)


Lesenswert?

Achim S. schrieb:
> Unabhängig von den Simulationsproblemen sollte dir für die Synthese klar
> sein, dass du hier ein Logiksignal als Takt missbrauchst:
>
> Johannes Beyer schrieb:
>> elsif(Intclk'event and Intclk='1') then
>
> Das kann beim Betrieb im FPGA alle möglichen unschönen Effekte geben.
> Implementiere sowas als ein Clock Enable, nicht als ein mit Logik
> erzeugtes Taktsignal

kannst du mir bitte konkret zeigen wie ich das mache?

von Achim S. (Gast)


Lesenswert?

Johannes Beyer schrieb:
>> Implementiere sowas als ein Clock Enable, nicht als ein mit Logik
>> erzeugtes Taktsignal
>
> kannst du mir bitte konkret zeigen wie ich das mache?

du findest hier ein Beispiel für die Nutzung eines Clock-Enable Signals:

http://www.mikrocontroller.net/articles/Taktung_FPGA/CPLD

Im Abschnitt "Kombinatorik im Taktpfad" wird auch beschrieben, welche 
Nachteile bisheriger Ansatz hat.

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.