microseconds()

bonjour,

Ce message fait suite aux posts [Résolu] interruption, delay et delayMicroseconds - Français - Arduino Forum interruption, delay et delayMicroseconds
, la convrsation a un peu dévié.

Il est question de voir combien de temps dure delayMicroseconds(). Elle est normalement correste si il n'y a pas d'interruptions.

Voici le programme qui m'a parmi de faire les tests avec une Uno:

#include <digitalWriteFast.h> // plus facile pour mesurer les temps courts, mais pas indispensable

#define mesure 2 // Mesure des temps
#define infos 3// Infos sur les temps

void setup()
{
  pinMode(mesure, OUTPUT);
  pinMode(infos, OUTPUT);
  noInterrupts();
}

word largeur[]={0,1,2,3,5,10,20};

void loop()
{
  for (byte num = 0; num <= 6; num++)
  {
    for (byte impulsion = 0; impulsion < num; impulsion++)
    {
      digitalWriteFast(infos, HIGH); // Pour étallonage
      digitalWriteFast(infos, LOW); // Pour étallonage
    }

    digitalWriteFast(mesure, HIGH);
    delayMicroseconds(largeur[num]);
    digitalWriteFast(mesure, LOW);
  }
  delayMicroseconds(50);
}

J'obtiens comme chronogramme:


les durées des impulsions du bas sont de 0,125µs c'est donc à déduire des impulsions de mesure pour avoir le temps de delayMicroseconds() seule:

num nb impul en bas temps demandé temps lu delayMicroseconds()
0 aucune 0 0.625µs 0.5µs
1 1 1µs 0.625µs 0.5µs
2 2 2µs 1.625µs 1.5µs
3 3 3µs 2.625µs 2.5µs
4 4 5µs 4.625µs 4.5µs
5 5 10µs 9.625µs 9.5µs
6 6 20µs 19.62µs 19.5µs

Il me manque 0,5µs à chaque fois. Et dans le code, ils indiquent qu'il y a 2 cycles en moins si on passe une constante plutôt qu'une variable.
J'ai fait une erreur de mesure?

Quand vous dites

les durées des impulsions du bas sont de 0,125µs

c'est une mesure précise sur l'oscilloscope à chaque fois ?

La boucle for

    for (byte impulsion = 0; impulsion < num; impulsion++)
    {
      digitalWriteFast(infos, HIGH); // Pour étallonage
      digitalWriteFast(infos, LOW); // Pour étallonage
    }

n'a pas le même coût lorsque num vaut 0 (aucun test positif pour boucler) que quand num est non nul. (ça ne devrait pas coûter 0,5µs cependant)

avez vous essayé dérouler la boucle à la main pour voir le comportement ?

#include <digitalWriteFast.h> // plus facile pour mesurer les temps courts, mais pas indispensable

#define mesure 2  // Mesure des temps
#define infos  3  // Infos sur les temps

void setup()
{
  pinMode(mesure, OUTPUT);
  pinMode(infos, OUTPUT);
  noInterrupts();
}

void loop()
{
  // num = 0
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(0);
  digitalWriteFast(mesure, LOW);

  // num = 1
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(1);
  digitalWriteFast(mesure, LOW);

  // num = 2
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(2);
  digitalWriteFast(mesure, LOW);

  // num = 3
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(3);
  digitalWriteFast(mesure, LOW);

  // num = 4
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(5);
  digitalWriteFast(mesure, LOW);

  // num = 5
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(10);
  digitalWriteFast(mesure, LOW);

  // num = 6
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(infos, HIGH); // Pour étallonage
  digitalWriteFast(infos, LOW); // Pour étallonage
  digitalWriteFast(mesure, HIGH);
  delayMicroseconds(20);
  digitalWriteFast(mesure, LOW);

  // petite pause
  delayMicroseconds(50);
}

hello
ton graph est issu de saleae qui tourne sur ton PC . donc avec son horloge.
tes données son issues de ton UNO donc de son horloge.

deux horloges différentes peuvent te donner des écarts.
j'ai fais le test suivant

#define mesure 2 // Mesure des temps
#define infos 3// Infos sur les temps

void setup()
{
  pinMode(mesure, OUTPUT);
  pinMode(infos, OUTPUT);
  noInterrupts();
}


void loop()
{
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(1);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(2);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(3);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(4);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(5);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(6);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(7);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(8);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(9);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(10);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
  PORTD |= 0b00001000;//pd3 digitalWriteFast(infos, HIGH); // Pour étallonage
  delayMicroseconds(20);
  PORTD &= 0b11110111;//pd2 digitalWriteFast(mesure, LOW);
  delayMicroseconds(20);
}

edit: ach, j'ai oublié de virer/mettre a jour les commentaires

exc_micro.PNG

exc_micro.PNG

