ESP32 problème d'interruption

Bonsoir à toutes et à tous,

Voilà un sketch très compliqué :

volatile uint8_t nbP50Hz = 100; // Intervale de temps entre chaque mesure en nombre de périodes de 50 Hz
volatile uint8_t depMesure; // Comptage du nombre de périodes

void IRAM_ATTR lanceMesure() {
  depMesure += 1;
  if (depMesure == nbP50Hz) {
    depMesure = 0;
    ets_printf("depMesure\n"); 
  } 
}

void setup() {
  attachInterrupt(26, lanceMesure, RISING);
}

void loop() {
}

L'entrée 27 est alimentée par du 50 Hz tout beau tout propre écrêté à 0 V et 3.3 V.

Et bien, au lieu d'avoir un résultat toutes des 2 secondes, j'ai un résultat qui tourne autour de 1.5 secondes avec des variations de ± 100 mS.

A l'oscillo, mon signal est très propre : pas de rebondissement visible. Les fronts ne sont pas très raides : 3 V pour 10 mS. Est-ce cela qui pourrait être la cause ?

Y a-t-il quelque chose que j'ai raté ?

Cordialement.

ierre.

Bonsoir @ChPr

Tu as mis ton code d'interruption est en IRAM (RAM Instructions), parfait.
.......mais il fait appel à une fonction qui , sauf erreur de ma part (je ne connais pas ses particularités), est exécutée , comme tout le reste, 'sur place' en mémoire Flash SPI, sans être chargé préalablement en totalité en RAM.

j'ai un doute sur les conséquences de cette acrobatie RAM/Flash SPI pour le code d'une fonction.

EDIT : voir #4

En remplacement du printf dans l'interruption tu pourrais y lever un drapeau pour faire le printf à l'extérieur après un test de l'état du drapeau

Il vaudrait mieux placer un buffer à trigger de Schmitt sur l'entrée pour éviter les problèmes.

Attention aussi à ce que tu utilises pour faire l'écrêtage. Certain montages/composants mettent du temps à récupérer s'il sont fortement saturés. Cela peut entrainer des dissymétrie sur le signal extrait. Ceci dit, comme tu ne comptes que les fronts montant tu devrais être à l'abris de ce problème.

ets_printf() m'intriguait , je ne l'avais jamais rencontrée

Contrairement à un Serial.print() ou un printf() cette fonction serait OK dans une routine d'interruption d'après ce fil de discussion

https://esp32.com/viewtopic.php?f=13&t=3748&p=17131

You can use ets_printf() which is the alternative function (in ESP32 ROM) which is ISR-safe. But generally it's good to avoid things like printing to serial in interrupts at all, if you can.

Stockée en ROM elle ne poserait donc pas le pb d'accès a du code en Flash SPI à partir d'un code en RAM
Les ESP32 ont qq fonctions utilitaires à demeure dans leur petite ROM, en particulier pour le Bootloader
(petit driver SPI, petit driver UART...)

Bonsoir,

Un signal de 50Hz 0-3V avec un temps de montée de 3V en 10ms, ça me perturbe un peu !

La période du 50Hz est de 20ms.

En 20ms, le signal doit faire
0-->3V = 10ms selon les données
3V-->0V = 10ms

Es tu sûr de ton temps de montée?

Un front qui dure 1/2 période, ça me semble trop long, à voir!
Quel est le rapport cyclique de ce signal périodique ?
Quelle est la durée du front descendant?

Peut-être qu'un schéma de la configuration permettrait d'expliquer le problème.
Ou alors il y a une faute de frappe.

+1

Ce bout de code

