Skocz do zawartości

Komunikacja bezpośrednia między PC, a ESP32 i układem ethernet W5500


Chev

Pomocna odpowiedź

Dzień dobry,

 

Od kilku dni próbuje nawiązać komunikację pomiędzy komputerem, a układem ESP32 (Helcat LoRa v2) poprzez zewnętrzną płytkę z układem W5500, komunikującą się poprzez SPI z ESP.

Buduje system, którym chciałbym sterować z poziomu komputera, a do poprawnego działania potrzebna mi jest duża przepustowość, więc zdecydowałem się na UDP poprzez ethernet, bo w moim przypadku WiFi się nie sprawdzi.

Jak to mam zwyczaj robić na początku, testuje nową płytkę poprzez wgranie exampla i sprawdzam czy wszystko działa prawidłowo. Test jest prosty. Wysyłam sobie pakiet używając programu PacketSender i czytam na ESP, proste. Niestety, ale nie mogę nawiązać komunikacji między dwoma urządzeniami i byłbym wdzięczny, gdyby ktoś spojrzał mi na ręce i zasugerował co robię źle. Więc kolejno:

1. Programuje sobie ESP, używając exampla:

#include <SPI.h>        
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <pins_arduino.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {  
    0x48,0x55,0x19,0xee,0xbf,0xa2
 };
IPAddress ip(192,168,1,2);
IPAddress mask(255,255,255,0);

unsigned int localPort = 8888;      // local port to listen on

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

void setup() {
  // start the Ethernet and UDP:

  Ethernet.init(SS);
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
  
  Serial.begin(115200);
  
  pinMode(LED, OUTPUT);
  Serial.println("hello");
}

void loop() {


  int packetSize = Udp.parsePacket();
  if(packetSize)
  {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remote = Udp.remoteIP();
    for (int i =0; i < 4; i++)
    {
      Serial.print(remote[i], DEC);
      if (i < 3)
      {
        Serial.print(".");
      }
    }
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBuffer
    Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
    Serial.println("Contents:");
    Serial.println(packetBuffer);
}
}

2. Otwieram port UDP w Windows 10 dla pakietów przychodzących i wychodzacych w firewallu. Otwieram port 8888 dla wszystkich aktywnych sieci (publicznych i prywatnych)

3. Konfiguruje Ethernet na statyczny adres IP (w trzecim oktecie wpisuje 1, bo 0 to moja sieć WiFi):

ip: 192.168.1.1

maska: 255.255.255.0

bramka: 192.168.1.2

dns: 192.168.1.2

Zmieniłem jeszcze w ustawieniach karty sieciowej, aby wymusić szybkość łącza z 1Gbps na 10Mbps, dla pewności.

4. W PacketSender wpisuje mój adres do ESP: 192.168.1.2, port 8888, UDP i jakąś tam wiadomość. 

Według mnie, po wysłaniu wiadomości, serial monitor z ESP powinien wydrukować zawartość pakietu, który otrzymał, a tego nie robi.

 

Płytkę mam podłączoną poprawnie, sprawdzałem kilka razy. Nie jest to też problem z zasilaniem, bo moduł ethernetu zasilam z zewnętrznego power banku. Połączenie między PC, a ESP32 realizuje przez kabel krosowy.

Byłbym wdzięczny za jakiś pomysł, bo już na prawdę nie wiem co jest grane.

 

1.JPG

eth.JPG

eth22.JPG

packet.JPG

Link do komentarza
Share on other sites

(edytowany)

Wprawdzie nie eksperymentowałem z Ethernetem i ESP ale pytanie czy ta karta sieciowa w ogóle działa? Może spróbuj to sprawdzić. W swoim programie nie sprawdzasz statusu karty więc czy jesteś pewny, że w ogóle działa? Tak na marginesie to brak komunikacji po skrętce może być spowodowany złym kablem (prosty, krosowany zależnie co z czym jest połączone), problemami z wtyczką ..... itd. Podsumowując najpierw bym się upewnił, że ethernet działa, a później zająłbym się odbiorem danych. Ekran z właściwościami połączenia Windows sugeruje, że fizycznego połączenia brak.

Edytowano przez Belferek
Link do komentarza
Share on other sites

(edytowany)

Sytuacja jest bardzo ciekawa. Zrobiłem to zaraz jak napisałem ten post czyli w setupie po inicjalizacji ETH wywołałem metodę Serial.println(String(Ethernet. hardwareStatus()));, która zwraca mi 0, czyli no device. 

