EthernetUDP Multiple Sockets

Status
Not open for further replies.

capricorn one

Well-known member
Hi there, have a few questions the UDP side of the Ethernet library. I need to send data using UDP messages to multiple IP addresses, but not the same data to each. The data doesn't have to be sent at the same time, but it does need to go out fast. The problem I'm running into is a delay between sending messages when using the same socket, or running out of sockets if I create multiple objects. I have about 6 devices that I'll be sending data to (not receiving, just sending), but after the fourth socket the program seizes up. Some hardware things, I'm using a teensy 3.1, with an audio shield, and the WIZ820io ethernet module (which uses the W5200 chip). So here's my list of questions.

1. How many sockets are used when creating a EthernetUDP obect, 1 or 2? I don't know enough about this stuff, but it seems like if you had a listening port and a sending port you would need two sockets?

2. If the answer above is 1, does the current Ethernet library not support the 8 sockets available on the W5200 chip? (In the W5100.h file, MAX_SOCK_NUM is defined as 4, I don't see where that changes to 8 for W5200.

3. Really, my main question which would resolve having to create so many UDP objects, why is there a long delay when sending messages from the same socket to different IP addresses? If I use two sockets, and have each one send to different IP addresses, I get no delay. But if I change the destination IP when creating the new packet, it hangs every time. Is this a problem with the library? Or the chip? Or is this unavoidable..

Sorry for the long post, thanks in advance anyone that can help me out!
 
If I recall correctly, the W5200 supports up to 8 sockets, IF the microprocessor side support code configures the W5200's memory for 8, not fewer. There are 8 for transmit and 8 for receive, with a standard MTU size. The W5100 had half this many.

One socket should be created for one instance of the UDP protocol:socket combination. So up to 8 could be concurrently active, if the MCU side did implement for 8.

The delay sounds like a library problem... you are not closing the socket. You should wait until the first packet has been sent before sending another on the same socket. If you dare, you can put two half-MTU sized packets on the socket and the W5200 will deal with that. But in my past work with the W5100, I normally do streaming and hide from the application the boundaries of packets.

If the library still has 4 sockets, sounds like it was a quick and dirty adaptation for the more capable W5200.

You should need only one UDP protocol instance (object) per socket - or perhaps they have one for receiving and one for transmitting. I haven't looked at that library.

Probably not a chip problem, as I used UDP on the 5100 and it was fine with my driver which was not the library at question. The 5200 is essentially the same code on the Wiznet chip with more RAM.
My driver relied on the per socket buffer for TX and buffer for RX, independently.
 
Thanks Steve! So, I should've mentioned I guess that I'm using Teensyduino 1.20 rc6 (latest release). I tried using the supplied code from Wiznet for the W5200, but it won't compile with the teensyduino code. It seems like the support for the W5200 chip is mostly there, but missing the extra 4 sockets. I'm curious though if maybe you have more insight into the delay problem? Here's a code example that creates a delay in between messages:

Code:
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h> 

byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x6E, 0x44 };

IPAddress ip(192, 168, 0, 105);
IPAddress ipONE(192, 168, 0, 110);
IPAddress ipTWO(192, 168, 0, 111);

unsigned int portONE = 8000;
unsigned int portTWO = 8001;

EthernetUDP udp;

void setup() {
  Ethernet.begin(mac,ip);
  udp.begin(8080);
}


void loop() {

    udp.beginPacket(ipONE,portONE);
    udp.write(mac,6);
    udp.endPacket();


    udp.beginPacket(ipTWO,portTWO);
    udp.write(mac,6);
    udp.endPacket();

}
Should I be calling udp.stop() after endPacket()? Then I would have to call udp.begin() again as well I think... Any thoughts? Suggestions? Maybe is there another UDP library I could use that would make this run smoother?
 
Last edited:
Can't help with the delay problem, but you are using the correct Library. IIRC The limitation to 4 sockets was a tradeoff to have more buffer memory, but as stevech said, you should not need to have multiple ports open.
You can also double the speed of the SPI bus from 12MHz to 24MHz by un-commenting this line:

