ESP32-C3 Super Mini bloqué, la vraie cause

Salut à tous.

Après des heures de tests, j’ai découvert que le sketch ne s’exécute pas du tout si l’option “USB CDC On Boot” n’est pas activée dans l’IDE Arduino. Ce n’est pas juste un problème de port série — le microcontrôleur reste bloqué en mode téléchargement, même avec un sketch valide.

Il ne permute pas en mode exécution après le téléversement.

Solution : activer “USB CDC On Boot” dans les options de compilation.

Cela débloque l’exécution automatique du sketch et permet enfin de voir les messages dans le moniteur série.

Espressif, si vous lisez ceci : il est urgent de documenter ce comportement.

Post mis dans la mauvaise section, on parle anglais dans les forums généraux, je viens de déplacer le post dans la section francophone.

Merci de prendre en compte les recommandations listées dans "Les bonnes pratiques du Forum Francophone".

Espressif ne lira sûrement pas un post en français sur ce forum :slight_smile:

Vous avez lu ceci ?

Avez vous aussi un while(!Serial); dans votre setup() ?

1 Like

Il y a eu une discussion sur le forum.
Je pense avoir apporté la preuve que cette ligne est inutile.

Il faut séparer ce qui se voit de ce qui se produit.
Ce n’est pas dans l’esp que cela se passe, c’est immediat, c’est une illusion d’optique, le responsable est l’ide a qui il faut du temps pour basculer du mode programmation au mode moniteur.

Seul un delay bloquant de plusieurs secondes est efficace mais seulement quand on est en phase de mise au point, en production c’est inutile.

En production avec un simple terminal sur la liaison série la réponse est toujours immédiate, parce que le terminal est toujours pré-configuré.
Il suffit de faire le test pour le constater.

Sur ce point de la configuration l’ide arduino est plus rapide que plateformIO parce qu’il faut spécifier manuellement à l’ide arduino le port a ecouter. PIO le fait automatiquement ou manuellement. En mode automatique l’établissement de la connexion est plus lent.

@gero33
Ton explication ne tiens pas.
Je m’explique.
J’ai utilisé des cartes esp avec deux usb, le natif ou en passant par un ch340 et rx et tx.

Quel que soit l’usb choisi et la configuration adaptée tout se passait sans anicroches.
Espressif n’a rien à signaler.

S’il n’y a pas de ch340, sur une carte super mini il n’y en a pas, c’est clair qu’il faut dire a la puce d’activer le mode emulation USB, elle ne va pas le déterminer toute seule.

Je n’ai pas de C3 mais il me aemblait que la condition while(!Serial); attend la connexion CDC USB, ce qui ne se produit que lorsque le microcontrôleur a été énuméré par l’ordinateur et que le port série virtuel est ouvert.

Si “USB CDC On Boot” n’est pas activé, le port n’apparaît pas, donc l’opérateur surchargé de Serial reste faux et la ligne bloque indéfiniment.

(Sur les ESP32 classiques utilisant le port série via un convertisseur USB-UART, Serial est toujours “true” dès que le MCU démarre. - comme sur le UNO ou MEGA)

Ce n’est pas le cas avec mes diverses cartes dotées d’un ESP32-C3 dont la Super Mini.

  1. Si “USB CDC on boot” est désactivé, l’ESP32-C3 démarre tout seul en fin de flashage et exécute sans pb le programme Blink

  2. si j’ajoute un while(!Serial) en fin de setup() dans le programme Blink l’ESP32-C3 démarre tout seuil , commence à éxécuter le code flashé, mais la condition portant sur le port série n’étant pas vérifiée le clignotement de la led ne se fait plus.

    Ce comportement me parait logique, sans surprise, je ne vois pas ce qu’Espressif aurait à documenter de plus sur son site à ce sujet, que ce soit pour le soc ESP32-C3 ou pour le core Arduino pour ESP32

Ceci dit Espressif n’est pas responsable des éventuels défauts de conception et/ou de réalisation des multiples cartes qui incorporent un ESP32-C3.

OK donc ça confirme bien ma compréhension

il me semble que le port série USB natif, si utilisé par le bootloader, disparait à la fin du flashage, le code ne peut en bénéficiér s’il n’est pas compilé avec ‘USB CDC on boot’ activé

Oui, mais sans while(!Serial) il démare aussi :grinning_face:.
Ce while(!Serial) est apparu avec le Léonardo (avr 8 bits 16 MHz).

Pour ce micro avr 8 bits 16MHz, le basculement de mode USB pouvait prendre du temps, ce qui reste à confirmer, je n'ai pas d'atmega32U2.
Mais, ceux qui en dispose peuvent faire la manip que je décrit pour les ESP32-C3 que j'ai testé.

J'ai tenté de mettre cette ligne while(!Serial) avec un RP2040 et un ESP32, cela n'a rien résolu.
Je l'ai remplacé par un délai, cela a fonctionné, mais en masquant l'origine du problème.

Dans le programme, en tête de setup() j'ai mis :

void setup(){
Serial.begin(115200);
//while(!Serial);  NON NON NON
//delay(2000);  NON NON NON
Serial.print("Tu vois que j'imprime sans while(!Serial) !");

..........
}

Mode opératoire :

  • Je programme avec une IDE. Une fois le micro programmé je n'utilise plus l'IDE, mais j'utilise un terminal, CuteCom, très simple,
  • Je configure le port à écouter et le débit.
  • J'ouvre le port sur Cutecom. Le logiciel est prêt pour écouter le port.
  • Je fais une RAZ (Reset) du programme sur le micro.
  • Le micro redémare.

Dans le terminal, après les informations de boot, je vois s'afficher instantanément :
Tu vois que j'imprime sans while(!Serial) ! :grinning_face:

Il me semble que c'est la démonstration que ce n'est pas un probleme de stabilisation de l'UART de l'ESP32 puisque je n'ai mis aucune boucle d'attente ni de delais bloquants.
J'ai seulement changé de terminal série.

Mieux avec l'IDE Arduino où il faut préciser le port usb à écouter, si on fait juste un Reset alors que le moniteur est en service cela imprime aussi très vite.

Avec PIO, par défaut le logiciel fait une recherche automatique du port USB, cela prend plus de temps qu'avec le moniteur de l'IDE Arduino.
PIO peut permettre de fixer le port manuellement,, quand j'aurai le temps de rechercher la syntaxe, je ferai la manip.

Je suis persuadé que c'est bien un fonctionnement, somme toute normal, des IDE qui sont des agrégateurs de programmes.

Un seul programme à la fois peut prendre le contrôle de l'USB.
Il faut bien laisser le temps à l'IDE de fermer les Esptools utilisés pour la programmation, et de rouvrir le moniteur, qu'elle a fermé avant de lancer l'opération de programmation.

Si pendant ce temps 'technique" le micro envoie des Serial.print ils sont perdus.

Mon interprétation est que cela ne se voyait pas des micros lents et aussi que l'IDE issue de Wiring, lui même issu de Processing, était plus simple et pouvait être plus rapide que la V2 (c'est une supposition). La vitesse du PC hôte compte aussi.

Avr atmega328p = 8 bits tournant à 16 MHz.
ESP32-C3 = 32 bits tournant à 160 MHz.

J'avais déjà rencontré ce phénomène avec des RP2040.
C'est la répétition avec les ESP32 qui m'a fait approfondir le sujet.

Le meilleur conseil que je peux donner :
Soit :
Pour la phase de mise au point, vous ajoutez un délai de durée compatible avec votre IDE.
Si ce délai ne vous gêne pas en phase de production, vous le laissez, sinon vous le retirez pour la compilation finale.
Soit :
Vous n'ajoutez rien et vous faites un reset immédiatement après les premières écritures sur le moniteur.
Comme le moniteur sera resté actif, vous verrez les premières sorties.

Bien entendu !!

J’ai seulement voulu évoquer comment un while(!Serial) peut entraver l’exécution complète d’un code ,sans perturber le démarrage de l’ESP32-C3 après flashage, c’est probalement ça la ‘vraie cause du bloquage’ évoqué par @gero33 jusqu’à preuve du contraire

