Handle multiple UDP packets at time

Post here first, or if you can't find a relevant section!
Post Reply
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

Handle multiple UDP packets at time

Post by Step73 »

On a Nucleo F429ZI I wrote this code:

Code: Select all

#include <LwIP.h>
#include <STM32Ethernet.h>
#define UDP_TX_PACKET_MAX_SIZE 512
#include <EthernetUdp.h>

IPAddress remoteIP;
unsigned int remotePort;

EthernetUDP Udp;
uint8_t packetBuffer[UDP_TX_PACKET_MAX_SIZE];

void setup() 
{
  Serial.begin(115200);
  IPAddress localIP = /***/;
  IPAddress netmask = /***/;
  IPAddress dns = /***/;
  IPAddress gateway = /***/;

  Ethernet.begin(localIP, netmask, dns, gateway);
  uint8_t *mac = Ethernet.macAddress();

  int port = 8888;
  Udp.begin(port);
}

void loop() 
{  
  processUDPMessage();
}

void processUDPMessage(void)
{ 
  while (int size = Udp.parsePacket())
  {
    if (size > 0) parsePacket(size);
  } 
}

void parsePacket(int size)
{
  remoteIP = Udp.remoteIP();
  remotePort = Udp.remotePort();

  Udp.read(packetBuffer, size);
  Serial.println((char *) packetBuffer);  
}
It works fine but if I send multiple UDP packet at the same time (even only 4-5) one of them is not received (never!).
The packets are very shorts, about 40 bytes each.

How would you improve my code?
ag123
Posts: 1668
Joined: Thu Dec 19, 2019 5:30 am
Answers: 25

Re: Handle multiple UDP packets at time

Post by ag123 »

well i'd guess you'd probably need to debug the codes if you want to find out why the udp packets are missing.
or possibly try to do some serial prints() to see what may be happening after all.
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

Re: Handle multiple UDP packets at time

Post by Step73 »

ag123 wrote: Mon Feb 17, 2020 2:45 pm well i'd guess you'd probably need to debug the codes if you want to find out why the udp packets are missing.
or possibly try to do some serial prints() to see what may be happening after all.

You're talking about my code?
Udp.parsePacket() returns only 3 times a value > 0 on 4 messages sent.
Where you're suggesting to put a printf?
ag123
Posts: 1668
Joined: Thu Dec 19, 2019 5:30 am
Answers: 25

Re: Handle multiple UDP packets at time

Post by ag123 »

well, i'm not sure about tcp/ip / ethernet etc and i'd guess you are using something related to the official core? libmaple core don't have tcpip nor ethernet.

the problem may be deeper down within the libraries that you use,
if you are using just the mcu alone normally sram memory is tight so it is quite possible of running out of memory. but stm32f429 has more memory in mcu and if you are using one of those discovery boards, some of them has 8MB dram connected. so i'd guess it isn't memory.

if you do a debug, you may be able to trace execution all the way into the library codes to figure out what could be a problem
sheepdoll
Posts: 32
Joined: Fri Dec 20, 2019 6:47 pm

Re: Handle multiple UDP packets at time

Post by sheepdoll »

I was having almost the same exact problem.

I just managed to port some Atmel 32UC3 code that uses UDP. This code floods the local net with UDP packets. A few seconds generates 100s of 1K packets. (a minute is about 13MB in the wireshark pcap dump.)

There is not a lot online about lwip or the low level HAL_ETH. Most of the stuff is PDFs that simply harvest the Doxgen comments and list the calling functions. Most of the other sites are me too, broken links, Obsolete examples, or else they are phishing nets that have harvested old messages and preform necropicy. These show up as new (in the last month or 24 hours.) Then hit you with a browser redirect. I have learned not to click on anything foreign.

That said, the best advice was to tear apart lwip and use only the parts that one needs. There are two ways of handling Packet reception. Polling and interrupt. I chose the latter as it was an option in the CubeMX setup. One still has to poll for next packet availabe from the DMA system.

This is where wireshark comes in. Capture what is being sent, and see what is being missed. Or where the endian order is swapped.

What the mid level driver does is allocate a chain of linked buffers. When the HAL_ETH receives a packet it is in DMA. When I put the break point at the ISR. (took me several days of searching to find where the ISR was instantiated deep in the driver code) I found that the buffers pointed to many of the packets even though I only wanted one. Only the first DMA buffer was being served.

Deconstructing the lwip showed how this was copied into the buffer chain, the DMA buffer then needed to be released. Then when the next call happened the next buffer was issued.

Oh the wonders of object oriented programming and data hiding :twisted: I have not been much of a fan of C++ on embedded for this reason. But if one wants to use Arduino type code C++ then one has to pay the devil.

The nice thing is that I wanted to change the display from a 4linex20 SPI character display to a TFT ILI9341. I imported the Print class to my C++ project then attached it to the adafruit Arduino library. This then gave me access to Print functions. The code was calling C ASF functions to control a the SPI display. I wanted to use the display controller on the STM32F29 disco board. but there is a hardware bug on the chip that makes it impossible to use Ethernet MAC and the TFT display at the same time.

I wound up using the 407 discovery and the FMSC lcd controller with a 83848PHY. I have some EN28j60s that are I think SPI based. Have not tried that yet. This should work on a system with out a MAC like the blue or whatevercoloryouwantpill. Have not seen if there is an lwip implementation yet. Last year I got the low level to work on the youtube tutorial.

By using object oriented modules, I can now switch between the different Hardware configurations as needed.

As for the problem at hand:

There were provisions in the code to count packets and errors, then report them to the display. All I had to do was replace calls like DisplayLine() with a class called Display and a call like display->Line() ; The debug code print code was already written, That built the message in a vsprintf. all I had to do was enable it. Saved a week of frustration that way. The whole reason for object oriented programming. High learning curve, then easy re-use.

I found that my direct calls to HAL_ETH were not releasing the buffer once it was copied. I also found that when lwip needs a call to free the pbuf once one is done with it.

Most of the lwip examples are for TCP rather than UDP. Where web pages are being served in not real time. I often wonder why this code is called light weight, Personaly I think this should be called mwip as it is more middleweight than lightweight. I shudder to think what a what a heavy weight TCP stack would look like.
ABOSTM
Posts: 60
Joined: Wed Jan 08, 2020 8:40 am
Answers: 7

Re: Handle multiple UDP packets at time

Post by ABOSTM »

According to LwIP documentation, https://github.com/stm32duino/LwIP/blob ... ore/pbuf.c

Code: Select all

 * So, a packet queue consists of one or more pbuf chains, each of
 * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
 * NOT SUPPORTED!!! Use helper structs to queue multiple packets.
So my understanding is that you can only get packet one by one (no bufferization at packet level). You need to read the previous one to be able to get the next one.
In other words, if multiple packets are send at the same time, you will not be able to read them quickly enough and then you will probably loose some of them.
You can try inserting delay between each packet send.
Step73
Posts: 27
Joined: Tue Jan 14, 2020 2:55 pm

Re: Handle multiple UDP packets at time

Post by Step73 »

You can try inserting delay between each packet send.
Unfortunately I don't have control of the sender application.
Thanks anyway for pointing out another limitation. At least now I understand why it doesn't work.
Post Reply

Return to “General discussion”