if (depMesure == nbP50Hz) {
    depMesure = 0;
    ets_printf("depMesure\n");

Pourrait aussi, il me semble, être sortit de l'interruption pour la rendre plus "atomique"

void IRAM_ATTR lanceMesure() {
  depMesure += 1;
}

et être deposé dans loop

void loop() {
  if (depMesure == nbP50Hz) {
    depMesure = 0;
    ets_printf("depMesure\n");
  }
}

Oui, il y a bien une erreur d'unité. Je m'en suis rendu compte quelques temps après. Il faut lire 3 V / mS.

Voilà une image de la tension sinusoïdale écrêtée :

Et un schéma du montage écrêteur :

Je vais aussi essayer de remplacer ce montage par un trigger de Schmitt.

Cordialement.

Pierre.

Oui, je vais essayer de la mettre dans la loop().

Cordialement.

Pierre.

Il faut conserver le montage et mettre le trigger de Schmitt après. Le trigger ne va pas faire l'écrêtage et il ne va pas apprécier de voir 30V alternatif sur son entrée.
Éventuellement tu pourrait peut-être t'en tirer en diminuant la 33k et/ou le condo de 10nF. C'est sans doute eux qui coupent la bande.

Je suis passé à un trigger de Schmitt :

Cette fois, j'ai des temps de commutation de 4 µS et j'ai bien "environ" 2 S.

Que je place le morceau de code dans la loop() ou que je le laisse dans l'interruption ou encore que je mette IRAM_ATTR en en-tête de l'interruption ne change strictement rien.

Pour autant, en me basant sur le temps affiché par le moniteur série de l'IDE Arduino, la récurrence n'est pas stable :

11:44:22.757 -> depMesure
11:44:24.737 -> depMesure
11:44:26.767 -> depMesure
11:44:28.726 -> depMesure
11:44:30.658 -> depMesure
11:44:32.617 -> depMesure
11:44:34.598 -> depMesure
11:44:36.608 -> depMesure
11:44:38.601 -> depMesure
11:44:40.606 -> depMesure
11:44:42.593 -> depMesure
11:44:44.557 -> depMesure
11:44:46.556 -> depMesure
11:44:48.579 -> depMesure
11:44:50.532 -> depMesure
11:44:52.523 -> depMesure
11:44:54.517 -> depMesure
11:44:56.455 -> depMesure
11:44:58.479 -> depMesure
11:45:00.450 -> depMesure
11:45:02.413 -> depMesure
11:45:04.393 -> depMesure
11:45:06.431 -> depMesure
11:45:08.394 -> depMesure
11:45:10.372 -> depMesure
11:45:12.344 -> depMesure
11:45:14.284 -> depMesure
11:45:16.235 -> depMesure
11:45:18.236 -> depMesure
11:45:20.152 -> depMesure
11:45:22.132 -> depMesure
11:45:24.093 -> depMesure

Je mesure un temps moyen de 1.975 S toujours en me basant sur la même référence.

Une image des variations :

Ce n'est pas que ça me gêne, mais c'est bizarre. Les pas entre chaque échantillon ne sont pas un multiple de 20 mS.

Cordialement.

Pierre.

Bonjour,

Le traitement des données maj dans une interruption doivent être protégées d'un accès concurrent à l'extérieur ... et donc peut-être que le code suivant améliora la chose; à savoir (code non optimisé pour plus de pédagogie):

void loop() {
  uint8_t l__depMesure = 0;

  noInterrupts();
  l__depMesure = depMesure;        // Lecture atomique
  interrupts();

  if (l__depMesure >= nbP50Hz) {   // Plus sûr que 'l__depMesure == nbP50Hz'
    l__depMesure = 0;
    ets_printf("l__depMesure\n");

    noInterrupts();
    depMesure = l__depMesure;      // Ecriture atomique
    interrupts();
  }
}

Cf. interrupts() documentation

A suivre...

Ton montage ressemble plus à un filtre passe-bas qu'à un trigger de Schmitt.

Je ne suis pas certain que l'on puisse s'appuyer sur cette information pour vérifier la stabilité des mesures. Il y a trop d'intermédiaires entre la mesure et l'arrivée des données dans l'IDE.
Il faudrait envoyer la valeur de millis() avec ton échantillon pour vérifier cela.

Merci pour cette propopsition. Malheureusement, ce n'est pas mieux :

Cordialement.

Pierre.

Ce serait vrai si la capacité avait son retour sur l'entrée"-", mais elle revient sur l'entrée"+".

Avec une capacité à la place d'un résistance, je crée une hystérésis dynamique au lieu de statique.

En ce qui concerne la référence à millis(), ce n'est pas mieux :frowning_face:. Ce à quoi il faut que je réfléchisse est que ces deux erreurs ne semblent pas vraiment corrélées. Ce qui voudrait dire, a priori, que le problème ne vient pas de l'interruption mais du système de mesure employé. Ce qui n’exclut pas d'ailleurs une propre imprécision de l'interruption ; il y a quand même une faible corrélation entre ces deux signaux (courbe que j'ai tracée en jaune).

Cordialement.

Pierre.

Dans le cas présent, pour lever le doute entre le matériel et le logiciel, j'adopte la stratégie qui consiste à faire générer par l'esp32 le même joli signal carré ou rectangulaire (fréquence et rapport cyclique) qui sera injecté dans un 1st temps directement sur la pin d'acquisition et dans un 2nd temps et si le résultat attendu est correct, l'injecter en entrée de l'électronique

NB: Par expérience, l'acquisition du 50 Hz n'est pas simple car celui-ci peut présenter un bruit indétectable à l'oscilloscope avec en général des harmoniques également indétectables...

Bonjour,

Cela paraît évident, mais ce 50Hz provient bien de ERDF ?

Si il y avait des harmoniques, il pourrait y avoir effectivement des fronts montants supplémentaires, d'où une mesure inférieure. Par contre lorsque le temps de mesure est supérieur à 2s, cela voudrait dire qu'il y a des pertes.

Autre remarque, il me semble qu'ERDF envoi des trames EC/EP et peut être EJP tous les jours sur le réseau. Il me semble qu'un filtre passe bas serait une bonne chose pour que votre montage ne compte pas ses trames.

A+

Oui. Pour autant, les trames HP, HC et EJP n'arrivent qu'à certains moments de la journée.

Par ailleurs, j'ai résolu mon problème en plaçant un trigger de Schmitt entre ce signal et mon ESP32. Le comptage se passe bien maintenant.

Cordialement.

Pierre.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.