[Serial] Débit maximum compatible avec PC/OS

Bonjour

Apparemment l'arduino permet une connexion de l'ordre du mégabaud par seconde. Ce qui est déjà très important par rapport au 9600 par défaut.

Plus le débit est important, plus la distance en mètre doit être courte et plus l'arduino sature.

Par contre qu'en est il du standard des différentes machines type arduino <-> PC/mac/Rapsberry pi ainsi que des OS (windows, linux, lion,...) dont le débit est modifiable ?

Est ce que 256000 bauds ou 512000 bauds vous paraissent raisonnable.

OLIVIERC67:
Bonjour

Apparemment l'arduino permet une connexion de l'ordre du mégabaud par seconde. Ce qui est déjà très important par rapport au 9600 par défaut.

Est ce que 256000 bauds ou 512000 bauds vous paraissent raisonnable.

bonjour
pour simple test

sur un XP avec terminal.exe qui permet un baud rate "customable"
et l'exemple analogoutserial arduino
test serial.begin a
256000
512000
768000
892000
OK

Voilà une question qu'elle est intéressante!

Je me suis aussi posé la question sans prendre le temps de faire des tests... Car dans une appli PC (programmation maison genre visualstudio), on peut mettre n'importe quelle valeur dans les propriétés série, puisque c'est une chaine de caractères. Maintenant, est-ce que le driver FTDI/usb accepte des valeurs non standard? j'imagine que oui, puisque c'est le chip FTDI sur la carte qui crée une liaison série, et que lui peut travailler à n'importe quelle vitesse raisonnable, comme le 328.

J'ai joué avec un UNO en branchant un signal DMX sur le RX de la carte, ça marche impec (liaison à 250000), mais pour un aure projet, j'aimerais tâtonner le 256000 entre un PC et arduino (via FTDI/usb), faut que je teste.

la limite serait peut-être le temps de traitement soft PC -> driver FTDI PC -> USB -> 8U2 -> RX/TX...

A mon avis tu risques d'avoir plutôt des soucis de % d'erreur si ton cristal n'a pas une fréquence multiple de ton baudrate.
Avec un cristal à 16Mhz il y a même des chances que ça se passe mieux à 500k qu'à 256k.

Benvenuto:
A mon avis tu risques d'avoir plutôt des soucis de % d'erreur si ton cristal n'a pas une fréquence multiple de ton baudrate.
Avec un cristal à 16Mhz il y a même des chances que ça se passe mieux à 500k qu'à 256k.

Il serait intéressant de faire un ino et un exe/elf pour faire des benchmarks qui testent* différentes plages de bauds sur plusieurs heures.

un peu comme memtest pour la ram.

*Edit : reste -> testent
pas pratique d'écrire sur un smartphone dans le train.

Sinon il y a la datasheet :smiley:
Par exemple celle de l'ATmega 328, p.200.

Il vaut mieux utiliser des fréquences standard 57600, 115200, 230400, 460800, etc...

En effet les oscillateurs des adaptateurs série des PC et autres machines fonctionnent sur ces multiples avec un quartz multiple (ou sous-multiple dans le cas d'un PLL) de ces fréquences.

Hormis la longueur de cable (qui peut être augmentée en travaillant en RS422 au lieu du RS232 ou pire du TTL) le principal problème de la vitesse est l'absence de handshaking de la librairie Serial Arduino. Il est toutefois possible de rajouter une surcouche qui va gérer un petit buffer FIFO et travailler en Xon/Xoff. L'ideal serait bien entendu de réécrire une librairie qui gère cela au niveau interruption.

La limite possible d'un traitement par interruption doit être de l'ordre de 2 megabits sur un ATmega à 16 MHz ce qui fait 200 000 interruptions par secondes et donc 80 cycles d'horloges pour contenir la routine d'interruption et l'éxécution du programme (c'est pas beaucoup et il faut écrire optimisé). 1 megabits me semble plus raisonnable...

JLB

JLB

Bonjour,

L'info sur le débit max en serial m'intéresse aussi énormément.

