Image of an arrow

Travailler les données d’un analyseur logique Saleae en Python

Avatar

sbourdelin

Salae Logic AnalyzerRécemment, j’ai été amené à devoir prendre des mesures de temps très précises pour répondre à une problématique de contrainte temps-réel. Sur un SoC particulier avec un système Linux dessus, la question était de savoir quelle était la fluctuation de la latence entre le déclenchement d’un événement matériel et la réponse d’une tâche logicielle associée à cet événement.

La gigue ou fluctuation du signal

Qu’est ce que la gigue ou jitter en anglais ? Prenons, par exemple, un événement avec une fréquence parfaite — disons l’heure à laquelle sonne mon réveil — et un autre événement moins parfait qui lui est associé, comme le moment où j’ouvre les yeux. Chaque jour, l’heure de mon réveil reste la même. En revanche, le moment où j’ouvre les yeux pour éteindre mon réveil varie… au désespoir de mon patron. :/

Cette fluctuation est la gigue. Dans ce cas, il s’agit d’une gigue temporelle, comme dans ma problématique.

Mesurer la gigue avec un oscilloscope

Typiquement, mesurer la latence entre deux événements matériels se fait très bien avec un oscilloscope à deux canaux. Il suffit de savoir où sonder, sur notre circuit, ces événements. Après quelques réglages, on peut visualiser la latence et, notamment, avoir une persistance sur chaque prise de mesure qui va nous donner une enveloppe de cette fluctuation.

Ma première démarche à donc été d’associer à ma tâche logicielle un autre événement matériel pour m’aider à prendre ces mesures. Mon événement matériel initial était une interruption et je savais où la sonder sur le SoC. À celui-ci, je réponds par un autre événement matériel qui consiste à faire commuter une GPIO que je sais également où sonder sur le SoC.

Ainsi à chaque fois que l’interruption se déclenche, la GPIO change d’état.

Ce qui nous donnera par exemple sur un oscilloscope quelque chose comme ça :

jitter_simulated

Avec en jaune l’interruption qui est réguliére, et en vert la fluctuation des temps de réponse de la GPIO.

Il ne me restait plus qu’à prendre mes mesures avec un oscilloscope. Mais là c’est le drame… je ne disposais pas d’oscilloscope suffisamment récent pour avoir une enveloppe consistante de mes signaux; faute de mémoire, je pouvais conserver tout au plus les 32 dernières mesures et je ne pouvais donc pas voir ma fluctuation sur de longues périodes.

Le seul autre équipement à ma disposition pour prendre des mesures était un analyseur logique Saleae Logic. Bien que très pratique, ce dernier ne me permettait pas de visualiser ma fluctuation du signal.

Comment visualiser la gigue avec l’analyseur logique de Saleae ?

Avec cet analyseur, ce que je peux obtenir comme résultat ressemble à cela:

logic_output

En zoomant on voit bien la latence entre le déclenchement de l’interruption (en haut) et la commutation de ma GPIO (en bas):

logic_output_zoom

Ce qui m’intéresse, c’est mesurer étant le temps entre le drapeau 1 et le drapeau 2 pour chaque interruption et le visualiser de façon facilement compréhensible, comme ceci:

logic_output_zoom_flag

Mais je ne peux pas faire ça à la main pour chaque interruption et recommencer à chaque prise de mesure.

C’est en discutant de mon problème, qu’un collègue et ami (Emeric Vigier, pour ne pas le nommer), me pointa à juste titre sur la fonction d’exportation de ce logiciel. Et, effectivement, l’ensemble des informations qui me sont nécessaires sont à ma disposition, le dernier problème étant juste qu’elles ne sont pas organisées comme je le désire.

Visualisation des données : du CSV au Graphique

Donc, comme précisé précédemment, l’analyseur logique de Saleae me permet d’exporter mes données au format CSV sous la forme:

Time[s], Interrupt Trigger, Gpio 0
0, 0, 1
0.00258295833333333, 1, 1
0.00258408333333333, 0, 1
0.002633, 0, 0
0.00758641666666667, 1, 0
0.00758758333333333, 0, 0
0.007629625, 0, 1
0.0125899166666667, 1, 1
...

La première valeur me donnant le temps en seconde, la deuxième l’état de mon interruption (0 = bas, 1 = haut), et la troisième l’état de ma GPIO. Donc, l’algorithme me permettant de récupérer ma latence sera:

Pour chaque ligne,

  1. Si mon interruption passe de 0 à 1, Alors je note son temps dans A
  2. Si j’ai A et que ma GPIO change d’état, Alors je note son temps dans B
  3. Si j’ai A et B, Alors je soustrais A à B et je garde le résultat dans le tableau C

Le tableau C contiendra ainsi l’ensemble des temps de latence. En quelques lignes de Python, cela donne le code suivant :

STEP_INTERRUPT  = 0
STEP_GPIO       = 1

