Conversion analogique rapide

Bonjour à toutes et à tous,

Faisant un essai de rapidité de lecture d'une entrée analogique avec un Nano, j'ai trouvé qu'il faisait de l'ordre de 8900 lectures par secondes. Ça va pas loin !

Je me suis dit c'est un CAN 10 bits, peut-être est-il configurable en 8 bits pour accélérer la cadence. J'ai lu des articles sur les registres correspondants, et, à mon avis, c'est un 10bits, c'est un 10 bits, point final.

Dans ces registres, j'ai vu que le CAN était piloté par la fréquence du quartz divisée par la valeur des trois bits de poids faibles du registre ADCSRA et qui sont, par défaut à 128 soit 125 kHz.

Je me suis dit, pour jouer, je vais voir si en changeant ces bits, j'obtiens quelque chose.

Et ben là, j'en reste sur le c.. :astonished: Voilà ce que j'obtiens :

ADSSRA = 10000111 : Fcan = 125 kHz ; Nb lectures / seconde = 8900
ADSSRA = 10000110 : Fcan = 250 kHz ; Nb lectures / seconde = 17800
ADSSRA = 10000101 : Fcan = 500 kHz ; Nb lectures / seconde = 33200
ADSSRA = 10000100 : Fcan = 1 MHz ; Nb lectures / seconde = 62500
ADSSRA = 10000011 : Fcan = 2 MHz ; Nb lectures / seconde = 102000
ADSSRA = 10000010 : Fcan = 4 MHz ; Nb lectures / seconde = 155000
ADSSRA = 10000001 : Fcan = 8 MHz ; Là, ça déconne

Jusqu'à 4 MHz, la valeur mesurée est toujours bonne !

On voit qu'il n'y a pas doublement du nombre de mesures/s à chaque fois que je multiplie la fréquence par 2, c'est sûrement lié au temps "constant" de mise en œuvre de la fonction "analogRead()".

C'est bluffant ! On doit certainement pouvoir aller encore plus vite si, au lieu d'utiliser la fonction analogRead(), on le fait par la programmation directe des registres. Mais je ne sais pas (encore) faire.

Voici le petit sketch qui me permet de voir ça ( j'ai un petit pont diviseur résistif entre VCC et GND et relié à A3:

int analog;
uint8_t freq;

void setup() {
  Serial.begin(9600);
  pinMode(A3, INPUT);
  freq = ADCSRA;
  Serial.println(freq, BIN);
  ADCSRA = 130; // faire baisser cette valeur jusqu'à 130
  freq = ADCSRA;
  Serial.println(freq, BIN);
}

void loop() {
  unsigned long t0 = millis();
  for (int i = 0; i < 10000; i++) {
    analog = analogRead(A3);
  }
  Serial.println("A = " + String(10000000 / (millis() - t0)) + "  " + String(analog));
}

Cordialement.

Pierre

plein d'info ici

à mon avis, c'est un 10bits, c'est un 10 bits, point final.

Lis la datasheet on peut l'utiliser en 8 bits.
De mémoire il suffit de ne lire que le deuxième registre.
Comme c'est la lecture de ce deuxième registre qui autorise l'acquisition suivante il faut donc configurer au préalable l'ADC pour inverser l'ordre de lecture des registres.
Tout est indiqué dans la datasheet du micro.
Mais abandon obligatoire de la fonction analogRead et utilisation des registres. Je suis loin d'être un dieu de la programmation et j'y suis arrivé alors .................

Il y a aussi une note d'application qui donne la possibilité inverse : porter la précision à "un équivalent" 12 bits (pour être honnête je n'y ai pas compris grand chose mais je signale son existance).

Le point à surveiller est la résistance équivalente du montage qui attaque une entrée ADC.
On peut fortement augmenter la fréquence d'échantillonnage à condition d'avoir une résistance équivalente faible.
C'est un bête probleme de temps de charge des capa internes de l'ADC.
Il suffit de faire des tests : mesures à fréquence basse et mesures à plus grande vitesse : si le résultat ne change pas c'est que c'est bon.

68tjs:
Lis la datasheet on peut l'utiliser en 8 bits.
De mémoire il suffit de ne lire que le deuxième registre. ...

J'ai relu plusieurs fois cette partie de la doc, mais de ce que comprends, bien qu'on puisse ne se servir que des 8 bits de poids forts (bit ADLAR = 1), le travail de conversion par approximations successives se fait quand même entièrement, c'est-à-dire sur les 10 bits. On ne doit donc gagner en temps que la lecture du registre ADCL J'essaierai de mesure cela.

68tjs:
Le point à surveiller est la résistance équivalente du montage qui attaque une entrée ADC.

On peut placer en amont un ampli OP. Ce sera même utile pour mesurer des tensions négatives et, soit mettre du gain soit de la division en fonction de ce que l'on veut mesurer

68tjs:
Le point à surveiller est la résistance équivalente du montage qui attaque une entrée ADC.
On peut fortement augmenter la fréquence d'échantillonnage à condition d'avoir une résistance équivalente faible.
C'est un bête probleme de temps de charge des capa internes de l'ADC.
Il suffit de faire des tests : mesures à fréquence basse et mesures à plus grande vitesse : si le résultat ne change pas c'est que c'est bon.

Dans la doc que j'ai lue, qui date de 2015, ils notent que la fréquence max sans dégradation de performance peut être de 1 MHz. Peut-être est-elle encore bonne sur 8 bits à 4 MHz : à tester.

Cordialement.

Pierre

Il y a souvent beaucoup à gagner quand on veut arriver à faire quelque chose rapidement avec Arduino, à oublier les fonctions de base Arduino et à manipuler les registres à la place. C'est particulièrement vrai pour le pilotage des broches, qui permet notamment de les commuter par port, donc jusqu'à huit à la fois.
On pourrait même envisager de réécrire les fonctions pour se garder la syntaxe originale, qui est pratique, mais se passer de toute la série de vérifications (et potentiellement de temps perdu) qu'induisent les fonctions d'origine.

Si on devait réécrire autant oublier la syntaxe originale (fonctions) et passer en objet qui est dans ce cas plus adapté.
Exemple : Mbed

  • Instantiation :
    DigitalOut loupiote(13) ;
  • Utilisation :
    loupiote = 1;
    ou loupiote = 0 ;

En effet, le système gagnerait encore en simplicité! Mais je ne suis pas certain que l'état de mes connaissances pour le moment me permette d'envisager une solution de ce genre.
Comment ça se passe? Il faudrait définir des surcharges d'opérateur dans une classe? Genre ça?

Class DigitalOut{
public:
    DigitalOut(int pin);

    operator=(bool state);

};

Cela ne sert à rien de chercher la rapidité si c'est pour mettre un délai de 100ms dans la boucle (déjà vue).

Tout dépend! On peut avoir besoin de commuter une ou des entrées le plus vite possible, et n'avoir rien d'autre de crucial à faire à coté!
Mais je suis d'accord, il faut que ce soit homogène.