VHDL UART mehrere Vectoren übertragen

Gast #3677728
Lesenswert?

1
  data_0 <= "1111100001010101"
2
  data_1 <= "0100101101001111"
3
  data_3 <= "0001101010101010"
4

5
  
6
    --Senden--
7
    
8
process
9
begin 
10
     
11
  TX_Data <= data_0 ?????????????????????????;
12
  
13
 
14
      
15
  wait until rising_edge(i_SystemClock_dl);
16

17
      txstart <= TX_Start; 
18
    
19
  
20
  if (TX_Start='1' and txstart='0') then      
21
    txcnt    <= 0;                          
22
    txbitcnt <= 0;                               
23
    txsr     <= '1' & TX_Data & '0';       
24
  else         
25
    if(txcnt<(Quarz_Taktfrequenz/Baudrate)-1) then            
26
      txcnt <= txcnt+1;         
27
    else              
28
      if (txbitcnt<18) then              
29
        txcnt    <= 0;              
30
        txbitcnt <= txbitcnt+1;              
31
        txsr     <= '1' & txsr(txsr'left downto 1);            
32
      end if;         
33
    end if;      
34
  end if;   
35

36
  end process;      
37
    
38

39
TXD     <= txsr(0);     
40
TX_Busy <= '1' when (TX_Start='1' or txbitcnt<18) else '0';   
41

42

43
end behaviour;



Hallo!

Ich möchte nacheinander die Daten (data_0 bis data_3) über den UART am 
PC ausgeben.
Hat jemand eine Idee, wie man das elegant und einfach lösen könnte.

Vielen Dank!

Gruss
Gast #3677745
Lesenswert?

Anfäng schrieb:
> [vhdl]
>   data_0 <= "1111100001010101"
>   data_1 <= "0100101101001111"
>   data_3 <= "0001101010101010"
>

> Ich möchte nacheinander die Daten (data_0 bis data_3) über den UART am
> PC ausgeben.
> Hat jemand eine Idee, wie man das elegant und einfach lösen könnte.

Hallo Anfänger,

also elegant wäre wenn man das gar nicht möchte, drei Daten seperater 
Typen auszugeben.
Elegant wäre es wenn die Daten bereits als Array vorliegen würden.
Dazu musst Du Dir einen Datentyp definierien, bsp:

type data_03_typ is array (2 downto 0,15 downto 0) of std_logic;
signal data_03 : data_03_typ := ("1111100001010101", "0100101101001111"
, "0001101010101010"
);

Anschließend kannst Du die Daten mit Hilfe einer kleinen Statemaschine 
dann durch deinen UART tackern.

Gruß

Vanilla
#3677762
Lesenswert?

Hallo, guten Tag.
So werden bei mir die Daten vom DE1 übertragen. Es sind dann 6 Byte.

Gruss
1
library IEEE; 
2
use IEEE.STD_LOGIC_1164.ALL; 
3
use IEEE.NUMERIC_STD.ALL; 
4

5
entity ram_array is
6
  Generic ( Quarz_Taktfrequenz : integer := 50000000;  
7
              Baudrate        : integer  := 9600 
8
          );      
9
  port(
10
    clk    : in  std_logic;
11
    sw     : in  std_logic_vector(1 downto 0);
12
    TXD    : out  STD_LOGIC 
13
    );
14
end ram_array;
15

16
architecture Behavioral of ram_array is
17

18
signal txstart : std_logic := '0';
19
signal txsr    : std_logic_vector  (9 downto 0) := "1111111111";  
20
signal txbitcnt : integer range 0 to 10 := 10;
21
signal txcnt    : integer range 0 to (Quarz_Taktfrequenz/Baudrate)-1;
22

23
signal TX_Start : STD_LOGIC :='0';
24
signal TX_Data  : STD_LOGIC_VECTOR (7 downto 0);
25
signal TX_Wert  : STD_LOGIC_VECTOR (7 downto 0);
26
signal TX_Busy  : STD_LOGIC :='0';
27

28
signal c : integer range 0 to 10000000 := 0; 
29

30
signal RomAddr: integer range 0 to 5 := 0; 
31

32
type Rom6 is array (0 to 5) of STD_LOGIC_VECTOR (7 downto 0);
33
  constant Speicher_rom : Rom6 := (
34
    "11111000", "01010101",
35
    "01001011", "01001111",
36
    "00011010", "10101010"
37
    );
38

39
begin
40

41
process
42
begin
43
  wait until rising_edge(clk);
44
    if (c<5000000 ) then        
45
      c <= c+1; 
46
      tx_start <= '0';
47
    elsif (romaddr < 6) and (sw(0)='1')then
48
      c <= 0;                  
49
      TX_Data <= std_logic_vector(Speicher_rom(RomAddr)); 
50
      RomAddr <= RomAddr +1;  
51
      tx_start <= '1';
52
    end if;
53
    
54
    if   (sw(1)='1') then   
55
      RomAddr <= 0;        
56
    end if;
57
end process;
58
  
59
process
60
begin
61
wait until rising_edge(clk);
62
  txstart <= TX_Start;
63
  if (TX_Start='1' and txstart='0') then 
64
     txcnt    <= 0;                      
65
     txbitcnt <= 0;                      
66
     txsr     <= '1' & TX_Data & '0';    
67
  else
68
     if(txcnt<(Quarz_Taktfrequenz/Baudrate)-1) then
69
        txcnt <= txcnt+1;
70
     else  
71
        if (txbitcnt<10) then
72
          txcnt    <= 0;
73
          txbitcnt <= txbitcnt+1;
74
          txsr     <= '1' & txsr(txsr'left downto 1);
75
        end if;
76
     end if;
77
  end if;    
78
end process;
79
TXD  <= txsr(0);
80
TX_Busy <= '1' when (TX_Start='1' or txbitcnt<10) else '0'; 
81
      
82
end Behavioral;
#3677794
Lesenswert?

Hallo, vielleicht findest du auch mal eine Lösung mit "RX" um Daten in 
ein Array zu schreiben:

Type Ram128x8 is ARRAY (0 to 127) OF unsigned(7 downto 0);
signal speicher_ram : Ram128x8;

oder:

Type Ram128x8 is ARRAY (0 to 127) of STD_LOGIC_VECTOR (7 downto 0);
signal speicher_ram : Ram128x8;

Gruss
Gast #3677796
Lesenswert?

Hallo Peter,

vielen Dank für deinen Bsp-Code. Ich habe das ganze mal implementiert 
und versuche es zum Laufen zu bekommen.

Was realisierstu du auf deinem DE1 mit:

sw     : in  std_logic_vector(1 downto 0);
bzw.
sw0 und sw1
?

Gruss
Moderator (Firma: Titel) Persönliche Seite #3677832
Lesenswert?

Anfäng schrieb:
> nur wie übergebe ich dann das Gesamtarray an TX_Data?
Gar nicht. Du musst ein Zeichen nach dem anderen übergeben und 
dazwischen warten, bis die vorige Übertragung fertig ist. Für dieses 
Warten ist eine FSM sinnvoll. Eigentlich läuft alles, was irgendwelche 
zeitlichen Abläufe darstellt ("nacheinander", "erst das, dann das", 
"solange", "während", "bis"...), in FPGAs über Zustandsautomaten.

Anfäng schrieb:
> Was realisierstu du auf deinem DE1 mit:
> sw     : in  std_logic_vector(1 downto 0);
Das ist ein zwei Bit breiter Eingangsvektor vom Typ std_logic. Das 
findest du in deinem VHDL Buch ganz weit vorne...
#3678004
Lesenswert?

sw(0) und sw(1) sind Schiebeschalter  (switch).
Mit dem sw(0) gebe ich den Start zur Ausgabe nach Ablauf einer 
bestimmten Zeit. Wenn ich den Schiebeschalter betätige , werden 6 Byte 
ausgegeben dann ist Feierabend. Mit dem sw(1) setze ich die Adresse 
wieder zum Anfang und es kann mit sw(0) wieder auegegeben werden.

GRuss
Gast #3678031
Lesenswert?

Peter Bierbach schrieb:
> sw(0) und sw(1) sind Schiebeschalter  (switch).
> Mit dem sw(0) gebe ich den Start zur Ausgabe nach Ablauf einer
> bestimmten Zeit. Wenn ich den Schiebeschalter betätige , werden 6 Byte
> ausgegeben dann ist Feierabend. Mit dem sw(1) setze ich die Adresse
> wieder zum Anfang und es kann mit sw(0) wieder auegegeben werden.
>
> GRuss

Hi,

hab es jetzt soweit hinbekommen.

Wie machst du das mit der Ausertung am PC?
Ich nutze HTerm.
Daten kommen zwar an, jedoch ist die Darstellgung bei mir falsch.

Gruss
#3678057
Lesenswert?

Ich habe mir selber ein Programm geschrieben in Purebasic, weil ich den 
Pc und das DE1 dann nach belieben kommunizieren lassen kann.

Für Testzwecke reicht aber der Hterm.

Was heisst falsch. Vielleicht stimmt die Baurate beim FPGA nicht überein 
mit der vom Hterm? Oder der AScii stimmt nicht überein?

Nimm mal "Terminal" von hier : 
http://hw-server.com/terminal-terminal-emulation-program-rs-232 der ist 
nicht so aufgeblasen.

Gruss
Gast #3678065
Lesenswert?

Die übertragen Binärvektoren stimmen überhaupt nicht mit denen im
VHDL überein.

Baudrate und Qurarzfrequenz sind richtig eingestellt.

Wenn ich mit dem Oszi den Datenstrem anschaue, werden 7 Blöcke anstatt 6
übertragen.

????

Gruss
#3678095
Lesenswert?

Peter Bierbach schrieb:
> Die Simulation kannste als Neuling vergessen, da werden teilweise
> Zustände reingezaubert die noch unerklärlicher für eine Neuling sind.
>
> Verlass dich erstmal auf deine Gedankenlogik und in die einer VHDL.

Eine Simulation ist auch als Anfänger absolut empfehlenswert und gehört 
zu den Dingen, die man so schnell wie möglich lernen sollte.
Eine Simulation ist wie der Debugger für ein PC-Programm.
Man kann damit alle Signale beobachten und entdeckt Gedankenfehler.
Die eigene Gedankenlogik kann zaubert nämlich noch viel unerklärlichere 
Zustände als der Simulator. Dieser zaubert nämlich auch nur dann 
unerklärliche Zustände, wenn die Gedankenlogik und das VHDL nicht 
stimmen.
Gast #3678100
Lesenswert?

@ Peter,

der Unterschied zu meiner Hardware liegt darin,
dass mein FPGA mit 100 MHz läuft.

Ich glaube der Fehler liegt bei mir am Timining.

Wie müsste ich folgende Zeilen ändern, dass sie zu meinen 100 MHz 
passen:

signal c : integer range 0 to 10000000 := 0;

 if (c<10000000 ) then


Gruss
Moderator (Firma: Titel) Persönliche Seite #3678256
Lesenswert?

Anfäng schrieb:
> dass mein FPGA mit 100 MHz läuft.
Und welche Toolchain von welchem Hersteller verwendest du?

Peter Bierbach schrieb:
> Die Simulation kannste als Neuling vergessen, da werden teilweise
> Zustände reingezaubert die noch unerklärlicher für eine Neuling sind.
Peter, läuft dein Simulator eigentlich schon?

Anfäng schrieb:
> Ich glaube der Fehler liegt bei mir am Timining.
Gerade so eine sendende serielle Schnitte ist doch optimal zu 
Simulieren, weil man nur in der Waveform schauen muss, ob was 
rauskommt...
http://www.lothar-miller.de/s9y/categories/42-RS232

Zur Einführung für "Neulinge":
http://www.lothar-miller.de/s9y/archives/80-Hello-World!.html
Und falls der Neuling die Xilinx ISE verwendet:
http://www.lothar-miller.de/s9y/archives/81-Xilinx-ISE-Step-by-Step.html
#3678380
Lesenswert?

Die hat damit nichts zu tun:
signal c : integer range 0 to 10000000 := 0;
Das ist nur eine Zeitbremse für die Datenübertragung  pro Byte zum PC.

Du musst hier deine 100.000.000 reinsetzen im Programm :
Quarz_Taktfrequenz : integer := 50000000;

Dann stimmt auch die Teilung nachher wieder zur Baud.
Im RS232 von Miller ist es eigentlich wurscht , ich glaube nur an die 
115.000 Baud-Grenze scheitert ee ab und zu wenn der USB-Dongle am PC ein 
billigprodukt ist.

Gruss
Moderator (Firma: Titel) Persönliche Seite #3678991
Lesenswert?

Peter Bierbach schrieb:
> Es geht hier um die Taktfrequenz und  die Baud .... keine
> Zeitverzögerung.
Es geht hier um die zeitliche Verzögerung zwischen den Startsignalen 
zweier Zeichen:
1
    if (c<5000000 ) then       -- bei 50MHz werden ca. 10 Zeichen pro Sekunde gesendet (50MHz/5Mio)=10Hz
2
      c <= c+1; 
3
      tx_start <= '0';
4
    elsif (romaddr < 6) and (sw(0)='1')then
5
      c <= 0;                  
6
      tx_start <= '1';
7
    end if;
Und hier geht es um die Baudrate:
1
signal txcnt    : integer range 0 to (Quarz_Taktfrequenz/Baudrate)-1;
2
:
3
:
4
     if(txcnt<(Quarz_Taktfrequenz/Baudrate)-1) then
5
        txcnt <= txcnt+1;
6
     else
Gast #3679029
Lesenswert?

Guten Morgen,

@ Lothar Miller:

Ich habe gestern nochmals dein RS232 Beispiel implementiert und 
getestet.
Im VHDL weise ich TX_Data <= "10101010"; zu.

Das Terminal spuckt mir jedoch immer 00010101 00000000 aus???????

Muss man das verstehen?



Gruss
Moderator (Firma: Titel) Persönliche Seite #3679061
Lesenswert?

Anfäng schrieb:
> Ich habe gestern nochmals dein RS232 Beispiel implementiert
Wie und auf welcher Hardware?

> und getestet.
Mit einer Simulation?

> Das Terminal
Welches?

> spuckt mir jedoch immer 00010101 00000000 aus???????
Warum?

> Im VHDL weise ich TX_Data <= "10101010"; zu.
Wie oft wird tx_start aktiviert?
Und was passiert mit anderen Bitmustern?

> Muss man das verstehen?
Es wäre gut. Der Weg dorthin nennt sich "Lernen".
Die gute Nachricht: meine Beschreibung wurde schon zigfach verwendet und 
auf einige FPGAs implementiert. Die Schlechte: irgendwas ist in deiner 
Implementierung oder deiner Hardware noch faul.
Gast #3679066
Lesenswert?

1
begin   
2
-- Senden   
3
process begin
4

5

6
 TX_Data <= "10101010"; 
7
      
8
wait until rising_edge(CLK);      
9
txstart <= TX_Start; 
10
   
11
if (TX_Start='1' and txstart='0') then -- steigende Flanke, los gehts         
12
txcnt    <= 0;                      -- Zähler initialisieren         
13
txbitcnt <= 0;                               
14
txsr     <= '1' & TX_Data & '0';    -- Stopbit, 8 Datenbits, Startbit, rechts gehts los      
15
else         
16
if(txcnt<(Quarz_Taktfrequenz/Baudrate)-1) then            
17
txcnt <= txcnt+1;         else  -- nächstes Bit ausgeben              
18
if (txbitcnt<10) then              
19
txcnt    <= 0;              
20
txbitcnt <= txbitcnt+1;              
21
txsr     <= '1' & txsr(txsr'left downto 1);            
22
end if;         
23
end if;      
24
end if;   
25

26
end process;
27

28

29
TXD     <= txsr(0);  -- LSB first   
30
TX_Busy <= '1' when (TX_Start='1' or txbitcnt<10) else '0';

Das Sendemodul habe ich wie oben dargestellt implementiert.
TX_Start wird über einen externen Schalter (Eingangspin) ausgelöst.

Müsste doch so in Ordnung sein.

Gruss
#3679112
Lesenswert?

Lothar hatte dir 6 einfache Fragen gestellt und du beantwortet keine 
davon. Erwartet du ernsthaft, dass man dir jetzt noch hilft?

Eine serielle Schnittstelle ist noch eher einfach, ich beschreibe mal 
das Senden.

Wie seriell schon sagt wird immer nur ein Bit übertragen. Man liefert 
die Bits intern aber oft als Byte an. Also hat man dieses Bit Array, 
dieses Byte, und gibt davon nacheinander die Einträge auf die 
Sendeleitung. Was man braucht ist etwas um die Baudrate einzustellen und 
etwas um die Einträge des Bytes zu zählen, einen Laufindex quasi. Beides 
geht mit Zählern. Dann gibt es noch das Start- und Stoppbit das man noch 
setzt. Mehr ist das nicht.

Aber aller Anfang ist hart, daher würde ich mit blinkenden LEDs und so 
anfangen um VHDL etwas zu verstehen.
Moderator (Firma: Titel) Persönliche Seite #3679138
Lesenswert?

Anfäng schrieb:
> TX_Start wird über einen externen Schalter (Eingangspin) ausgelöst.
> Müsste doch so in Ordnung sein.
Externe Signale müssen einsynchronisiert werden. Sonst hast du evtl. das 
Problem der FSM mit asynchronem Eingang (das hier aber nicht die Ursache 
ist!):
http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

> Müsste doch so in Ordnung sein.
Es kommt darauf an, wie und ob der unbekannte Schalter prellt.

> Müsste doch so in Ordnung sein.
Ich hatte 6 Fragen gestellt. Mindestens die Antwort für die erste wäre 
hochinteressant...
(edit: Gustl Buheitel war schneller ;-)
#3679301
Lesenswert?

---------------------------------------
X_Start wird über einen externen Schalter (Eingangspin) ausgelöst.
---------------------------------------
Da wird dann immer nur 1 Byte gesendet.

So kannst du es in einer Schleife einbinden.
Funktioniert bei meinem DE1 wunderbar:
1
 if c<5000000 then  
2
      c <= c+1; 
3
      tx_start <= '0';      
4
    elsif  sw(0)='1' and (ramaddr < 130) then          
5
      c <= 0; 
6
      tx_start <= '1';              
7
      TX_Data <= std_logic_vector(Speicher_ram(RamAddr)); -- Daten von mein RAM-Bereich
8
      led_r <= std_logic_vector(Speicher_ram(RamAddr)); -- LED zur Kontrolle
9
      RamAddr <= RamAddr + 1;    
10
    end if;
#3679315
Lesenswert?

-----------------------------------
begin
-- Senden
process begin


 TX_Data <= "10101010";

wait until rising_edge(CLK);
-------------------------------------

Dein TX_Data kannst du nicht so wild nach Processbegin hinschmeissen.
Da kommt dann nur Kauderwelsch an am PC. Das muss mit im Takt 
eingebunden werden damit es einen sychronen Lauf hat für die 
Senderoutine.

Gruss
Gast #3679619
Lesenswert?

Hallo zusammen,

schon mal vielen Dank für die ganzen nützlichen Hilfestellungen.

Ich versuche nochmal alles neu aufzusetzen, hier eine kurze Beschreibung 
was mein Ziel ist:

- Eval-Kit: DE0 nano
- FTDI UART - USB - Kabel


Würde gern die Sende- und Empfangsroutine von Lothar Miller auf dem DE0 
nano implementieren.
Dazu möchte ich hintereinander mehrere 18 - bit lange std_logic_vector 
an
mein Terminalprogramm übertragen und auswerten.

Der ganze Datenübertragung soll mit einstellbarem Taktzyklus ablaufen 
(z.B. alle 2 Sekunden Übertragung der Datenpakete)

Wie ihr schon gemerkt habt, stecke ich VHDL-technisch noch in den 
Kinderschuhen ;), aber vll. kann mir doch jemand spezifische 
Hilfestellung geben.

Viel DANK!

Gruss
Holger
#3679671
Lesenswert?

---------------------------
Dazu möchte ich hintereinander mehrere 18 - bit lange
----------------------------

Die musst du schon in Byte aufteilen wenn du von Miller die Routine 
nutzen möchtest. oder überträgst die als Textstring 18Bit sind dann 
18Ascii zum PC wenn es nicht so auf Geschwindigkeit ankommt wie du 
schreibst ca alle 2 Sekunden.

Gruss
Moderator (Firma: Titel) Persönliche Seite #3679680
Lesenswert?

Anfäng schrieb:
> Dazu möchte ich hintereinander mehrere 18 - bit lange std_logic_vector
Kann dein PC mit 18 Datenbits umgehen? Meiner kann nur 7 oder 8 
Datenbits...

Du erkennst das Problem? Du wirst also die 18 Bits in 3 Bytes aufteilen 
müssen. Das letzte Byte kann dann noch Zusatzinformationen beinhalten. 
Oder jedes einzelne Byte seine Position im Wort mitbringen. Oder ein Bit 
den Start markieren...
Gast #3679885
Lesenswert?

Lothar Miller schrieb:
> Du erkennst das Problem? Du wirst also die 18 Bits in 3 Bytes aufteilen
> müssen.

Ja, das habe ich erkannt.
Kann das UART-Design von dir einfach 1:1 auf dem FPGA implementieren 
werden, wenn man NUR 8-Datenbit an das Terminal senden will?

Oder muss man zusätzlich (außer passende CLK und Baud) noch etwas 
beachten und den Code erweitern?

Es müsste doch ausreichend sein, am Eval-Kit nur die UART/USB-Leitungen 
TXD, GND und 5V anzuschließen, um die Daten empfangen zu können?

Gruß
Holger
Moderator (Firma: Titel) Persönliche Seite #3680081
Lesenswert?

Anfäng schrieb:
> Oder muss man zusätzlich (außer passende CLK und Baud) noch etwas
> beachten und den Code erweitern?
Nein, das geht so. Nur die Pins müssen noch zugeorndet werden.

> Es müsste doch ausreichend sein, am Eval-Kit nur die UART/USB-Leitungen
> TXD, GND und 5V anzuschließen, um die Daten empfangen zu können?
> - Eval-Kit: DE0 nano
> - FTDI UART - USB - Kabel
Die Pegel passen da zusammen? Ist da irgendwo ein Pegelwandler 
dawischen?
Gast #3680115
Lesenswert?

Hallo,

wenn ich TX_Data direkt TX_Data <= "10101010"; zweisen möchte, bekomme 
ich den Fehler:

Error (10568): VHDL error at DCDC_UART_COM.vhd(57): can't write to 
interface object "TX_Data" of mode IN

Wie kann man hier eine korrekte Zuweisung durchführen?

Gruss
Moderator (Firma: Titel) Persönliche Seite #3680187
Lesenswert?

Anfäng schrieb:
> Wie kann man hier eine korrekte Zuweisung durchführen?
Wenn du innerhalb des RS232 Moduls etwas TX_Data zuweisen willst, dann 
musst du TX_Data aus der Port-Liste herausnehmen und als Signal 
deklarieren...

Oder andersrum: mein UART ist nicht geeignet als Top-Level-Modul, das 
direkt an IO-Pins angeschlossen wird. Es ist eigentlich ein Modul, das 
als Komponente in dein Top-Level-Modul integriert und angesteuert 
wird. Und dieses Top-Level-Modul bekommt an seinen Ports Anschlüsse des 
FPGAs zugewiesen...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren