Contrôler la fréquence d'un Arduino...

Voici une manip que je trouve géniale et qui a été proposée par ChristopheFr sur le forum français d’arduino.cc. Son idée permet de contrôler très simplement la fréquence réelle de fonctionnement des cartes Arduino et compatibles. Et cela sans aucun matériel complexe! Il suffit de télécharger le logiciel gratuit Processing.

processing3-logo

Dans l’éditeur arduino, on copie/colle le sketch suivant et on l’upload sur la carte:

void setup()
{

Serial.begin(115200);
}

void loop()
{

static uint32_t t = micros();

while (micros() - t < 16000000);
t += 16000000;

Serial.write('1'); // envoi un octet sur le port série toutes les 16 secondes
}

Et dans l’éditeur Processing, on utilise le code suivant:
import processing.serial.*;
Serial Port;
int t1,t2;
void setup()
{
int i;
Port = new Serial(this, "COM7", 115200); // remplacez COM7 par le port occupé par l'Arduino, sinon bug!

t1 = millis();
while(true)
{
while(Port.available() > 0)
{
i = Port.read();
t2 = millis();
println(256000000 / (t2-t1) + "KHz"); // affiche la fréquence du quartz de l'Arduino en KHz toutes les 16 secondes (la première mesure n'est pas fiable).
t1 = t2;
}
delay(1);
  }
}
void draw()
{
}

C’est terminé! On lance l’exécution du code sur Processing et on patiente.

Testé chez moi avec la MKS MINI V2.0 Makerbase et une carte Arduino MEGA de chez SUNFOUNDER:
- La SUNFOUNDER tourne à 15996KHz (avec +-1 KHz de variation entre les mesures).
- La MKS MINI est parfaitement calibrée à 16000KHz.

J’ai ensuite testé en chauffant les cartes avec un sèche cheveux:

- La carte SUNFOUNDER perd quasi instantanément 10Khz et elle descend encore un peu pour se stabiliser autour des 15983Khz au bout de quelques minutes. - La MKS MINI ne bronche pas et reste parfaitement stable à 16000KHz. Voilà qui confirme la MKS MINI comme un excellent choix pour mon projet. Sa fréquence est conforme et elle ne souffre pas de dérive en fonction de la température ambiante. :) Moralité: attention aux cartes choisies pour un usage en astronomie. Si possible, vérifiez bien dans les specs qu’elles sont équipées de Quartz. Moi je me suis fait berner de visu avec la SUNFOUNDER qui est équipée de résonateurs céramiques en boitier métallique ressemblant à un boitier de Quartz (merci à al1fch pour l’info). Lien vers le topic original lancé par ChristopheFr: Mesurer la fréquence d'un Arduino avec Processing

Timer hardware ou les 55 cycles manquant...

Je ne sais pas pour vous mais c’est plus fort que moi: Quand quelque chose ne se passe pas comme prévu j’ai besoin de comprendre le « pourquoi? ». Lors de l’écriture de la librairie RunLoop pour Arduino, j’avais constaté à l’époque un décalage sur les timers hardware entre la période demandée par le programme et la périodicité réellement constatée en sortie avec l’analyseur logique.

runloop

Le problème c’est que toutes les librairies testées avaient le même décalage que moi: un peu plus de 3us!!! Cela peut paraitre ridicule vu de loin mais pour des fréquences dépassant le KHz, l’erreur est de plus en plus problématique si l’on a besoin de précision. Hors en astronomie, pour le pilotage des moteurs pas à pas, la précision est de rigueur. A l’époque, j’avais donc intégré ce décalage dans RunLoop en l’estimant de manière empirique autour des 3,3us.

Et voilà qu’aujourd’hui, je viens de tomber sur l’excellentissime blog de Bill Grundmann! Si vous lisez l’anglais, c’est par ici que cela se passe:

The overhead of Arduino Interrupts

Pour résumer: il a étudié le phénomène à l’oscilloscope et décortiqué le code assembleur de la librairie Arduino. Et effectivement, la levée d’interruption entraine un surcout de 55 cycles! Soit 55*0,0625 = 3,4375us précisément!!! Hors faute de le savoir, les librairies qu’on trouve sur le net n’en tiennent pas compte. Et bim!

J’ai donc le plaisir de vous annoncer que je viens d’en profiter pour affiner encore un peu plus le code de RunLoop et de le publier sur mon github. Un test à 20Khz, montre maintenant une périodicité quasi parfaite à +-40ns près d’après l’analyseur logique (hors avec ses 12MS/s max on est dans la limite de précision d’échantillonnage donc même pas sûr que la variation résiduelle soit réelle).

50us-20khz


Note: en toute logique, le phénomène constaté n’est présent que pour des timers hardware levant une interruption au niveau logiciel. Je ne pense pas qu’un usage en PWM soit concerné.

Veni, vidi, vici et big up à Bill! :)