Forum: FPGA, VHDL & Co. Ethernet Verbindung zwischen FPGA und PC


von matzunami (Gast)


Lesenswert?

Hallo,

ich würde gerne eine Verbindung mit einem FPGA und einem PC über 
Ethernet herstellen. Hierzu hab ich mir die app1024 von Xilinx 
angeschaut und das referenz Design auf meinem Board implementiert 
(ML505).
Ich sehe nun im Terminalprogramm die beschriebene Ausgabe, kann aber 
keine Verbindung zum Board aufbauen. Wenn ich im command window 
ipconfig/all eingebe wird mir folgendes angezeigt:
IP-Adresse: 168.254.72.76
Subnetzmaske: 255.255.0.0
Standardgatway: nix

-> ist es richtig das das Board hier nicht auftaucht???

Dementsprechent hab ich in der main.c folgendes eingetragen:
IP4_ADDR(&ipaddr,  168, 254,  72,  77);
IP4_ADDR(&netmask, 255, 255,   0,   0);
IP4_ADDR(&gw,      168, 254,  72,   1);

Die MAC Adresse hab ich unverändert gelassen. Ist dies korrekt, oder 
müsste der MAC nicht eine bestimmte MAC adresse haben. Wenn ja wie komm 
ich an diese?

Wenn ich nun über CMD window versuche den Echo Server zu testen kommt 
folgender fehler.

telnet 168.254.72.77 1024
Verbindungsaufbau zu 168.254.72.77...Es konnte keine Verbindung mit dem 
Host her
gestellt werden, auf Port 1024: Verbinden fehlgeschlagen

Hat eventuell noch jemand eine Idee, was ich falsch mache?

Danke
matzunami

von A. M. (am85)


Lesenswert?

matzunami schrieb:
> Hierzu hab ich mir die app1024 von Xilinx
> angeschaut und das referenz Design auf meinem Board implementiert

Nur fürs Protokoll, du wirst wohl die xapp1026 meinen.

matzunami schrieb:
> ipconfig/all eingebe wird mir folgendes angezeigt:
> IP-Adresse: 168.254.72.76
> Subnetzmaske: 255.255.0.0
> Standardgatway: nix

Du hast deinem PC wohl keine IP zugewiesen, denn das scheint eine 
Standardadresse zu sein, die Windows setzt, wenn die Netzwerkkarte noch 
nicht konfiguriert und auch kein DHCP Server im Netz gefunden wurde. 
Änder die IP lieber auf z.B. 192.168.0.xxx, damit du auf der sicheren 
Seite bist. Gib deinem Board eine entsprechende IP aus dem selben Netz.

matzunami schrieb:
> -> ist es richtig das das Board hier nicht auftaucht???

Mit dem Kommando "ipconfig \all" wird nur die Konfiguration der 
Netzwerkinterfaces angezeigt, die in deinem PC sind und nicht, davon, 
was noch so alles im Netz rumschwirrt.

matzunami schrieb:
> Dementsprechent hab ich in der main.c folgendes eingetragen:
> IP4_ADDR(&ipaddr,  168, 254,  72,  77);
> IP4_ADDR(&netmask, 255, 255,   0,   0);
> IP4_ADDR(&gw,      168, 254,  72,   1);

Wie gesagt, beweg dich lieber im 192.168.0.xxx'er Netz mit der passenden 
Netzmask 255.255.255.0.

matzunami schrieb:
> Die MAC Adresse hab ich unverändert gelassen. Ist dies korrekt, oder
> müsste der MAC nicht eine bestimmte MAC adresse haben. Wenn ja wie komm
> ich an diese?

In der nähe der RJ45'er Netzwerkbuchsen müsste ein Aufkleber sein, auf 
dem die MAC Adresse drauf steht. Die solltest du natürlich auch 
benutzen.

matzunami schrieb:
> telnet 168.254.72.77 1024
> Verbindungsaufbau zu 168.254.72.77...Es konnte keine Verbindung mit dem
> Host her
> gestellt werden, auf Port 1024: Verbinden fehlgeschlagen
>
> Hat eventuell noch jemand eine Idee, was ich falsch mache?

Vermutlich ists eine Folge der oben genannten Dinge. Zudem ist die 
Frage, obs auch der richtige Port ist? Sollte der so in der 
Dokumentation und vorallem auch im Code stehen, dann ists natürlich 
richtig.

von matzunami (Gast)


Lesenswert?

Danke für die Antwort. Ich hab mit wireshark mein Datentransfer mal 
beobachtet und bemerkt, dass ich bei der IP Adresse einen Fehler gemacht 
habe. Diese ist nicht 168.254.72.76 sondern 169.254.72.76 und dies muss 
auch beim Standardgateway eingetragen werden.
Es funktioniert jetzt alles :)

