ESP32 : pulse digital le plus court possible

Bonjour

La question est dans le titre : comment réaliser avec un ESP32 à 160MHz un pulse digital le plus court possible ?

Si je fais un truc du genre :

digitalWrite(pin,HIGH);
delayMicroseconds(1);
digitalWrite(pin,LOW);

sachant que, pour delayMicroseconds :

This function works very accurately in the range 3 microseconds and up. We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.

J'aurai un pulse (au mieux) d'une microseconde alors que la période d'horloge est de 6.25 ns, soit 160 fois plus court. Il doit donc être possible de faire mieux mais comment ?

Au final, j'aimerais générer un signal binaire à la fréquence la plus haute possible sur une pin digitale.

Bonjour lesept

et si tu enlèves le delayMicroseconds(1) , combien de temps dure l'état haut sur la sortie ?

Je ne sais pas : comment le mesurer ? Avec l'analyseur logique ?

EDIT : j'ai refait mes calculs dans le message précédent, et corrigé d'un ordre de grandeur. Il y a donc de la marge...

hello
"Je ne sais pas : comment le mesurer ? Avec l'analyseur logique ?"

ou en éditant le code assembleur et en comptant le nombre de cycles entre les deux états de la sortie.

dfgh:
ou en éditant le code assembleur et en comptant le nombre de cycles entre les deux états de la sortie.

Ça, je ne sais pas faire, mais j'aimerais bien apprendre ! J'ai un PC Windows 10, quels outils utiliser pour ça ? Et quelle doc sur l'assembleur ?

J'ai fait de l'assembleur il y a ... 35 ans, sur un LH5801, un processeur 8-bit similaire au Z80, mais en version CMOS (c'était un Sharp PC 1500, mon premier ordinateur de poche - nostalgie, nostalgie)...

Salut

Pour faire ce que tu veux, il vaudrait mieux passer par une écriture directe dans les ports, en C, sans passer par digitalWrite().
Ensuite, entre l'écriture du 1 et l'écriture du 0, intercaler un ou plusieurs NOP.

@+

Tu as de la doc ou des liens pour comprendre le fonctionnement des ports de l'ESP32 ?

Pas du tout, mais en cherchant sous google "ESP32 Direct IO Port Manipulation" cela ne devrait pas poser de problème.
Au pire cherche le code de la fonction digitalWrite() de la librairie ESP32 et regarde ce qu'elle fait exactement.

@+

lesept:
Tu as de la doc ou des liens pour comprendre le fonctionnement des ports de l'ESP32 ?

C'est le sujet que je voulais aborder plus un coté matériel.
Les circuit Espressif ne sont pas des microcontrôleurs classiques.
Ils sont fabriqués par Cadence qui fourni avec son environnement de développement matériel des circuit non terminés.
Espressif fait des compléments (wifi, bluetooth, etc ) sur l'environnement de dev matériel Cadence.
Cadence fabrique le circuit et le livre à Espressif.
https://ip.cadence.com/
Les responsabilités de documentation sont partagées entre deux sociétés ce qui ne simplifie pas la tâche.

Ensuite vient le coté 32 bits.
Même si ce ne sont pas des ARM il existe plusieurs bus horloge à l'intérieur des micros et tous ne tournent pas à la vitesse horloge. Notament celui qui gère les sorties.
pepe avait fait une communication à ce sujet.

Logiciel :
Il faudrait connaître ce qu'Espressif a placé dans ses fonctions.
Chez Wiring puis arduino la fonction digitalWrite() comprend :

  • la conversion de la dénomination en Port vers celle de 1 à N de l'IDE Wiring/Arduino
  • les différents contrôles pour vérifier que la sortie n'est pas déjà utilisée avec une "alternate function" et la raz des différents registes
  • enfin l'écriture dans le port.

Je crains que la première limitation sera dans la fréquence de l'horloge qui commande les sorties.
A quoi pourrait bien servir une sortie qui commute à 160 MHz ?
D'autant que pour pouvoir fournir du courant à 160 MHz il faut en consommer beaucoup en amont.

Cela n'a pourtant pas l'air sorcier :

extern void IRAM_ATTR __digitalWrite(uint8_t pin, uint8_t val)
{
    if(val) {
        if(pin < 32) {
            GPIO.out_w1ts = ((uint32_t)1 << pin);
        } else if(pin < 34) {
            GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
        }
    } else {
        if(pin < 32) {
            GPIO.out_w1tc = ((uint32_t)1 << pin);
        } else if(pin < 34) {
            GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
        }
    }
}

Merci Henri, c'est le code de la fonction digitalWrite. J'ai un peu de mal avec ça.

Si je comprends bien, le premier test est sur HIGH ou LOW.

if(val) {

Ensuite si c'est HIGH, selon le numéro de pin (inférieur à 32 ou égal à 32 ou 33) on met dans GPIO.out_w1ts la valeur 1 décalée vers la gauche d'un nombre de bits égal au numéro de pin
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));ou décalé de 1 ou 2 vers la gauche si c'est 32 ou 33GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
Si c'est LOW, même chose avec GPIO.out_w1tc

