Vitesse IO sur module ESP8266

Les modules ESP8266, devenu très populaires vu leurs prix et esp8266-e08performances, peuvent provoquer quelques questions si l’on n’est pas habitué aux processeurs ARM. Le processeur (ARM) de l’ESP8266  exécute les instructions à 80Mhz (la fréquence peut-être doublée par soft). Si l’on utilise l’environnement de programmation (IDE) Arduino, ainsi que les routines populaires Arduino, on peut rencontrer quelques surprises quant à la vitesse d’exécution des fonctions digitalWrire() si on la compare à un processeur traditionnel (AVR/Microchip). Ces processeurs peuvent générer un signal carré d’une fréquence de la moitié de la fréquence oscillateur (moyennant que l’on ne fasse rien d’autre pendant ce temps. Le processeur ESP8266 programmé dans Arduino génère un signal de 160khz. Ce que l’on oublie dans notre cas, c’est que la vitesse GPIO d’un processeur ARM doit-être définie en début de programme. Ceci est le cas si l’on programme sous Linux ou GNU mais ne l’est pas avec l’environnement Arduino, la vitesse GPIO ayant été défini lors de l’intégration ESP. On ne sait donc pas quelle vitesse a été choisie!

Regardons donc plus en détail la vitesse Entrées/Sorties de l’ESP8266.

 

1. Test digitalWrite() dans loop. Nous obtenons une impulsion de 450ns tous les 6.24us, pas étonnant, on ne sait pas ce que fait Arduino en dehors de la routine loop(), fréquence du signal obtenu, 160khz.

2. Test digitalWrite() avec while(1) dans setup, on évite ainsi le temps perdu par l’implantation Arduino, pas de surprise, on obtient un signal carré de 2x 450ns = 1.11Mhz

3. En connaissant un peu ARM, on peut s’imaginer qu’il existe une librairie plus efficace qui permet de changer l’état des GPIO directement. Une librairie gpio.h est disponible sous ESP8266/ARDUINO. Cette libraire permet d’écrire directement dans les registres. Il existe un registre CLEAR et un registre SET utilisés dans les tests qui suivent. Il suffit de mettre le bit correspondant au GPIO 1 et le tour est joué.

GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << PIN); // pour SET de l’IO (PIN)

GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << PIN); // pour CLEAR de l’IO (PIN)

 

Même test que pour 1/2 ci dessus. Dans loop, on obtient une impulsion de  110ns tous les 5.54us

4. Comme dans .2, nous faisons une boucle infinie, impulsion de 88ns tous les 176ns donc 5.68mhz

Il est possible que l’on puisse encore optimiser plus la routine IO en changeant la vitesse GPIO. Je ne l’ai pas essayé ici.

A retenir, la gestion GPIO sur Arduino n’est pas optimale pour ESP8266 (à tester pour les processeurs AVR également). Par contre si l’on veut faire une routine I2C ou UART soft, on a intérêt à utiliser les fonctions GPIO et non pas ceux de la librairie Arduino.

 

Plus de détails sur le module ARM/WIFI ESP8266 lors de notre prochaine conférence le 7.10.2016

Rolf Ziegler Sept. 2016

Code utilisé pour le test fast_io.zip

Attention, les commandes GPIO ne sont pas valable pour toutes les pins. Je viens de découvrir que la pin 16 n’est pas sous contrôle de GPIO mais de RTC.

 

4 pensées sur “Vitesse IO sur module ESP8266

  • 16 septembre 2016 à 10:03
    Permalink

    Question: comment doit-on définir: ‘GPIO_OUT_W1TS_ADDRESS’ ?
    Sinon on obtient: was not declared in this scope

    • 4 décembre 2016 à 11:54
      Permalink

      il suffit d’ajouter « #include gpio.h » dans l’entête du fichier.

  • 16 septembre 2016 à 10:11
    Permalink

    GPIO_OUT_W1TS_ADDRESS est un registre du processeur ARM, J’ai juste ajouté #include « gpio.h » dans mon code (pour ESP8266). Ne fonctionne bien sure pas pour les cartes Arduino !

    Pour info, gpio.h est installée avec la librairie de base. On peut également la trouvé sur git dans le paquet suivant: https://github.com/esp8266/Arduino/tree/master/tools/sdk/include

  • 19 septembre 2016 à 7:14
    Permalink

    Très intéressant, j’ai effectué un test identique avec :
    – une carte arduino Uno ATMega328
    – Arduino 1.6.7

    TEST 1 :
    Voici le programme :

    void setup() {
    pinMode(3, OUTPUT); // initialize digital pin 13 as an output.
    }

    void loop() {
    digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
    digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
    }

    Résultat :
    la fréquence vaut 94 kHz, le signal est pratiquement carré, 5.08ns à 1 et 5.56ns à 0

    TEST 2 :
    Maintenant, comme Rolf, je remplace les fonctions arduino digitalWrite par l’accès direct au registre de sortie du port, soit :

    void setup() {
    pinMode(3, OUTPUT); // initialize digital pin 13 as an output.
    }

    void loop() {
    PORTD |= 0x04;
    PORTD &= ~0x04;
    }

    Résultat :
    la fréquence passe alors à 992kHz !!! en plus, le signal reste à 1 durant 126ns et à 0 durant 882ns.

    TEST 3 :
    Cette fois j’ai utilisé l’environnement AVR Studio au lieu d’Arduino, dont voici le code source :

    int main(void)
    {
    PORTD = 0x0;
    DDRD = 0x4;
    while(1)
    {
    PORTD |= 0x04;
    PORTD &= ~0x04;
    }
    }

    Si l’on regarde le code assembleur généré, on remarque que le compilateur a vraiment optimisé le code de la boucle en utilisant les fonctions de traitement de bits sbi et cbi:
    while(1)
    {
    PORTD |= 0x04;
    86: 5a 9a sbi 0x0b, 2 ; 11
    PORTD &= ~0x04;
    88: 5a 98 cbi 0x0b, 2 ; 11
    8a: fd cf rjmp .-6 ; 0x86

    difficile de faire plus court !

    Résultat :
    la fréquence est de 2,64MHz période à « 1 » : 126ns et période à « 0 » 252ns

    Arduino reste un environnement merveilleux, qui a le mérite d’avoir rendu le micro contrôleur accessible à beaucoup de néophytes ainsi qu’à des professionnels. Evidemment, pour certaines applications l’environnement a ses limites.
    Si l’on compare à l’automobile, une grande partie des conducteurs n’ont pas besoin d’une Ferrari pour se rendre au travail !!! mais leur petite cylindrée leur rend bien service !

Commentaires fermés.