Rozpocząłem zatem śledztwo co jest nie tak. Jak wejdziemy sobie w ciało metody Ethernet.init() to zobaczymy tam takie coś:

void EthernetClass::begin(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet)
{	Serial.println("Tp7");
	if (W5100.init() == 0) return;
	Serial.println("Tp8");
	
	SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
	W5100.setMACAddress(mac);
	W5100.setIPAddress(ip.raw_address());
	W5100.setGatewayIp(gateway.raw_address());
	W5100.setSubnetMask(subnet.raw_address());
	SPI.endTransaction();
	_dnsServerAddress = dns;
}

Te TestPointy są moje, żebym zobaczył, gdzie metoda kończy swoje działanie. Okazuje się, że 5100.init() zwraca 0. Wchodzimy zatem do tej metody.

uint8_t W5100Class::init(void)
{
	static bool initialized = false;
	uint8_t i;

	if (initialized) return 1;

	// Many Ethernet shields have a CAT811 or similar reset chip
	// connected to W5100 or W5200 chips.  The W5200 will not work at
	// all, and may even drive its MISO pin, until given an active low
	// reset pulse!  The CAT811 has a 240 ms typical pulse length, and
	// a 400 ms worst case maximum pulse length.  MAX811 has a worst
	// case maximum 560 ms pulse length.  This delay is meant to wait
	// until the reset pulse is ended.  If your hardware has a shorter
	// reset time, this can be edited or removed.
	delay(560);
	Serial.println("w5100 init");
	SPI.begin(SCK, MISO, MOSI, ss_pin);
	initSS();
	resetSS();
	SPI.beginTransaction(SPI_ETHERNET_SETTINGS);

	// Attempt W5200 detection first, because W5200 does not properly
	// reset its SPI state when CS goes high (inactive).  Communication
	// from detecting the other chips can leave the W5200 in a state
	// where it won't recover, unless given a reset pulse.
	if (isW5200()) {
		CH_BASE_MSB = 0x40;
#ifdef ETHERNET_LARGE_BUFFERS
#if MAX_SOCK_NUM <= 1
		SSIZE = 16384;
#elif MAX_SOCK_NUM <= 2
		SSIZE = 8192;
#elif MAX_SOCK_NUM <= 4
		SSIZE = 4096;
#else
		SSIZE = 2048;
#endif
		SMASK = SSIZE - 1;
#endif
		for (i=0; i<MAX_SOCK_NUM; i++) {
			writeSnRX_SIZE(i, SSIZE >> 10);
			writeSnTX_SIZE(i, SSIZE >> 10);
		}
		for (; i<8; i++) {
			writeSnRX_SIZE(i, 0);
			writeSnTX_SIZE(i, 0);
		}
	// Try W5500 next.  WIZnet finally seems to have implemented
	// SPI well with this chip.  It appears to be very resilient,
	// so try it after the fragile W5200
	} else if (isW5500()) {
		CH_BASE_MSB = 0x10;
#ifdef ETHERNET_LARGE_BUFFERS
#if MAX_SOCK_NUM <= 1
		SSIZE = 16384;
#elif MAX_SOCK_NUM <= 2
		SSIZE = 8192;
#elif MAX_SOCK_NUM <= 4
		SSIZE = 4096;
#else
		SSIZE = 2048;
#endif
		SMASK = SSIZE - 1;
		for (i=0; i<MAX_SOCK_NUM; i++) {
			writeSnRX_SIZE(i, SSIZE >> 10);
			writeSnTX_SIZE(i, SSIZE >> 10);
		}
		for (; i<8; i++) {
			writeSnRX_SIZE(i, 0);
			writeSnTX_SIZE(i, 0);
		}
#endif
	// Try W5100 last.  This simple chip uses fixed 4 byte frames
	// for every 8 bit access.  Terribly inefficient, but so simple
	// it recovers from "hearing" unsuccessful W5100 or W5200
	// communication.  W5100 is also the only chip without a VERSIONR
	// register for identification, so we check this last.
	} else if (isW5100()) {
		CH_BASE_MSB = 0x04;
#ifdef ETHERNET_LARGE_BUFFERS
#if MAX_SOCK_NUM <= 1
		SSIZE = 8192;
		writeTMSR(0x03);
		writeRMSR(0x03);
#elif MAX_SOCK_NUM <= 2
		SSIZE = 4096;
		writeTMSR(0x0A);
		writeRMSR(0x0A);
#else
		SSIZE = 2048;
		writeTMSR(0x55);
		writeRMSR(0x55);
#endif
		SMASK = SSIZE - 1;
#else
		writeTMSR(0x55);
		writeRMSR(0x55);
#endif
	// No hardware seems to be present.  Or it could be a W5200
	// that's heard other SPI communication if its chip select
	// pin wasn't high when a SD card or other SPI chip was used.
	} else {
		//Serial.println("no chip :-(");
		chip = 0;
		SPI.endTransaction();
		return 0; // no known chip is responding :-(
	}
	SPI.endTransaction();
	initialized = true;
	return 1; // successful init
}

