Comment l'Arduino gère-t-il le débordement du tampon série?

27

Comment l'Arduino gère-t-il le débordement du tampon série? Jette-t-il les données entrantes les plus récentes ou les plus anciennes? Combien d'octets le tampon peut-il contenir?


la source

Réponses:

13

Pour les ports série matériels, vous pouvez voir dans HardwareSerial.cpp que la taille de la mémoire tampon varie en fonction de la quantité de RAM disponible sur l'AVR particulier:

#if (RAMEND < 1000)
    #define SERIAL_BUFFER_SIZE 16
#else
    #define SERIAL_BUFFER_SIZE 64
#endif

Pour un port série logiciel dans SoftwareSerial.h, la taille de la mémoire tampon du récepteur _SS_MAX_RX_BUFFest définie comme 64 octets. Dans les deux cas, il cesse d'essayer d'insérer les données reçues dans la file d'attente lorsqu'elle est pleine, vous pouvez donc obtenir un mélange d'anciennes et de nouvelles données selon la façon dont vous récupérez les données de la file d'attente.

Idéalement, il serait préférable de s'assurer que le tampon est toujours vidé rapidement pour éviter le remplissage du tampon. Peut-être jetez un œil aux minuteries et à l'implémentation d'une machine à états simple si votre problème est lié à un autre code bloquant la boucle principale.

PeterJ
la source
J'ai l'impression que si je transmets des données à l'Arduino et que je n'ai pas un "extracteur" actif de données du côté de l'Arduino, alors si plus de données arrivent que ce qui peut tenir dans le tampon, elles seront rejetées. Pouvez-vous confirmer cela? J'avais naïvement supposé que l'émetteur se bloquerait jusqu'à ce que l'espace disponible pour contenir les données devienne disponible.
Kolban
Je viens de parcourir tout ce code (sous / usr / share / arduino / hardware / arduino / core / arduino / HardwareSer‌ ial.cpp) et je peux confirmer ce que vous avez écrit ici. La seule chose que j'ajouterais est que puisque la SRAM est 2K (RAMEND> 1000), alors cette instruction if utilisera toujours 64 plutôt que 16 sur un Nano ou un Uno. Donc, si l'on veut étendre la taille du tampon en anneau, ce serait l'endroit pour le changer
SDsolar
5

Réception

Vous pouvez voir à partir de la source de HardwareSerial que si un octet entrant trouve le tampon en anneau plein, il est rejeté:

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

J'ai l'impression que si je transmets des données à l'Arduino et que je n'ai pas un "extracteur" actif de données du côté de l'Arduino, alors si plus de données arrivent que ce qui peut tenir dans le tampon, elles seront rejetées. Pouvez-vous confirmer cela?

Oui, il sera jeté. Il n'y a pas de contrôle de flux logiciel ou matériel, sauf si vous implémentez le vôtre.

Cependant, avec un tampon de 64 octets et la réception de données à (disons) 9600 bauds, vous obtenez un octet toutes les 1,04 ms, et il faut donc 66,6 ms pour remplir le tampon. Sur un processeur 16 MHz, vous devriez pouvoir vérifier le tampon suffisamment souvent pour qu'il ne se remplisse pas. Tout ce que vous avez vraiment à faire est de déplacer les données du tampon HardwareSerial vers le vôtre, si vous ne voulez pas les traiter maintenant.

Vous pouvez voir à partir de la #if (RAMEND < 1000)vérification que les processeurs avec plus de 1000 octets de RAM obtiennent le tampon de 64 octets, ceux qui auront moins de RAM obtiendront le tampon de 16 octets.


Envoi

Les données que vous écrivez sont placées dans un tampon de même taille (16 ou 64 octets). Dans le cas d'envoi si le tampon remplit le code "blocs" en attente d'une interruption pour envoyer l'octet suivant hors du port série.

Si les interruptions sont désactivées, cela ne se produira jamais. Par conséquent, vous n'effectuez pas d' impressions série dans une routine de service d'interruption.

Nick Gammon
la source
Je pense que vous vous trompez d'un ordre de grandeur: à 9600 bauds, vous obtenez un octet toutes les ~ 0,1 ms, il ne faut donc que 6,6 ms pour remplir le tampon.
Eric Dand
1
À 9600 bauds, vous obtenez 9600 bits par seconde. Étant donné que chaque octet est de 10 bits (8 données + 1 bit de démarrage + 1 bit d'arrêt), vous obtenez 960 octets par seconde. 1/960 = 0.001042 s- soit un octet toutes les 1,04 ms.
Nick Gammon
Ahh bien sûr, des bits pas des octets! Merci pour la correction.
Eric Dand
Alors Nick, veuillez répondre à ceci pour moi: si j'ai un Pi exécutant Python assis à un ser.readline () en attente d'entrée en tant qu'enregistreur de données, et il est alimenté via série par Arduino en prenant des lectures puis en les envoyant sous forme de lot avec onglet délimètres, puis en utilisant le délai (120000) pour que les lots arrivent toutes les deux minutes, les entrailles Python lisent probablement immédiatement chaque caractère jusqu'à ce qu'il rencontre une nouvelle ligne, auquel cas il libère la ligne entière comme valeur de retour. Je n'ai donc pas à me soucier de la taille du tampon Arduino même si j'envoie 80 caractères au total, hein? Serait-ce une bonne hypothèse?
SDsolar
Oui, la taille du tampon d'envoi n'aura pas d'importance dans ce scénario. Un petit tampon ralentirait l'envoi (légèrement) mais si vous faites un long délai de toute façon, vous ne vous en soucierez pas.
Nick Gammon