Gruß
matzunammi

von matzunami (Gast)


Lesenswert?

Hallo,

nach dem ich den kompletten Programmaufbau durchgeschaut hab, muss ich 
feststellen das es doch etwas komplizierter ist als ich gehofft habe. 
Mein Ziel ist es Daten aus dem Speicher auszulesen und über UDP oder TCP 
an einen Rechner zu schicken. Ich habe gehofft das ich an hand des 
Echo_Server Beispiels funktionen finde die mir die Übertragung über TCP 
ermöglichen (sowas wie TCP_Send oder so). Das Programm schickt ja auch 
die empfangenen Daten zurück, ich habe da allerdings noch nicht ganz den 
durchblick, wo dies genau geschieht.
Eventuell kann mir da vielleicht noch jemand unter die Arme greifen und 
mir etwas behilflich sein. Wäre sehr dankbar.

Gruß
matzunami

von A. M. (am85)


Lesenswert?

Mir ging/geht es da nicht anders als dir, weswegen ich weg von der RAW 
hin zur Socket API gegangen bin, weil die doch deutlich intuitiver ist. 
Bezogen auf die Durchsatzrate ist sie natürlich schwächer als die RAW 
API (Meine Beispielkonfiguration bei Fast Ethernet: 66Mbit/s mit der 
RAW, 26 Mbit/s mit der Socket API) aber wenn du nur reine 
Controllinginformationen verschicken willst und nicht irgendwelche 
megagroßen Datenblöcke, dann wäre es eine Überlegung wert, die API zu 
wechseln.

von matzunami (Gast)


Lesenswert?

Ich hab mit dem Xilinx Kernel noch keine Erfahrungen gemacht und soll 
die Schnittstelle auch in ein bestehendes Projekt integrieren, was 
ebenfals ohne den Kernel läuft. Dementsprechent weiß ich nicht wie 
sinvoll es ist auf die Socket Variante umzusteigen, die diesen ja 
benötigt??? Existiert nicht irgend ein Dokument, wie die "Xilinx Device 
Drivers Documentation", in der ich alle mir zur Verfügung stehenden 
Funktionen mit einer kurzen Beschreibung finde? Oder ein besser 
erläutertes Beispiel?

von A. M. (am85)


Lesenswert?

Ok, wenn das ganze komplett ohne Xilkernel laufen soll, dann wirst du an 
der RAW API nicht vorbei kommen. Eine kleine Übersicht, über die zur 
Verfügung stehenden Funktionen findest du in der "rawapi.txt", die du, 
zumindest in der EDK 10.1 im Verzeichnis 
\EDK\sw\ThirdParty\sw_services\lwip130_v1_00_a\src\lwip-1.3.0\doc 
findest. Ansonsten kannst du auch nochmal schaun, ob dir das hier hilft 
http://lwip.wikia.com/wiki/Raw/TCP

von matzunami (Gast)


Lesenswert?

ok ich nehm mal an das ich sicher noch ein paar Fragen dies bezüglich 
hab, aber ich werd mir das noch mal alles anschaun und mal sehn, ob ich 
was zu stande bekomme, schon mal vielen Dank für die Hilfe

von D. I. (Gast)


Lesenswert?

Wäre es für deine Anwendungen ausreichend komplett auf den TCP Krempel 
zu verzichten und einfach RAW kommunikation zu machen?

Ich habe hier TEMAC mit LocalLink über SGMII am laufen und baue mir die 
Pakete manuell zusammen sowohl auf Software als auch auf Hardwareseite, 
das funktioniert ganz gut

von matzunami (Gast)


Lesenswert?

ich würde die TCP funktionalität schon gerne nutzen

von matzunami (Gast)


Lesenswert?

und verstehen :)

von A. M. (am85)


Lesenswert?

Sollte das mit der RAW API doch all zu nervig und zeitintensiv werden, 
dann ist es vielleicht doch eine Überlegung wert mit dem Xilkernel. Den 
bindest du über eine #include- Anweisung und einen Funktionsaufruf in 
deinen bestehenden Code ein und kannst sonst arbeiten, wie in einer 
standalone Anwendung. Wie gesagt, ich würde ihn mir zur Not einfach mal 
anschaun und wenn du eh schon das EDK hast, dann kannst du den auch 
problem- und kostenlos nutzen. Aber das ist natürlich alles 
projektspezifisch, ob man das will/braucht/nutzen kann.

von matzunami (Gast)


Lesenswert?

Wo kann ich sehen wie genau struct tcp_pcb deklariert ist, um meine 
empfangenen Daten auslesen zu können? Die müssten ja dort abgespeichert 
sein oder?