W inicjalizacji SPI ustawiłem sobie piny tak jak powinny być ustawione. CS u mnie to pin 17, ponieważ na dedykowanym pinie SS jest przypięty kontroler LoRa. 

Dalej nic ciekawego się nie dzieje, aż do momentu gdzie dochodzimy do instrukcji warunkowych. Mamy kilka instrukcji (isW5xxx). Widziemy, że jak żadna z nich nie jest prawdą to zostanie zwrócone 0 czyli no device. Tutaj znajduje swój problem. Ja używam W5500 więc wchodzimy sobie do tej metody.

uint8_t W5100Class::isW5500(void)
{
	chip = 55;
	Serial.println("w5100.cpp: detect W5500 chip");
	if (!softReset()) return 0;
	writeMR(0x08);
  	if (readMR() != 0x08) return 0;
	writeMR(0x10);
	if (readMR() != 0x10) return 0;
	writeMR(0x00);
	if (readMR() != 0x00) return 0;

	int ver = readVERSIONR_W5500();
	Serial.print("version=");
	Serial.println(ver);
	if (ver != 4) return 0;
	Serial.println("chip is W5500");
	return 1;
}

I to jest najciekawsza część przygody. Na początku wklejam przypis z dokumentacji W5500 dotyczący wersji kontrolera

Cytat

VERSIONR (W5500 Chip Version Register) [R] [0x0039] [0x04] VERSIONR always indicates the W5500 version as 0x04.

Czyli czytając rejestr 0x0039, wersja kontrolera W5500 powinna zawsze zwracać 0x04.

Dopisałem sobie kilka printów, żeby zobaczyć co tak na prawdę czytam z rejestrów. Kod wygląda tak:

uint8_t W5100Class::isW5500(void)
{
	chip = 55;
	Serial.println("w5100.cpp: detect W5500 chip");
	if (!softReset()) 
	{
		Serial.println("softReset: -true");
		return 0;
	}
	else
	{
		Serial.println("softReset: -false");
	}

	writeMR(0x08);
	if (readMR() != 0x08) 
	{
		Serial.println("readMR(0x08-true): " + String(readMR()));
		return 0;
	}
	else
	{
		Serial.println("readMR(0x08-false): " + String(readMR()));
	}
	
	writeMR(0x10);
	if (readMR() != 0x10)
	{
		Serial.println("readMR(0x10-true): " + String(readMR()));
		return 0;
	}
	else
	{
		Serial.println("readMR(0x10-false): " + String(readMR()));
	}

	writeMR(0x00);
	if (readMR() != 0x00)
	{
		Serial.println("readMR(0x00-true): " + String(readMR()));
		return 0;
	}
	else
	{
		Serial.println("readMR(0x00-false): " + String(readMR()));
	}	

	int ver = readVERSIONR_W5500();
	Serial.print("version=");
	Serial.println(ver);
	if (ver != 4) return 0;
	Serial.println("chip is W5500");
	return 1;
}

Jaki wynik?

softReset: -false
readMR(0x08-false): 4

