Bonjour,
Depuis quelques jours j’affronte quelques problèmes de communication série entre un Atmega328 et mon PC si bien que j'ai décidé de faire le test qui me semble le plus simple pour vérifier cela : un simple programme "loopback" sur l'Atmega.
J'ai donc d'un côté un Atmega328 qui tourne avec le code affiché ci-après, et de l'autre côté l'adaptateur USB<->série présent sur ma vielle carte "Arudino UNO" (non peuplé par son propre Atmega), un Atmega8U2. De plus j'utilise pour ces tests un très petit bitrate (1200bit/s) afin d'écarter les problèmes d'imprécisions de l'horloge interne.
Le code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #define F_CPU 8000000 #include <avr/io.h> #include <avr/interrupt.h> #define USART_BAUDRATE 1200 #define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2) ) / ( USART_BAUDRATE ) ) - 1) typedef uint8_t u8; typedef uint16_t u16; int main(void) { UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = (1<<USBS0)|(3<<UCSZ00); UBRR0H = (unsigned char)(BAUD_PRESCALE>>8); UBRR0L = (unsigned char)BAUD_PRESCALE; UCSR0B |= (1 << RXCIE0); sei(); while(1) {} } ISR(USART_RX_vect, ISR_BLOCK) { u8 received_byte; received_byte = UDR0; UDR0 = received_byte; } |
Du côté du python j'utilise la bibiothèque "serial". Lorsque je teste l'envoi de bits individuels je ne perd rien :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ser = serial.Serial("/dev/ttyACM0", 1200, timeout=1) ok = 0 ko = 0 for i in range(nb_bytes): char = random.randint(0,255) ser.write([char]) result = ser.read() if len(result) > 0 and result[0] == char: ok += 1 else: ko += 1 print("nb_chars = {}".format(nb_bytes)) print("ok = {}".format(ok)) print("ko = {}".format(ko)) |
1 2 3 4 | >>> test3.test_indiv(100) nb_chars = 100 ok = 100 ko = 0 |
En revanche quand j'envoie directement "un paquet" de plusieurs octets, certains n'arrivent pas (ou ne reviennent pas en tout cas) de manière semble-t-il aléatoire:
1 2 3 4 5 6 7 8 9 10 11 | >>> ser = serial.Serial('/dev/ttyACM0', 1200, timeout=1) >>> data = [random.randint(0,255) for _ in range(100)] >>> ser.write(data) 100 >>> data2 = list(ser.read(100)) >>> data [178, 193, 217, 98, 243, 147, 153, 73, 191, 191, 5, 190, 141, 94, 133, 121, 25, 255, 56, 7, 139, 77, 211, 56, 216, 182, 159, 201, 156, 235, 96, 144, 30, 73, 216, 196, 97, 201, 183, 204, 212, 145, 182, 59, 186, 191, 191, 35, 161, 252, 103, 1, 177, 204, 28, 205, 245, 51, 59, 83, 136, 105, 224, 255, 35, 116, 98, 199, 79, 240, 52, 224, 78, 92, 178, 122, 75, 184, 5, 75, 250, 128, 83, 190, 197, 14, 235, 147, 58, 20, 80, 248, 34, 224, 146, 225, 158, 72, 70, 118] >>> data2 [178, 193, 217, 98, 243, 147, 153, 73, 191, 191, 5, 190, 94, 133, 121, 25, 255, 56, 7, 139, 77, 211, 216, 182, 159, 201, 156, 235, 96, 144, 30, 73, 196, 97, 201, 183, 204, 212, 145, 182, 59, 186, 191, 35, 161, 252, 103, 1, 177, 204, 28, 205, 245, 59, 83, 136, 105, 224, 255, 35, 116, 98, 199, 240, 52, 224, 78, 92, 178, 122, 75, 184, 5, 250, 128, 83, 190, 197, 14, 235, 147, 58, 20, 80, 34, 224, 146, 225, 158, 72, 70, 118] >>> data == data2 False |
On pourrait supposer que le problème provienne d'un dépassement de buffer quelque part (sur l'adaptateur USB<->série ?), sauf que dans ce cas comment expliquer le placement random des manques (dans cet exemple le premier octet manquant est le 13ème) ?
L’imprécision de l'horloge parait être une éventualité mais… à ce faible bitrate ?
Est-ce que la lib python envoie "trop vite" pleins d'octets et le micro n'a "pas le temps" de suivre ? Ça parait curieux.
En tout cas quand les octets sont envoyés individuellement c'est vraiment lent.
Voilà, si quelqu'un a une piste je suis preneur
Merci d'avance
Emmflo
EDIT: En fait je suis un débile, j'avais pas le bon format de frame série.
1 | >>> ser = serial.Serial('/dev/ttyACM2', 9600, timeout=1, bytesize=8, stopbits=2) |
Et pouf tout va mieux. Donc oui pour ceux qui ne le savaient pas (comme moi :> Même si en fait c'est logique…) ça peut marcher à moitié si on met pas le bon format :>