Partage
  • Partager sur Facebook
  • Partager sur Twitter

Programmation uC: communication série très rapide

    28 octobre 2014 à 9:48:00

    Bonjour à tous,

    Dans le cadre d'un projet personnel, je devrais faire communiquer un ATmega328p avec un ordinateur, par le biais d'une liaison série. Chaque "paquet" de données devrait faire entre 16bits et 64bits. Seulement, en dehors de la communication avec l'ordinateur, mon uC doit faire énormément de calculs et à une fréquence élevée, il faut donc que la communication soit la plus rapide possible. De plus, plusieurs communication peuvent avoir lieu par seconde, au moins une vingtaine. 

    J'aimerais donc savoir quelle est la meilleure solution pour récupérer ces paquets de données à temps mais sans gêner les autres calculs. Merci beaucoup de votre aide

    • Partager sur Facebook
    • Partager sur Twitter
      28 octobre 2014 à 10:26:29

      20 paquets de 64 bits  ?  160 octets par seconde ? On est en pleine science fiction :-)

      • Partager sur Facebook
      • Partager sur Twitter
        28 octobre 2014 à 12:02:08

        Des paquets de 64bits au maximum ! Je pense qu'on sera plus près des 16!
        • Partager sur Facebook
        • Partager sur Twitter
          28 octobre 2014 à 20:07:02

          EH, un ATmega328p peut parfaitement gérer une com série à 115200 bauds.

          Ce qui nous donne 115200 bits par secondes et donc 11520 octets par secondes si l'on compte les bits de start et de stop.

          Si l'on se place dans le pire cas où il faudrait envoyer 50 packets 64 bits par secondes, cela fait 400 octets secondes.

          Pour une tache bloquante, cela ne prendrait donc que 3.5% du temps CPU.

          Après, si ces 3.5% sont trop, tu peux toujours utiliser les interruptions ou un DMA si le ATmega328p en possède un.

          -
          Edité par lorrio 28 octobre 2014 à 20:07:49

          • Partager sur Facebook
          • Partager sur Twitter
            28 octobre 2014 à 23:22:15

            Pour communiquer avec un ordinateur la solution la plus simple (et pas trop coûteuse) c'est une liaison série qui peut monter à 1 Mbps. 

            Le problème c'est que le protocole ne permet de transmettre que 8 ou 9 bits de données à chaque fois, donc il te faudra reconstituer les paquets derrière, soit en ajoutant des informations dans le premier paquet, ce qui augmentera l'overhead, soit en définissant une taille fixe (un nombre de paquets fixe) mais en mettant plus ou moins de data utile.

            Le problème de l'ATMega328p comme de beaucoup de microcontroleurs 8 bits et 16 bits, c'est qu'il ne possède pas de DMA. C'est un système qui permet des échanges entre des périphériques (en général entre 2 adresses "mémoire") en direct, sans passer par le CPU.

            De ce fait le CPU peut faire des calculs (qui n'utilisent pas les périphériques qui sont en transfert DMA) sans être bloqué à cause d'un transfert.

            Si tu passe par des interruptions et que tu en as beaucoup tu va aussi perdre un peu de temps vu qu'il y a un temps minimum pour entrer dans une interruption (sauvegarde du contexte) et en sortir (reprise du contexte).

            Je ne sais pas ce que tu va faire comme calculs mais un ATMega328p ne me semble pas forcément adapté.

            • Partager sur Facebook
            • Partager sur Twitter
              29 octobre 2014 à 1:15:04

              Lorio : Oui d'accord ! 3.5%! C'est rien !! 

              zeqL : Ha mince le DMA serait parfait là... :( Tu as u e idée du nombre de cycles d'horloge nécessaires pour entrée + sortie d'une interruption ? J'ai prévu de mettre en place un filtre du même style que celui de Kalman, basé sur les quaternions, et un régulateur PID ! Mais j'avais déjà fait des tests, sur le même uC mais programmé avec arduino j'arrivais sans problème à une fréquence de 45-50Hz,alors en C pur, sans la sur couche arduino ça passera encore mieux ! 

              • Partager sur Facebook
              • Partager sur Twitter
                29 octobre 2014 à 8:31:08

                Le 3.5% que j'annonce tient compte d'une fonction bloquante d’envoi des données (50 paquets 64bits par secondes à 115200 bauds).

                Fonction bloquante, cela signifie qu'elle commence l'envoie du premier octet octet, attend que l'envoie se termine, commence l'envoie du second, attend ...

                Elle n'utilise donc ni DMA, ni interruption qui permettrait d'utiliser le CPU à faire autre chose pendant ces temps d'attente.

                Du coup, cette fonction va surement passer 0.1% du temps CPU à lancer les transferts et 3.4% du temps à attendre bêtement.

                Par contre, si ces 3.5% ne te dérangent pas, il n'y a pas à chercher plus loin avec l'étude d'un processeur plus puissant, d'un DMA ou d'interruptions.

                • Partager sur Facebook
                • Partager sur Twitter
                  29 octobre 2014 à 17:29:08

                  Lorrio, pour estimer que cela ne prendra que 3,5% du temps CPU, sur quoi te bases-tu ? Tu prends quelle fréquence d'horloge ? Et combien de cycles d'horloge pour l'envoi et la réception d'un octet ?

                  • Partager sur Facebook
                  • Partager sur Twitter
                    29 octobre 2014 à 18:10:46

                    Lancer l'écriture d'un octet sur une liaison série est extrêmement rapide : il suffit d'écrire le caractère voulu dans le registre d'écriture de l'UART.

                    En revanche, ce qui prend énormément de temps, c'est attendre que l'UART ai finit d'envoyer le caractère.

                    Exemple sur arduino :

                    void HardwareSerial::write(uint8_t c) {
                        while (!((*_ucsra) & (1 << _udre)));    // Boucle d'attente de disponibilité de l'UART
                        *_udr = c;                              // Lancement de l'envoie du caractère
                    }
                    

                    Vu que le processeur sera presque tout le temps en train d'attendre, je néglige le temps des autres opérations.


                    A 115200 bauds, cela signifie que le CPU envoie 115200 bits par secondes.

                    Un octet contient 8 bits mais il ne faut pas oublier d'ajouter le bits de start et de stop donc cela fait 11520 octets par secondes.

                    Du coup, l'UART va mettre 1 / 11520 = 8,68e-5 = 87us pour envoyer un caractère.

                    En clair, pour chaque caractère à envoyer, le CPU déclenche l'envoie du caractère (une seule instruction) presque instantanément puis attend 87us avant de pouvoir passer au suivant.

                    Pour envoyer 50 trames de 64bits (8 octets), le CPU va donc attendre 50*8*87 = 34800us = 34.8ms

                    Comparées au 1000ms qu'il y a en une seconde, ces 34.8ms ne représentent que 3.5%.

                    -
                    Edité par lorrio 29 octobre 2014 à 18:13:07

                    • Partager sur Facebook
                    • Partager sur Twitter
                      30 octobre 2014 à 9:10:30

                      Faut penser aussi que les UART peuvent avoir un tampon (buffer) qui évite d'avoir à attendre.

                      Bon, si on revient au problème initial, il s'agit apparemment, du côté du microcontroleur, de

                      • faire des calculs
                      • recevoir des paquets de données.

                      La question ça serait plutôt de savoir si c'est un fonctionnement synchrone, du genre

                      repéter indéfiniment
                         attendre un message
                         lire le message
                         traiter les données du message
                      

                      Et dans ce cas, si on attend, c'est qu'on n'a de toutes façons rien d'autre à faire. Ou alors quelque chose de plus asynchrone

                      répeter indéfiniment
                         si un message est arrivé
                           lire et traiter le message
                         sinon
                           faire des calculs
                      

                      mais dans les deux cas, le problème c'est pas d'attendre les messages, mais de les traiter assez vite.
                      Sinon, il faut gérer un tampon de réception.

                       C'est ce que sous-entend probablement "sans gêner les autres calculs".

                      Si c'est pour un arduino, pas de panique, la bibliotheque "serial" gère un tampon d'entrée (de 64 octets ?)

                      -
                      Edité par michelbillaud 30 octobre 2014 à 9:23:06

                      • Partager sur Facebook
                      • Partager sur Twitter
                        30 octobre 2014 à 13:25:21

                        Michelbillaud : plus précisément, il s'agit de la part du microcontrôleur de récupérer les données d'un capteur, recevoir plusieurs paquets de données, faire les calculs nécessaires en prenant en compte les mesures et les paquets de données, puis commander des périphériques externes. Qu'il y ait des données envoyées ou non à l'USART ou non, je dois faire les calculs, donc c'est asynchrone. Non ce n'est pas pour arduino, donc je pense qu'une simple interruption,   générée à chaque réception d'un octet, et ajoutant l'octet dans un buffet, serait suffisante ! 

                        • Partager sur Facebook
                        • Partager sur Twitter
                          30 octobre 2014 à 14:02:26

                          Interruption qui place l'octet dans un buffer quand il arrive, c'est suffisant, et c'est justement ce que fait le truc sous arduino.

                          Comme on a accès au source, y a qu'à piquer dedans.

                          https://code.google.com/p/arduino/source/browse/trunk/hardware/arduino/cores/arduino/HardwareSerial.cpp

                          • Partager sur Facebook
                          • Partager sur Twitter
                            30 octobre 2014 à 14:04:10

                            D'accord merci j'irai voir ! :)
                            • Partager sur Facebook
                            • Partager sur Twitter
                              31 octobre 2014 à 9:29:37

                              Lord Casque Noir a écrit:

                              C'est quoi comme uC ?



                              Spirine a écrit:

                              Bonjour à tous,

                              Dans le cadre d'un projet personnel, je devrais faire communiquer un ATmega328p avec un ordinateur, par le biais d'une liaison série. Chaque "paquet" de données devrait faire entre 16bits et 64bits. Seulement, en dehors de la communication avec l'ordinateur, mon uC doit faire énormément de calculs et à une fréquence élevée, il faut donc que la communication soit la plus rapide possible. De plus, plusieurs communication peuvent avoir lieu par seconde, au moins une vingtaine. 

                              J'aimerais donc savoir quelle est la meilleure solution pour récupérer ces paquets de données à temps mais sans gêner les autres calculs. Merci beaucoup de votre aide

                              ;)
                              • Partager sur Facebook
                              • Partager sur Twitter
                                31 octobre 2014 à 9:37:40

                                Ah, comme plus haut t'avais dit que c'était pas un arduino, je m'étais dit que t'avais dû changer...

                                Si tu veux faire du gros calcul, un 8 bits souffreteux n'est pas forcément la solution adaptée, mais si ça suffit, c'est bon.

                                Note que si tu as un filtre ou autre calcul numérique qui doit s'effectuer à une fréquence constante, tu dois faire gaffe que le traitement additionnel effectué sur les infos reçues sur le port série n'ajoute pas un délai variable dans ton filtre.

                                -
                                Edité par Lord Casque Noir 31 octobre 2014 à 13:35:53

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  31 octobre 2014 à 11:45:42

                                  Le uC est limité niveau puissance je pense, mais il est suffisant ! Et non ça tombe bien, je n'ai pas à le faire à fréquence constante, j'aurai juste à calculer le temps écoulé depuis le dernier calcul, ce qui ne sera pas très dur avec un timer !
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    31 octobre 2014 à 13:39:29

                                    Très bien.

                                    Donc tu prends la mesure sur l'ADC et tu prends le timer qui va avec pour la placer dans le temps ?

                                    Attention si une interruption survient entre ces deux opérations, la valeur du timer sera augmentée de la durée de la routine d'interruption. Si ce jitter est gênant, tu peux couper les interruptions, noter le timer et lancer l'ADC, puis réautoriser les interruptions, par exemple, ou mettre le code qui prend la mesure et le timestamp dans l'interruption de l'ADC si celle-ci a une priorité plus haute et peut interrompre les autres interruptions...

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      31 octobre 2014 à 15:32:58

                                      Non je n'utilise pas d'ADC, si tu parlais du capteur il communiqué avec l'uC en I²C! Mais sinon oui, je récupère les mesures du capteur, je désactive les interruptions, je regarde la valeur du timer, je le réinitialise puis je fais les calculs ! 

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Programmation uC: communication série très rapide

                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                      • Editeur
                                      • Markdown