shield ethernet : un souci de buffer ?

bonjour, je suis en train de prêter la main à un plasticien qui désire faire une installation avec des dichros 12v ( une 30taine).

la base est envisagée sous arduino UNO, avec 2 ou 3 TLC5940, et l'utilisation de transistors de puissance ( encore à définir pour des puissances de 40w en 12v)

L'envoi des infos de contrôle de ces dichros se fera en ethernet en protocole art-net ( UDP), avec un shield, l'arduino étant cachée dans l'oeuvre.

J'ai un petit, voir un gros souci avec mon script, hors TLC. Je l'ai allégé au maximum, de façon à essayer de déterminer ce sur quoi je butais.

J'envoies depuis un logiciel tiers une trame art-net qui fait 530 bytes de données, et dont les infos de circuits sont exprimées en bytes, donc en valeur de 0 à 255.
Header + données propres au protocole= 17 bytes
512 circuits dmx
1 caractere de terminaison

Je teste le resultat pour l'instant sur une seule LED en PWM.

lorsqu'une valeur est changée, j'envoies une trame art-net vers l'arduino.
un changement sec d'état est répercuté directement sur la LED.

parcontre si il y a crossfade ( et donc envoi en continu de trames artnet) la LED ne rafraichit pas, ou après un certain temps qui peut aller jusqu'à 4 secondes.

le blocage se produit à plus de 12 trames par secondes

  • comme si le buffer de réception ethernet était saturé
  • ou que la connexion était en mode bloquant

Donc avant de me lancer dans les TLC, je me dis oulalala.... demandons un coup de main !

#include <SPI.h>         // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <Udp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008

// ADRESSES MAC ET IP du shield ethernet
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1,177 };
unsigned int localPort = 6454;      // port UDP générique art-net=6454
// the next two variables are set when a packet is received
byte remoteIp[4];        // holds received packet's originating IP
unsigned int remotePort; // holds received packet's originating port
// buffers for receiving  data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

const int nombre_de_circuits=512;
int taille_chaine_artnet=8+17+nombre_de_circuits+1;
//8: UDP protocole //17: header + donnees artnet // 1: caractere de fin de chaine
byte buffer_dmx[nombre_de_circuits];



void setup() {
  for (int i=0;i<nombre_de_circuits;i++)
 {
  buffer_dmx[i]=0;
 }
  pinMode(3, OUTPUT);  
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
}

void loop() {

  int packetSize = Udp.available(); // note that this includes the UDP header
  if(packetSize==taille_chaine_artnet)
  {
    Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort);
    for(int i=0;i<nombre_de_circuits;i++)
    {
    buffer_dmx[i]=(byte) packetBuffer[i+17];
    }
  //report des valeurs sur les PWM
  analogWrite(3,buffer_dmx[3]);  
  }

}

Ok. j ai un peu fureté de partout, rien trouvé sur un éventuel Blocking Mode.

Est ce qu il faut que je repasse la structure en serveur ?

Est ce une limitation due à l'écriture sur PWM ?

Je pense que quand il y a des données en rafales, peut-être que la Udp.available()

ne retourne pas tous les octets de la trame. Hors tu supposes qu'à chaque fois tu va recevoir le bon nombre d'octets (cf : if(packetSize==taille_chaine_artnet))

Essaye de voir si tu ne recois pas des packetSize différents...

Si c'est le cas, c'est à toi de reconstruire toute la tramme Udp en conséquence. Cela est du probablement au buffer de la carte ethernet.

En gros je ferai plutôt un truc du style :

packet_size = Udp.available

if (packet_size)
{
for (int i=0; i<packet_size; i++)
buffer_tmp*=Udp.read();*
}
puis reconstruire ta tramme udp. (pseudo code au dessus).
Voilà mon avis.
A+

j ai mis un serial print sur le nombre d'octets reçus, qui correspondent bien à chaque fois à la trame artnet ( 530 bytes après deduction des 8 bytes de code l UDP)

il n y a rien de possible pour flusher le port ?

il faut que j atteigne pour que les longs crossfades soient acceptables visuellement ( 10 secondes, 20 secondes, 2 minutes) un rafraichissement de 50 trames par secondes.

Résolu.
L' UDP_TX_PACKET_MAX_SIZE ne fait que 24 dans le header udp.h
remplacé cette valeur par une taille de buffer correspondant ) ma chaine.

Tu peux préciser stp.

Tu as changer la valeur dans le UDP.h ou tu as adapté ton programme à la valeur 24 ?

Le fait de changer (donc de mettre 538) dans le udp.h induit sur la consommation de mémoire RAM.

Merci de tes précisions.

Sinon essaye (comme un exercice, d'adapter avec 24 comme valeur), car si un jour tu veux des trammes de 16ko tu sera un peu ennuyé ;o)

d'abord merci à toi de ta réponse ! :smiley:

ensuite, non je n ai pas changé le contenu du header udp.h, j ai changé les arguments données à .Read
dans udp.h la taille MAX est de 24 alors que dans ethernet.h, le MAX d'un packet est défini comme 2048

const int UDP_MAX_PERSONNAL_SIZE=1024;
/*
...
*/
Udp.readPacket(packetBuffer,UDP_MAX_PERSONNAL_SIZE, remoteIp, remotePort);

Je ne comprends pas que j'ai pu avoir une trame complète avec 10 envois par secondes. Je suppose que le buffer n est pas vidé et qu il manque vraiment un flush quelque part, ou que les fonctions udp débordent....
A ton avis, faut il que je nettoye le buffer de réception après analyse ?

Là je suis monté à 50 envois / secondes sans soucis, c'est fluide, et je reçois donc mes 512 circuits de manière plus que satisfaisante...
je me demande même à combien je peux monter si j avais un mur de leds et des animations rapides à faire dessus...
j'ai garde comme impératif d'avoir une taille de packet reçue == à la taille d'un paquet artnet avant de traiter ce dernier ( du coup j ai remis toutes mes fonctions d'analyse des headers pour décoder si c'est le bon message attendu, et ca fonctionne bien).

Peux tu me dire ce que tu entends par vouloir des trames de 16ko? envoyer des petits flux vidéos ?

Salut,

voici mon avis/expérience sur le sujet:

même si tu ne veux tenir compte que des messages ayant la bonne taille, il faut systématiquement le récupérer afin de vider le buffer du wiznet (par défaut 2048, mais tu peux le monter à 4*2048 si tu n'utilises qu'un seul des 4 sockets)

donc:

  1. récupérer la taille du message disponible que renvoit Udp.available() (-> doit-être au minimum de 8 bytes, soit la taille de l'en-tête)
  2. récupérer le message Udp.readPacket()
  3. vérifier qu'il est de la taille souhaité
  4. traiter en conséquence
int packetSize = Udp.available(); // note that this includes the UDP header
if(packetSize)
  {
        Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort);
  
        if(packetSize==taille_chaine_artnet)
        {
             // ici le code qui traite le message s'il est de taille conforme  
        }
   }

Note qu'il est important de ne pas laisser saturer le buffer du wiznet, au risque d'avoir une corruption des données contenues dedans: c'est un buffer circulaire, donc risque d'écrasement des données pas encore lue.

Enfin, je ne connais pas art-net, mais pour éviter de bombarder de messages inutilement, pourquoi ne pas implémenter la fonction fading directement dans l'arduino ? en un seul message, tu peux lui donner la nouvelle consigne à changer en x secondes ?

Gromain