Perso : j’évite systématiquement les while(!Serial) avec tous les ESP32-x en bus USB natif

Quand branchez vous l’ESP ? (ou est il resté branché après sa programmation ?)

Si le périphérique était déjà branché et reconnu par l’OS, le pilote conserve l’association avec le même port et dans ce cas, l’énumération et la disponibilité du port peuvent sembler quasi instantanées après un reset, et Serial peut devenir true presque immédiatement, plus rapidement que le temps mis par l’ESP pour atteindre le setup()

(Il me semble que les drivers gardent même un cache quand on débranche et réaffecté le même port au même device si possible )

C'est possible........ou pas.
Je ne fais que constater, mes connaissances théoriques en la matière étant insuffisantes.
Mais j'ai une certaine expérience dans l'analyse de ce qui se voit et de ce qui cause.

Sans débrancher quoi que ce soit, c'est très clair.
Si je lance un téléchargement avec l'IDE Arduino sans while ni délai.

  1. je perds les premiers serial.print de setup.
    Je n'ai jamais rien perdu dans loop.
    Ce n'est pas parce que je n'ai rien perdu dans loop que quelqu'un d'autre, avec un autre matériel, n'en perdra pas.

  2. Si, sans rien changer à l'IDE après une programmation, je fais un reset, au redémarage du micro je n'ai jamais perdu un message que ce soit avec le moniteur Arduino ou celui de Vscode.

  3. Si je prend l'IDE Arduino et si je déconnecte une carte et que je la reconnecte, l'IDE arduino avec sa configuration manuelle met peu de temps à la reconnaitre, c'est assez subjectif.

  4. Si je fais pareil avec PIO et sa recherche automatique, l'IDE met beaucoup plus de temps pour reconnaitre la carte. Cette fois, c'est du comparé.

  5. Si, toujours sans déconnecter quoi que ce soit, je ferme le moniteur de l'IDE et que j'ouvre un terminal, si je reset la carte je n'ai jamais rien perdu pendant le redémarrage.

Maintenant une ligne while(!serial) ne peut pas faire de mal même si je n'ai jamais vu son efficacité et donc son utilité.
Cela me parait être une vieillerie apparue avec le Léonardo et que l'on traine, comme souvent les vieilleries trainent dans la sphère arduino.

Tout évolue, tout s'améliore, les systèmes d'expliotations aussi.

En résumé, la perte des premiers Serial.print() se constate aussi bien avec l'Ide Arduino que plateformIO. Il n'y a pas de pertes des premiers Serial.print si l'IDE est en situation stable.

Quand un micro est en production, on ne le connecte pas à une IDE.
Au premier démarrage d'un micro en production, ou si on fait un Reset, on ne perd pas de message.

Ajouter une temporisation pour la phase de développement est du confort qui n'est pas pénalisant en production.
Donc en soit cela ne me gêne pas. Mais la cause des pertes de messages n'est pas l'absence de while(!serial); puisque sans cette ligne on ne perd pas de message en situation stable de l'IDE.

Dans Linux si j'ouvre un terminal et que je fais sans IDE en service et sans carte connectée :
$ls /dev/tty*
je ne vois pas apparaitre de ttyUSBx (ch340) ou de ACMx (USB natif).

Dès que connecte une carte à un port USB, je vois apparaitre
ttyUSB0 ou ttyACM0
Je vois que l'énumeration est automatique et instantanée.
Peut-être que Windows a besoin de cet artifice :grinning_face:

Pour revenir au sujet, le titre est faux et induit des débutants en erreur.

@gero33 ne savait pas que l'ESP32 n'active pas automatiquement l'USB natif, il faut le lui demander dans les directives des IDE.

Alors nous sommes d'accord, je ne l'avais pas compris comme tel.

Perso je pense que ça fonctionne comme attendu

Sur les plateformes sans énumération nécessaire , l’opérateur booléen surchargé sur la classe HarwareSerial est toujours vrai et sur les autres il faut attendre que l’énumération qui se fait côté hôte soit terminée donc le timing est hors de contrôle de l’Arduino et dépend du fonctionnement de l’OS hôte, d’un cache éventuel etc…