Code:
 //   SPIFIFO.begin(W5200_SS_PIN, SPI_CLOCK_24MHz);  // W5200 is 33 MHz max

line in the Ethernet library in utility/w5100.cpp.
 
Last edited:
The limitation to 4 sockets was a tradeoff to have more buffer memory
That makes total sense, I would do the same. I just wish I could change increase the max sockets number, but it doesn't compile if I do. However, it really seems like I shouldn't need to do that, hopefully I can figure out why this delay is happening. Something maybe worth mentioning is that this problem occurs the same way when using an arduino with the ethernet shield, so if it is a code thing, it's probably something leftover from the original arduino ethernet libraries.

As for the SPI, I would love to double the speed, but I don't see the line you mentioned, maybe it's from an older version of the code, is the line below the one to change? Maybe just repleace SPI_CLOCK_12MHz with SPI_CLOCK_24Mhz ?

Also, is there something I need to do to tell the teensy that I'm using the W5200 chip? or does it really figure that out itself?

Code:
#ifdef USE_SPIFIFO
  SPI.begin();
  SPIFIFO.begin(W5200_SS_PIN, SPI_CLOCK_12MHz);  // W5100 is 14 MHz max
#else
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  initSS();
#endif
 
That makes total sense, I would do the same. I just wish I could change increase the max sockets number, but it doesn't compile if I do. However, it really seems like I shouldn't need to do that, hopefully I can figure out why this delay is happening. Something maybe worth mentioning is that this problem occurs the same way when using an arduino with the ethernet shield, so if it is a code thing, it's probably something leftover from the original arduino ethernet libraries.

As for the SPI, I would love to double the speed, but I don't see the line you mentioned, maybe it's from an older version of the code, is the line below the one to change? Maybe just repleace SPI_CLOCK_12MHz with SPI_CLOCK_24Mhz ?

Also, is there something I need to do to tell the teensy that I'm using the W5200 chip? or does it really figure that out itself?

Code:
#ifdef USE_SPIFIFO
  SPI.begin();
  SPIFIFO.begin(W5200_SS_PIN, SPI_CLOCK_12MHz);  // W5100 is 14 MHz max
#else
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  initSS();
#endif

Yes , using SPI_CLOCK_24Mhz instead of SPI_CLOCK_12MHz should work. I am still working with Teensyduino 1.18 (I think) and have not had a chance to check if this works. But is works in TD 1.18 so there's good reason to believe it works for TD1.20. If you ever use a W5100 based Ethernet module, don't forget to switch it back to SPI_CLOCK_12MHz ;-)

The Ethernet library that ships with Teensyduino (since 1.18 IIRC) has an auto detect mechanism to be able to determine if you have a W5100 or W5200 based Ethernet board connected. So no need to define anywhere in your Sketch what Chip is connected.

Also you may want to search the forum (use Google to do that) for Ethernet speed tests. Certain UDP packet sizes are transferred quicker than others. THIS thread is generally educational in that aspect.
 
Last edited:
Seems to me that a buffer isn't needed for an idle socket. But you have to rely on new and malloc to do so.
 
Also you may want to search the forum (use Google to do that) for Ethernet speed tests. Certain UDP packet sizes are transferred quicker than others. THIS thread is generally educational in that aspect.

Thanks, good to know for the future!

So I was digging through the W5100 and Socket files in the Ethernet library, and I think I've found where the delay is happening. My understanding of the sendUDP function in socket.cpp is that it continually checks the interrupt register of the wiznet chip for the SENDOK interrupt. Once it catches that, it exits the function cleanly. However, if the TIMEOUT interrupt bit is found, it indicates a message has failed to send correctly.

Nothing wrong with that function as far as I can tell, matches the manual for the chip pretty closely. So my question is, why is it that I can send continuous messages over an IP/PORT socket at very high speed, but if I change the destination IP/PORT for the same socket, the messages fail to send occasionally, causing the timeout, and the delay in the program. It's not on every send that they fail though, I'll do try some tricks with my code to see if I can get more information out of this problem which might give me more insight into the source.
 