ton graph est issu de saleae qui tourne sur ton PC . donc avec son horloge.
tes données son issues de ton UNO donc de son horloge.

Il y a effectivement deux horloges différentes, l'une est celle de l'Arduino, l'autre je pense qu'elle est plutôt dans l'analyseur logique. Celle de l'analyseur logique tourne un peu plus vite. J'ai fait un programme que contient 4096 lignes, une sur deux est

digitalWriteFast(infos, HIGH);

les autres sont

digitalWriteFast(infos, LOW);

Cela me permet d'avoir un signa carré avec peu de cassures dues à la boucle.

Si l'échantillonnage par l'analyseur se fait loin des fronts, j'ai un signal parfaitement carré 2T haut, 2T bas. Régulièrement, l'échantillonnage passe sur les changements de niveau et j'ai alors des perturbations genre 3T haut pour 1T bas ou l'inverse. Voici ce que j'ai:


Dans la pertie gauche, j'échantillonne deux fois en haut, deux fois en bas. Dans la partie droite, en étant quasiment sur les fronts, j'ai t échantillons haut pour un bas. En poursuivant, l'échantillonnage se décalant encore, je retrouve le carré 2T haut pour 2T bas. Puis plus tard, je vais revoir ce T 1T. Je ne vois pas l'inverse comme si le temps haut était un poil plus long ou si en mesurant pile poil sur un front on ait un état haut. Environ toutes les 2700µs j'ai ce phénomène. Il y a donc une différence de 0.0625µs toutes les 2700µs Ce n'est pas ce qui peut expliquer la différence.

c'est une mesure précise sur l'oscilloscope à chaque fois ?

La mesure est faire sur la courbe numérisée de l'analyseur. Mais sachant que de temps ne temps l'analyseur prend la mesure sur les fronts, le fais la mesure sur plusieurs trains.

[...]n'a pas le même coût lorsque num vaut 0 (aucun test positif pour boucler) que quand num est non nul.

Les mesures n'incluent jamais une boucle. Les boucles for me servent uniquement de repères. Que je développe ou pas n'a pas d'influence sur les mesures qui se font ailleurs.
Je viens de chronométrer avec le logiciel qui me permet de mesurer les temps des instructions, je trouve exactement le même résultat.
Dans le premier essai, j'avais

delayMicroseconds(largeur[num]);

En passant à

delayMicroseconds(valeur);

je gagne 7 cycles d'horloge et en mettant un entier, je gagne encore 12 cycles.@dfgh doit donc trouver 19 cycles (1,18µs) en moins que moi, 1,06µs si PORTD.... n'a pas été déduit (0.125µs)

Pas trop cohérent avec les mesures de dfgh, mais dans tous les cas delayMicorceconds est plus courte que prévu.
En tout cas rien n'est prévu pour compenser le rajout de la mise à l'heure du système que je viens de mesurer enfin de façon plus précise (variation du temps d'impulsion rapides). La mise à l'heure du système prend 6,188µs si millis() s'incrémente de 1, et 6,500µs quand millis() s'incrémente de 2.

Je chipote sur un temps trop court de 1µs, et les gros sabots de l'horloge rajoute plus de 6µs, possiblement dans delayMicorceconds(2)!

Bon je retourne à non bricolage et à mon Uno multitâches, si j'ai du temps.

Il y a probablement une différence de précision dans les horloges.
Celle de l'analyseur est pilotée par un quartz
Celle de la Uno est pilotée par un simple résonateur moins précis et moins sélectif qu'un quartz.

Je ne sais pas si c'est perturbant pour la mesure actuelle mais ce n'est pas à perdre de vue.

Les boucles for me servent uniquement de repères.

la boucle devrait générer une petite différence puisque il y a une incrémentation et un test et un branchement par rapport à dérouler à la main de HIGH et LOW.

Il y a probablement une différence de précision dans les horloges.

Il y a donc une différence de 0.0625µs toutes les 2700µs

Cela fait 0.023% de différence. Paradoxalement, plus cette différence est petite, plus c'est difficile de faire la mesure. Tout marche très bien si l'échantillonage est au milieu des changements. Quand l'échantillonnage est fait sur les fronts, cela peu faire des erreurs d'1/16µs. Il suffit de regarder un peu plus loin pour vérifier que l'on n'est pas dans ce cas.

la boucle devrait générer une petite différence puisque il y a une incrémentation et un test et un branchement par rapport à dérouler à la main de HIGH et LOW.

Je dirais même que c'est la boucle qui prends le plus de temps. En agrandissant le chronogramme:
chrono.gif

de 0,125µs on passe à 0,437µs

Mais on s'en moque la mesure n'inclue jamais une boucle.

chrono.gif

Je pensais avoir compris que vous utilisiez le petit signal de référence comme moyen de référence en connaissant la durée d’un digitalWriteFast