Pour le controle du flux, c'est une fonctionnalité intégré de base dans les nouveaux ATmega (32u4 par exemple) malheureusement cela n'est pas possible avec un ATmega328p (en hardware j'entend).

La solution recommandé (par avr-freaks) pour la gestion des erreurs est d'implémenter un protocole de communication comportant une checksum (de préférence CRC16).
Et un systéme d'acquittement des données (en cas d'erreur il y a renvoi des info).

Reste à voir si cela ne demande pas trop de calcul côté PC comme côté arduino à de si haute vitesse de transmission.

skywodd:
Bonjour,

L'info sur le débit max en serial m'intéresse aussi énormément.

Le plus important est le débit max stable

Pour le controle du flux, c'est une fonctionnalité intégré de base dans les nouveaux ATmega (32u4 par exemple) malheureusement cela n'est pas possible avec un ATmega328p (en hardware j'entend).

Le contrôle de flux c'est le DTR ?

La solution recommandé (par avr-freaks) pour la gestion des erreurs est d'implémenter un protocole de communication comportant une checksum (de préférence CRC16).
Et un systéme d'acquittement des données (en cas d'erreur il y a renvoi des info).

J'etais justement en train de me poser la question sur le CRC.

Reste à voir si cela ne demande pas trop de calcul côté PC comme côté arduino à de si haute vitesse de transmission.

Pour arduino, PIC, FEZ ça peut poser des problème.

Pour le PC, c'est différent. Les ressources sont en général bien plus importante, d'où l’intérêt d'un benchmark que gérera le PC. Sans compter que d'un PC à l'autre le matos n'est pas forcement le même en qualité.

OLIVIERC67:
Le plus important est le débit max stable

Oui bien sur, enfin on se comprend quoi :grin:

OLIVIERC67:
Le contrôle de flux c'est le DTR ?