Czytam decymalnie, więc dostałem 0x04. Jak skonwertujemy wartość 0x08 na binarny to mamy 0000 1000, natomiast 0x04 to 0000 01000. Mamy 1 bit przesunięty w prawo... Zmieniam zatem te warunki, dzieląc każdą wartość przez 2 (czyli np. (readMR() != 0x10 / 2), żeby przesunąć o 1 bit w prawo. 

Co dostaję?

softReset: -false
readMR(0x08-false): 4
readMR(0x10-false): 8
readMR(0x00-false): 0
version=2

Ojej, udało się. Dochodzimy do wersji. Mój test zwraca 0x02, a powinno być 0x04. Znowu 1 bit przesunięty w prawo... Zmieniam warunek, if (ver != 4 / 2) return 0;

Wynik

softReset: -false
readMR(0x08-false): 4
readMR(0x10-false): 8
readMR(0x00-false): 0
version=2
chip is W5500
Tp8
hw status: 3

hw status 3 oznacza, że wykryto W5500. W windowsie widzę, że pojawiła się sieć, autonegocjacja wybrała sobie szybkość 100Mbits. Wszystko fajnie, ale dalej nie otrzymuje danych po UDP.

Patrzę zatem czy poprawnie zapisuje IP i maskę do W5500. Napisałem sobie do tego taki kod:

byte mac[] = {  
    0x48,0x55,0x19,0xee,0xbf,0xa2
 };

IPAddress mask(255,255,255,0);
IPAddress ip(192,168,2,1);

unsigned int localPort = 7575;      // local port to listen on

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

void setup() {
  // start the Ethernet and UDP:
  Serial.begin(115200);
  pinMode(SS, OUTPUT);
  digitalWrite(SS, HIGH); // tutaj wyłączam LoRa
  
  Ethernet.init(13);
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
  
  Serial.println("local ip: " + String(ip[0]) + "."  + String(ip[1])  + "."  + String(ip[2])  + "."  + String(ip[3])); // tutaj sprawdzam czy czytam poprawnie oktety, które są zapisane w ESP
  
  pinMode(LED, OUTPUT);
  Serial.println("hello");
  Serial.println("hw status: " + String(Ethernet. hardwareStatus())); // zwraca 3 czyli OK
  Serial.println("link: " + String(Ethernet.linkStatus())); // zwraca 1 czyli OK
  
  IPAddress ip_read = Ethernet.localIP();
  Serial.println("local ip: " + String(ip_read[0]) + "."  + String(ip_read[1])  + "."  + String(ip_read[2])  + "."  + String(ip_read[3])); // tutaj sprawdzam IP zapisane w W5500

  IPAddress mask_read = Ethernet.subnetMask();
  Serial.println("mask: " + String(mask_read[0]) + "."  + String(mask_read[1])  + "."  + String(mask_read[2])  + "."  + String(mask_read[3])); // tutaj sprawdzam maskę zapisaną w W5500
}

Wynik:

local ip: 192.168.2.2
hw status: 3
link: 1
local ip: 224.84.1.1
mask: 255.255.255.128

Wnioski:

Czytam adres z tablicy taki jaki zapisałem.

Dekoduje sobie IP na binarny:

       224                84                 1                 1

1110 0000 | 0101 0100 | 0000 0001 | 0000 0001

       192                168                 2                 2

1100 0000 | 1010 1000 | 0000 0010 | 0000 0010

Maska na końcu powinno być 0000 0000, a mam 1000 0000

Wygląda znowu, że wszystko jest przesunięte w prawo o 1 bit, ale zobaczmy na ping z poziomu windowsa:


C:\Users\mw>ping 192.168.2.2

Pinging 192.168.2.2 with 32 bytes of data:
Reply from 192.168.2.2: bytes=32 time<1ms TTL=128
Reply from 192.168.2.2: bytes=32 time<1ms TTL=128
Reply from 192.168.2.2: bytes=32 time=1ms TTL=128
Reply from 192.168.2.2: bytes=32 time<1ms TTL=128

Ping statistics for 192.168.2.2:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 1ms, Average = 0ms

C:\Users\tst>ping 224.84.1.1

Pinging 224.84.1.1 with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for 224.84.1.1:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

Szczerze to mam dość tej biblioteki. Wybrałem sobie arduino, bo miało być łatwo, szybko i prosto, a wychodzi na to, że niekoniecznie tak jest. Napisałem ten post, bo pewnie wiele osób nigdy nie debugowało w ten sposób kodu, więc z taką intencją go napisałem. Sam dochodzę do wniosków, że biblioteka Ethernet jest błędnie napisana ( a przynajmniej wersja 2.0.2 z której korzystam). Nie widzę w którym miejscu te bity mogłyby się przesuwać. Może tylko odczyt jest zły? Ciężko mi powiedzieć, bo wysyłając pod adres 192.168.2.2  po porcie 7575 nie czytam informacji z ESP. A widzę, że odbieram i nadaje pakiety z poziomu PC, więc zakładam, że konfiguracja przebiegła poprawnie, ale pewny w 100% nie jestem. Zapisuje raczej do dobrych rejestrów, bo wersję kontrolera czytamy z rejestru 0x0039 (czyli to 0x02), więc zakładam, że adres rejestru jest brany poprawnie. Gorzej z tymi danymi, które tam zapisuje do tych rejestrów.

Może ktoś z forumowiczów miałby jakiś pomysł jak to naprawić?

Edytowano przez Chev
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.