von matzunami (Gast)


Lesenswert?

ja Danke ich will noch nicht aufgeben, aber wenn ichs absolut nicht 
hinbekomme dann schau ich mir das auch auf jeden Fall an...
Wenn ich etwas empfange wird ja eine Callback Fkt. aufgerufen 
(recv_callback), in der ein struct übergeben wird -> struct tcp_pcb 
*tpcb. In diesem müssten doch meine empfangenen Daten stehen, die ich 
doch in den Speicher schreiben kann oder was auch immer... seh ich das 
richtig?

von floGzmo (Gast)


Lesenswert?

Kuck dir das Telnet Echo Server Example im SDK an. Da wird eine TCP 
Verbindung auf den Port 7 (Telnet Echo Port) gebunden. Und in der 
Callback Funktion err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
                               struct pbuf *p, err_t err)
wird auf die Daten (payload) so zugegriffen: p->payload und p->len. Das 
Paket ist meiner Meinung nach also im pbuf p. tcp_pcb ist nur die 
Session?

von Purzel H. (hacky)


Lesenswert?

>ich würde die TCP funktionalität schon gerne nutzen
>und verstehen :)

Also. TCP bedeutet eine gesicherte Verbindung. Dh  man kann ein Paket 
senden, viel groesser wie die Blockgroesse, dabei koennen die 
Teilpackete auf verschiedenen Wegen transportiert werden und das 
Protokoll setzt die Bloecke wieder zusammen, alles is CRC geschuetzt, 
mit Retries, Acknowledge und so. Dh die Daten die ankommen stimmen.

Alternativ kann man UDP verwenden. Da fallen die Retries weg. Die 
Verbindung ist nicht gesichert. Der CRC ist zwar da, wird gerechnet, 
aber die Neuanforderung muss man selbst machen. Dadurch ist UDP viel 
schneller.

Eine Datenuebertragung macht man in TCP, eine Musikuebertragung mit UDP.

von matzunami (Gast)


Lesenswert?

ok danke... das mit dem pbuf hab ich mitlerweile auch gefunden aber da 
meine c Kenntnisse nicht die besten sind... wie kann ich da drauf zu 
greifen?
1
unsigned char x;
2
x = p->payload

funktioniert nicht? Das struct sieht ja volgendermaßen aus:
1
struct pbuf {
2
void *payload;
3
...
4
...
5
}

müsste da mein pointer p nicht auf das erste Byte zeigen und in x 
speichern?

Wie gesagt c ist bei mir schon ne weile her...

von floGzmo (Gast)


Lesenswert?

*p ist ein Pointer vom Typ void. Damit ist das ein Typenloser Pointer 
der nun in diesem Fall auf den Anfang der Nutzdaten zeigt. Wieviele Byte 
Nutzdaten da gekommen sind steht in p->len.

Ich vergleiche die angekommenen Daten z.b. Byte für Byte auf ein 
MagicWord. Wurde das Zauberwort erhalten, beendet sich der Server:
1
unsigned int count=0;
2
    for(i = 0; i < (p->len); i++) // compare each byte