Annnddd as I think about the previous post a little more, I think maybe I am sending too many small packets as once, have to do a lot of rewriting to check, but I think that may be the answer. Thanks for everyone's help! I'll post the solution when I figure this out.
 
The 5100/5200 socket buffers on the chip itself, esp. the 5200, can hold more than one packet. And same for receiving.
If the packets are small compared to the MTU, lots of packets can be queued up on-chip.

So if you do streaming, you can put lots of bytes into the chip's socket buffer, times 4 or 8 sockets times 2 for TX/RX.
With care, one can rely on those on-chip buffers and with streaming, lessen the need for buffers in the Teensy 3.
 
Okay, so I've gone through this in pretty rigorous detail now, and it doesn't look like packet size, or SPI speed has anything to do with the issue. I reorganized my code to send larger packets, and even put some more time between sending packets, but it made no difference. So finally, I just made a simple sketch to test the issue outside of my program, here's what I found.

When sending data using UDP, if you change the IP address or port number between transmissions when using the same socket, there is a significant delay in waiting for the SENT_OK interrupt to trigger on the chip. Sometimes, this wait time can be close to 500ms! But at it's best, it's around 1-5ms. However, if you use two sockets (or two EthernetUDP objects). The wait time is around 128 micro seconds, so, like between 10-1000 times faster.

The delay occurs in the sendUDP function of socket.cpp in the while loop :

Code:
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )

That loops basically polls the chip over and over waiting for the SEND_OK bit to trigger in the socket interrupt.

So basically, my question is, does anyone have an idea why it would take so long just by changing the destination for the packet? Is there a setting in the chip that can be modified to not have this waiting? Anyways, here's my sample sketch that illustrates this problem :

Code:
#include <SPI.h>
#include <SD.h>
#include <Ethernet.h>
#include <EthernetUdp.h> 


byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x6E, 0x44};

IPAddress myIP(192, 168, 0, 105);

IPAddress destinationONE(192, 168, 0, 102);
IPAddress destinationTWO(192, 168, 0, 103);

unsigned int portONE = 8002;
unsigned int portTWO = 8004;

EthernetUDP UdpONE;
EthernetUDP UdpTWO;

uint8_t buffer[24];
uint8_t counter;

elapsedMicros transmissionTime;

void setup() {

  Ethernet.begin(mac,myIP);
  
  UdpONE.begin(8000);
  UdpTWO.begin(8001);
}

void loop() {
  
  for(int i=0; i<24; i++)
    buffer[i] = counter;
  
  if(++counter == 100)
    counter = 0;
  
  transmissionTime = 0;
  UdpONE.beginPacket(destinationONE,portONE);
  UdpONE.write(0xF0);
  UdpONE.write(buffer,24);
  UdpONE.endPacket();
  Serial.print("Packet 1 - ");
  Serial.print(transmissionTime);
  
  transmissionTime = 0;
  UdpONE.beginPacket(destinationTWO,portTWO);
  UdpONE.write(0xF0);
  UdpONE.write(buffer,24);
  UdpONE.endPacket();
  Serial.print("\tPacket 2 - ");
  Serial.println(transmissionTime);
  
//  transmissionTime = 0;
//  UdpTWO.beginPacket(destinationTWO,portTWO);
//  UdpTWO.write(0xF0);
//  UdpTWO.write(buffer,24);
//  UdpTWO.endPacket();
//  Serial.print("\tPacket 2 - ");
//  Serial.println(transmissionTime);
  
  delay(10); 
}

So, it seems like probably this is an issue with the chip, or something inherent in UDP transmission that I'm not familiar with. Alternatively, I would love to just use the 8 sockets available on the W5200, but I can't get the code to run correctly, has anyone been able to do this? I can get it to compile, but it crashes when I send messages... :(
 
assuming a bind was not done for UDP socket.
The 5100 can do what you are trying to do, if the library "driver" code is correctly written.
 
Status
Not open for further replies.
Back
Top