with open(file_csv, 'r') as csvfile:
    cvsreader = csv.reader(csvfile, delimiter=',')

    # the first entry give us the initial state
    init_state      = next(cvsreader)
    interrupt_state = init_state[interrupt]
    gpio_state      = init_state[gpio]
    step            = STEP_INTERRUPT

    for row in cvsreader:

        # The first step is to find an interrupt edge
        if step == STEP_INTERRUPT:
            if (interrupt_state == 0 and int(row[interrupt]) == 1):
                interrupt_value = float(row[0])
                step = STEP_GPIO

        # The second step is to find a gpio commutation
        elif step == STEP_GPIO:
            if (gpio_state != int(row[gpio])):
                gpio_value = float(row[0])
               
                # here we know we have an interrupt edge value
                # and the gpio commutation time
                # we can take the delay mesure between the two
                delay = gpio_value - interrupt_value

                # store the delay value in millisecond.
                dic.append((delay * 1000, 0.5))

                # we can now reinit the step
                step = STEP_INTERRUPT

        interrupt_state = int(row[interrupt])
        gpio_state      = int(row[gpio])

À ce stade, je dispose de l’ensemble de mes latences, maintenant j’aimerais bien pouvoir les mettre en forme avec quelque chose de plus parlant — et ce n’est pas comme si l’on manquait de librairies pour réaliser des graphiques dans Python. Donc, prenons en une au hasard, et dessinons!

J’ai choisi la librairie pygal, qui permet de dessiner des points dans un espace à 2 dimensions. Il m’a suffit de rajouter ces quatre lignes de Python à mon script:

xy_chart = pygal.XY(stroke=False, fill=False, show_y_labels=False, legend_at_bottom=True, show_dots=True, dots_size=0.8, print_values=False)
xy_chart.title = 'Jiffies'
xy_chart.add('values in milli-second', sorted(dic))
xy_chart.render_to_png('jitter.png')

Et voilà le résultat tant désiré car nettement plus parlant:

jitter-with-pygal

On peut ainsi voir quelque chose qui se rapproche de notre première capture d’écran (l’exemple d’un oscilloscope) tout en économisant quelques milliers de dollars… cette fois, au grand bonheur de mon patron. 😉

Le script complet est disponible ici : github.com/sbourdelin/logic-jitter

  1. Excellent cet article sur « comment sauver 40 000 dollars avec 50 lignes de Python »!
    Tu as oublié de préciser: « Article terminé 2h avant que le réveil ne sonne, d’où le jitter à l’ouverture des yeux. 😉

  2. Très bonne utilisation de Python dans ce type de contexte!

    Par contre il y a bug: tu as un état de trop, STEP_GPIO!
    Durant l’état STEP_INTERRUPT tu obtiens toutes les valeurs nécessaire
    durant l’état STEP_GPIO, donc tu peux déjà calculer ‘delay’ dedans
    et passer directement de STEP_INTERRUPT à STEP_INIT.

    De plus passer par STEP_GPIO mange une entrée de tes données pour rien.
    J’ai posté un bug dans sur ton github 😉

Comments are closed.


Articles similaires

Image of an arrow

[L’introduction est en français, le reste du texte en anglais] Le premier article de cette série présentait les motivations et les avantages de l’intégration d’une image de conteneur dans un système Linux embarqué et examinait les défis que ce nouveau paradigme soulève. Le second article présentait différentes approches pour intégrer un conteneur dans le système […]

Thumbnail image

[L’introduction est en français, le reste du texte en anglais] Points clés: La série de correctifs PREEMPT_RT permet au noyau Linux de répondre aux besoins des systèmes temps-réel. Différents réglages permettent un compromis entre performance et latence. Un paquet de support de carte minimal permet une réduction de la latence. Les mesures de durcissement du […]

Thumbnail image

[L’introduction est en français, le reste du texte en anglais] Les produits industriels deviennent de plus en plus complexes et nécessitent de beaucoup plus d’interaction et de connectivité. Il est maintenant usuel de faire le suivi et la maintenance d’un appareil à partir d’une interface par une application web embarqué sur ce même appareil. Au […]

Précuseur de l’Internet post-GAFAM             Las Vegas, le 9 janvier 2019 ​ – Présente au Consumer Electronics Show de Las Vegas, Savoir-faire Linux, entreprise québécoise de services-conseils depuis plus de 20 ans et experte dans l’industrie du logiciel libre au Canada, lance l’application de communication universelle et autonome Jami. Destiné […]

Rennes, le 30 novembre 2017 – Savoir-faire Linux est fière d’annoncer l’installation à Rennes d’un centre d’expertise en ingénierie logicielle libre et systèmes embarqués pour desservir ses clients français et européens. Savoir-faire Linux est une entreprise québécoise experte en technologies libres et open source, leader au Canada et implantée en France depuis 2014. Elle a […]