3
    {
4
      if(pcompare_data[i] == ((char *)(p->payload))[i])
5
      {
6
        count++; // do_something();
7
      }
8
...

Hier siehst du wie in der if Abfrage der void Pointer implizit 
Typkonvertiert wird um ihn mit einem Chararray vergleichen zu können. 
Wie groß das Chararray sein muss? Gute Frage, selber implementieren. Ich 
nehme an es gibt nicht etwas wie "msg = malloc(size);". Wenn du 
voraussagen kannst dass p->len nie größer als xy Bytes ist, dann kannst 
dir ja entsprechend einen char buffer[xy]; im voraus erstellen.

Mahlzeit

von matzunami (Gast)


Lesenswert?

vielen dank

von matzunami (Gast)


Lesenswert?

So ich habs fast alles am laufen. Aber eine Frage hät ich noch. Wenn ich 
größere Datenmengen verschicken will (einige MB), muss ich mir diese 
selbst zerteilen? Mit der funktion:
1
err_t tcp_write(struct tcp_pcb * pcb, void * dataptr, u16_t len,
2
                 u8_t apiflags)
kann ich ja nur Daten mit der maximalen länge von der größe meines 
TCP_SND_BUF verschiecken. Muss ich somit bei einer größeren Datenmänge 
diese Funktion mehrmals aufrufen???

Gruß matzunami

von A. M. (am85)


Lesenswert?

Schau dir mal auf 
http://magazin.c-plusplus.de/artikel/Sockets%20und%20das%20HTTP-Protokoll 
die Funktion SendAll unter Punkt 5.2 an. Das sollte hier auch möglich 
sein.

von matzunami (Gast)


Lesenswert?

Meine Fkt. tcp_write gibt mir aber nicht die Zahl der gesendeten Bytes 
zurück. Und wenn "len" größer wie der TCP_SND_BUF wird, wird garnix mehr 
gesendet (ich nehm mal an dann gibt die Funktion ERR_MEM zurück).

von matzunami (Gast)


Lesenswert?

Hallo ich bins noch mal... meine Ethernet Verbindung läuft "fast" wie 
gewünscht. Ich habe noch ein Problem bei dem ich noch hoffentlich etwas 
Hilfe bekomme. Und zwar:
Wenn ich mit dem Xilinx Beispielprogramm (aus xapp1024) ein iperf Test 
laufen lasse, übertrage ich Daten mit einer Geschwindigkeit von über 
100Mbits/sec (in beide Richtungen). Nach dem ich das Programm für meine 
Zwecke leicht abgeändert habe übertrage ich meine 100kByte (meine 
Nutzdaten) in 21 sekunden??? Warum dauert das so lange? Wenn ich mir mit 
WireShark den Datentransfer anschaue, sehe ich, dass der PC ja jedes 
Packet mit einem ACK bestädigt. Dieses Bestätigen dauert bei dem Xilinx 
Beispielprogramm wenige µs (wenn es 100µs sind, sind es viel). Bei 
meiner Applikation dauert es ganze 300ms bis ich mein ACK empfange. 
Woher kommen diese unterschiede? Da ich mein nächstes Datenpaket (anders 
wie beim Xilinx Programm) erst nach dem Empfang des ACK's los schicke 
ist mir auch klar warum das alles so lange dauert, ich verstehe nur 
nicht warum das ACK in meinem Fall so spät kommt???

wäre sehr dankbar, wenn einer eine Idee hätte woran es liegen könnte

Gruß
matzunami

von matzunami (Gast)


Lesenswert?

ich habe festgestellt, dass wenn ich es so mache wie Xilinx und einfach 
den Buffer mit meinen Daten voll stopfe, ich auf die gewünschte 
Datenrate komme. Mir ist aber nicht klar warum die Übertragung dann so 
wesentlich schneller ist? Zuerst hab ich auf das ACK gewartet, was mir 
auch meldet wieviel Bytes erfolgreich ankamen hab um diese Zahl meine 
Adresse erhöht und den nächsten Frame gesendet. Das scheint eine 
schlechte vorgehensweise zu sein.

von Rone (Gast)


Lesenswert?

Hallo,

Ich bin recht neu in der fpga welt. habe ein einfaches sender/empfänger 
system implementiert und würde gerne daten von dem empfänger fpga auf 
den pc übertragen. ich habe allerdings ein virtex 4 board. in der 
xapp1026 steht ausdrücklich für ML oder Sparten Boards. Gibts es 
ähnliches Dokument oder Hilfe für Ethernet Übertragung zwischen PC und 
Virtex 4 Boards?

Danke und Grüße,
Rone

von A. M. (am85)


Lesenswert?

ML ist nur ein Namenszusatz und wird in der Regel für Boards mit Virtex 
Chip benutzt. Das Xapp1026 ist grundsätzlich für alle Xilinx Boards 
brauchbar.

von Rone (Gast)


Lesenswert?

Danke für die schnelle Antwort!

von mirkjo (Gast)


Lesenswert?

matzunami schrieb:
> Zuerst hab ich auf das ACK gewartet, was mir
> auch meldet wieviel Bytes erfolgreich ankamen hab um diese Zahl meine
> Adresse erhöht und den nächsten Frame gesendet

Das Tcp protokoll ist darauf ausgelegt, deinen Datenstrom in Pakete 
aufzuteilen, die quasi Parallel unterwegs sind, je nach Netztopologie 
können zwei Pakete einen völlig anderen Weg nehmen und damit sie am Ende 
richtig zusammengesetzt werden, sind sie nummeriert. Die Pakete werden 
quasi bündelweise verschickt und die ACKs kommen ebenso in Bündeln 
zurück. Du musst theoretisch jedes Frame, was du schickst solange 
aufheben, bis du weist, dass es sicher angekommen ist, gleichzeitig aber 
auch schon neue losschicken, um den gewünschten Durchsatz zu kommen, 
also brauchst du ne Menge Ram, damit du ein fehlerhaftes Frame evtl 
nochmal senden kannst. Oder du scheisst einfach drauf, schliesslich 
werden die Meisten Fehler per CRC korrigiert und sobald dein Paket mal 
in einem Switch gelandet ist, ist es meistens auch sicher aufgehoben.

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.