Mais à quoi correspondent ces GPIO.out_w1ts et GPIO.out_w1tc et surtout leurs .val ? Ce sont des registres ? J’imagine que chaque bit correspond à une sortie.

Dans ce cas, si au lieu de mettre 000001000000...00 on mettait plusieurs 1 dans ce registre, on pourrait avoir plusieurs écriture simultanées sur plusieurs sorties ?

out_w1ts et out1_w1ts désignent certainement deux registres de 32 bits différents.
out_w1ts est utilisé lorsque pin < 32 et l'autre si pin est >= 32 et < 34.
Il faut rechercher la définition de la structure GPIO. Elle doit être dans un des .h inclus dans le fichier.

Dans ce cas, si au lieu de mettre 000001000000...00 on mettait plusieurs 1 dans ce registre, on pourrait avoir plusieurs écriture simultanées sur plusieurs sorties ?

Absolument. C'est l'intérêt principal de la chose.
Quand je pilote des afficheurs 7 segments sur un ARDUINO, c'est ce que j'utilise.
Cela permet une grande rapidité, surtout quand il faut multiplexer 4 ou 6 afficheurs.

@+

Trouvé ceci :

The GPIOs have a configuration register each, but the value is set using 4 32-bit registers, namely GPIO_OUT_W1TS/W1TC and GPIO_OUT1_W1TS/W1TC. You use the GPIO_OUT_* register to modify GPIO0-31, you use GPIO_OUT1_* to modify GPIO32 and higher. When you write an 1 in a bit in a W1TC register, you'll make the GPIOs associated with these bits low, when you write an 1 in a bit position in a W1TS register, you make the corresponding GPIO high. (W1TC = Write 1 To Clear, W1TS = Write 1 To Set.) For both registers, any GPIO written 0 does not change.

Il suffit donc d'essayer ... avant de réussir.
Conserve simplement la config du GPIO : pinMode(pin, OUTPUT);
J'ai l'impression que la correspondance N° pin ARDUINO et ESP32 sera simple à trouver.

@+

Bonjour,
je connais mal l'ESP32, mais le mieux est de consulter le datasheet:

Descriptif:

Datasheet complet:

Sur un Arduino j'utilise le timer1 16 bits pour mesurer le temps:

void setup() {
  unsigned int i;
  Serial.begin(115200);
  TCCR1A = 0; // mode normal
  TCCR1B = 1; // TCCR1B = 1; // clk/1, TCCR1B = 2; // clk/8, TCCR1B = 3; // clk/64, TCCR1B = 4; // clk/256, TCCR1B = 5; // clk/1024,
  TCNT1 = 0;
  bitSet(PORTB, 5); // code à mesurer, allumer led
  bitClear(PORTB, 5); // éteindre led, 2 cycles soit 125ns
  i = TCNT1; // entre 0 et 65535
  Serial.print("Temps: ");
  Serial.println(i);
 }
void loop() {
}

Il faudrait que tu puisses le porter sur l'ESP32, il doit avoir des timers 32bits
On devrait pouvoir manipuler directement les registres I/O.

La gestion des ports de sortie est, AMHA, plus du ressort de Tensilica (acheté par Cadence) que d'Espressif qui ne fait qu'ajouter des fonctions à un microcontrôleur existant qu'il n'a pas construit.
Sauf si Espressif l'a documenté à partir de la doc Tensilica.

Je redécouvre ce sujet et j'ai des informations.
J'ai trouvé cette solution sur internet, je l'ai testé et cela fonctionne et même très bien.

REG_WRITE est une macro qui simplifie l'écriture dans un registre.
Les registres GPIO sont décrits dans le document Espressif : ESP32 Technical References Manual ( 718 pages, désolé)
Les pages concernant les GPIOs vont de 44 à 52.

Exemple pratique :

Déclaration d'une E/S en sortie :

E/S comprise entre 0 et 31 :
REG_WRITE(GPIO_ENABLE_REG, BITX); // X étant le numéro du gpio

E/S comprise entre 32 et 39 : Remplacer ENABLE par ENABLE1.

Mettre une sortie à 1 :
REG_WRITE(GPIO_OUT_W1TS_REG, BITX) ; // S pour Set
Mettre une sortie à 0 :
REG_WRITE(GPIO_OUT_W1TC_REG, BITX) ; // C pour Clear

Idem changer OUT en OUT1 pour les sorties entre 32 et 39.

Mesures :
appareil de mesure : analyseur logique clone Saleae => vitesse d'échantillonage trop faible, ne donne qu'une indication.

ESP32 240 MHz (Horloge des gpio ? )

digitalWrite => ~330 ns
Registes => ~ 50 ns => mesure indicative, trop près des limites de l'analyseur logique

Rappel nano/Uno avec digitalWrite ~ 3700 ns

Note : avec pulseview de sigrok le clone de saleae "peut fonctionner" à 48 MHz : attention synchronisation assez délicate.