Non j'entends par "controle de flux" la gestion du Xon/Xoff.
(oui je sait j'utilise pas les termes adéquat :sweat_smile:)
Mais bon ça n'est qu'une partie de la solution, il faut quand même une vérif (checksum) des données + acquittement.

OLIVIERC67:
J'etais justement en train de me poser la question sur le CRC.

Si tu veut faire une CRC16 en C j'ai une formule mathématique hyper optimisé pour les microcontrôleurs.

En C ça donne :

/**
 * CRC-CCITT (0xFFFF) 16 bits - polynomial x^16 + x^12 + x^5 + 1
 */
 uint16_t CRC16(uint8_t *buffer, uint8_t length) {
   uint16_t crc = 0xFFFF, x;
   
   do {
     x = ((crc >> 8) ^ *(buffer++)) & 0xFF;
     x ^= x >> 4;
     crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
   } while( --length);
   
   return crc;
 }

Si l'on veut de la vitesse pourquoi s'embêter avec de l'asynchrone ??? Le synchone est bien plus fiable !

Le SPI est natif sur les ATMELs et avec une clock à 16 MHz il peut tourner à 4 Mhz de debit (2 clocks high et 2 clock low sont les minimums indiqué dans la datasheet). De plus c'est un bus et tu peux adresser d'autre périphériques. Bien sur tu ne pourras pas faire de grandes distances avec les niveaux TTL mais tu peux mettre des adaptateurs.

Ensuite il peut bien sur y avoir un contrôle par redondance cyclique (CRC). Le polynome du CRC est très simple à calculer comme le montre skywodd dans son post.

Evidemment si c'est pour communiquer avec un PC il faut autre chose. Une solution ancienne pour avoir de la vitesse consistait à utiliser le port parallèle du PC et on doit encore pouvoir trouver le code PC pour le faire (voir des DLLs toute faites), il n'y aura plus qu'à faire le design Arduino qui va bien.

JLB

Bonjour,
Une question que je me pose depuis que j'ai découvert l'Arduino il y a quelques mois:
Pourquoi ne peut-on pas profiter du débit maximal supporté par l'USB et est-on limité à ces débits extrèmement lents de ports série virtuels?

J'imagine que c'est dû à une limitation de l'UART de l'ATMega mais j'ai pas encore pris le temps d'aller voir dans sa datasheet.

jihelbi:
Si l'on veut de la vitesse pourquoi s'embêter avec de l'asynchrone ??? Le synchone est bien plus fiable !

Parce que les communications synchrone ne sont pas possible avec un port série usb ...

jihelbi:
Le SPI est natif sur les ATMELs et avec une clock à 16 MHz il peut tourner à 4 Mhz de debit (2 clocks high et 2 clock low sont les minimums indiqué dans la datasheet). De plus c'est un bus et tu peux adresser d'autre périphériques. Bien sur tu ne pourras pas faire de grandes distances avec les niveaux TTL mais tu peux mettre des adaptateurs.

On parle bien du port série ici, pas de SPI, du reste il n'existe pas sur le marché de clef usb SPI -> usb qui se ferait passer pour un port série (tient ça pourrait être une idée !).

jihelbi:
Evidemment si c'est pour communiquer avec un PC il faut autre chose. Une solution ancienne pour avoir de la vitesse consistait à utiliser le port parallèle du PC et on doit encore pouvoir trouver le code PC pour le faire (voir des DLLs toute faites), il n'y aura plus qu'à faire le design Arduino qui va bien.

Oui mais port paralléle = interface paralléle = beaucoup de broche = pas envisageable.

patg_:
Pourquoi ne peut-on pas profiter du débit maximal supporté par l'USB et est-on limité à ces débits extrèmement lents de ports série virtuels?

Avec les anciennes carte sur base FTDI c'était une limitation hardware du chipset usb il me semble.
Pour les nouvelles cartes c'est plus une question de rétro-compatibilité je pense (ou juste que la team arduino ne voulait pas ce casser la tête).
Avec la leonardo par contre c'est de l'usb natif pour l'upload à ~1.5Mo/s :sweat_smile:

jihelbi:
J'imagine que c'est dû à une limitation de l'UART de l'ATMega mais j'ai pas encore pris le temps d'aller voir dans sa datasheet.

Non justement l'UART de l'Atmega peut aller jusqu'à 1Mbps en mode normal, ou 2Mbps en mode "fast".

Yop Yop,
Juste aux cas ou,pour le crc16 la lib avr est déjà pourvu de fonctions optimisés pour nos µc, je l'utilise sans problème dans mon projet.
http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html#ga95371c87f25b0a2497d9cba13190847f

/** \ingroup util_crc
    Optimized CRC-16 calculation.

    Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)

    Initial value: 0xffff

    This CRC is normally used in disk-drive controllers.

    The following is the equivalent functionality written in C.

    \code
    uint16_t
    crc16_update(uint16_t crc, uint8_t a)
    {
	int i;

	crc ^= a;
	for (i = 0; i < 8; ++i)
	{
	    if (crc & 1)
		crc = (crc >> 1) ^ 0xA001;
	    else
		crc = (crc >> 1);
	}

	return crc;
    }

    \endcode */

static __inline__ uint16_t
_crc16_update(uint16_t __crc, uint8_t __data)
{
	uint8_t __tmp;
	uint16_t __ret;

	__asm__ __volatile__ (
		"eor %A0,%2" "\n\t"
		"mov %1,%A0" "\n\t"
		"swap %1" "\n\t"
		"eor %1,%A0" "\n\t"
		"mov __tmp_reg__,%1" "\n\t"
		"lsr %1" "\n\t"
		"lsr %1" "\n\t"
		"eor %1,__tmp_reg__" "\n\t"
		"mov __tmp_reg__,%1" "\n\t"
		"lsr %1" "\n\t"
		"eor %1,__tmp_reg__" "\n\t"
		"andi %1,0x07" "\n\t"
		"mov __tmp_reg__,%A0" "\n\t"
		"mov %A0,%B0" "\n\t"
		"lsr %1" "\n\t"
		"ror __tmp_reg__" "\n\t"
		"ror %1" "\n\t"
		"mov %B0,__tmp_reg__" "\n\t"
		"eor %A0,%1" "\n\t"
		"lsr __tmp_reg__" "\n\t"
		"ror %1" "\n\t"
		"eor %B0,__tmp_reg__" "\n\t"
		"eor %A0,%1"
		: "=r" (__ret), "=d" (__tmp)
		: "r" (__data), "0" (__crc)
		: "r0"
	);
	return __ret;
}