Wierd Serial behaviour of ESP32-C3-SuperMini (no UBS/UART chip)

I'm trying to comprehend the behaviour of the ESP32-C3-SuperMini similar to: https://www.tindie.com/products/adz1122/esp32-c3-development-board-esp32-supermini/.
image

It has no USB/UART adaptor chip (CH340 etc.) and can handle USB natively.
It seems to be able to negotiate with the serial monitor it finds and adapts the baud rate dynamically.

I've configured the IDE (version 1.x) so

image

and run the following program:


void setup() {

  delay( 5000 ) ;
  
  Serial.begin( 9600 ) ;
  printMsg( "9600 baud" ) ;
  Serial.flush() ;
  Serial.end() ;
  delay(500);
  
  Serial.begin( 250000 ) ;
  printMsg( "250000 baud" ) ;
  Serial.flush() ;
  Serial.end() ;
  delay(500);

  Serial.begin( 57600 ) ;
  printMsg( "57600 baud" ) ;
    Serial.flush() ;
  Serial.end() ;
  delay(500);

  
  Serial.begin( 3000 ) ;
  printMsg( "3000 baud" ) ;
  Serial.flush() ;
  Serial.end() ;
  delay(500);

}

void loop() {
}

I get the following results:

So it seems to be able to adapt somehow to the baud rate setting in the serial monitor. Note that the serial monitor is set to a baud rate which matches none of the Serial.begin statements. This is OK (and really quite amazing) but the problem I am actually trying to solve is that when the serial monitor is not available the application (not this minimal, reproducible example) blocks and the published work around I found (Serial.setTxTimeoutMs(0)) does not appear to help.

With a native USB Interface the baudrate is of no meaning ( e.g. the same with Leonardo or others). Apart from initiating a reset at many boards when it is set to 1200 Baud by the PC.

Did you trie to check the USB connection with if(Serial); ?

2 Likes

OK. Thanks. I've learned something. I also found this supporting statement "No, the USB-serial-JTAG ignores any and all baud rate settings and simply sends/receives data at the maximum speed USB allows. . ." from https://esp32.com/viewtopic.php?f=13&t=35150.

The following example code:

const uint8_t led = 8 ;  // led wired HIGH side

void setup() {

  pinMode( led, OUTPUT ) ;
  digitalWrite( led, HIGH ) ;

  Serial.begin( 9600 ) ;

  while ( !Serial && millis() < 10000 ) {
    delay(500) ;
  }

  if ( millis() < 10000 ) {
    Serial.println( "found Serial") ;
    digitalWrite( led, LOW ) ;
    delay( 4000 ) ;
    digitalWrite( led, HIGH ) ;
    delay( 1000 ) ;
  }
  else {
    // no Serial found
  }

}

void loop() {
  for ( int i = 0; i < 500 ; i++ ) {
    Serial.print( i ) ;
    Serial.print( '\t' ) ;
    Serial.println( "the quick brown fox jumps over the lazy dog" ) ;
  }
  digitalWrite( led, LOW ) ;
  delay( 1000 ) ;
  digitalWrite( led, HIGH ) ;
  delay( 1000 ) ;
  
}

Behaves so:

  1. if the ESP32 device is powered by a USB charger then no serial is detected (the onboard led does not switch on for 4 seconds) but the program otherwise works indicated by the led pulsing about once per second in the loop.

  2. if the ESP32 device is powered by a USB cable connected to the PC but no serial monitor is active then the Serial connection is detected (the onboard led switches on for 4 seconds) but the application freezes. The led in the loop does not blink.

  3. if the ESP32 device is powered by a USB cable connected to the PC and the serial monitor is active then everything works correctly.

  4. If I add a statement Serial.setTxTimeoutMs(0) ; after Serial.begin then case 2 works correctly also. Now I have to understand the difference between my minimal example code and the actual (huge) application which still freezes (somewhere) if there is no active serial monitor. Anyway, thanks for your help.

I'm just adding to this because I now appear to have found an IDE configuration which works reliably with the ESP32-C3 supermini and seems to be insensitive to a serial monitor being available or not and quickly and reliably makes network and ntp server connections. The sample program joins a wlan and then gets a time stamp from an NTP server then generates masses of serial output while pulsing the onboard led to show it is active. See the program code for the IDE configuration details. My previous attempts with the integrated USB JTAG adapter enabled appeared to have caused difficulties for the network activity such as joining a wlan or getting a time via NTP, however, I have not studied the behaviour in detail.

image
.
.

/* 
 *  esp32-c3 supermini test
 *  similar to: https://www.tindie.com/products/adz1122/esp32-c3-development-board-esp32-supermini/
 *  
 *  set up IDE with 
 *  (a) Board ESP32-C3 dev module
 *  (b) "USB CDC on boot : enabled"
 *  (c) JTAG adapter disabled
 *  
 *  gets a network connection and a timestamp from NTP and generates lots of serial output.
 *  
 *  This test appears to function correctly:
 *  (a) if the supermini is connected via USB to a PC and the serial monitor is active.
 *  (b) if the supermini is connected via USB to a PC and the serial monitor is NOT active.
 *  (c) if the supermini is powered via a phone charger with no PC connection.
 *  
 */ 




#include <WiFi.h>
#include "time.h"
#include "esp_sntp.h" // https://esp32tutorials.com/esp32-sntp-esp-idf-synchronize-time-ntp/



const uint8_t led = 8 ;  // led wired HIGH side
const char * ssid = "asdfgh123" ;  // your wlan credentials
const char * psk = "opkjhm896" ;  // your wlan credentials



void signalStatus( uint8_t appStatus ) {
  // pulses led to indicate progression through the program
  for ( int i = 0; i < appStatus; i++ ) {
    digitalWrite( led, LOW ) ;
    delay( 100 ) ;
    digitalWrite( led, HIGH ) ;
    delay( 100 ) ;
  }
  delay(1000) ;
}


void setupWlan() {
  // set up wlan

  Serial.println(F("Stopping WiFi")) ; // attempt to clear previous AP connection
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  delay (3000) ; // attempt to stabilise after WIFI_OFF
  Serial.println(F("Starting/Restarting WiFi")) ;


  WiFi.mode(WIFI_STA);  // before begin() ?

  WiFi.begin( ssid , psk );
  Serial.println( "WiFi.waitForConnectResult() . . ." ) ;

  // https://stackoverflow.com/questions/69976104/esp32-wifi-status-always-returns-wl-dicsonnected-sta-mode
  uint8_t status = WiFi.waitForConnectResult();

  // try forever to get a WLAN connection
  static uint16_t tryCount = 0;
  while ( status != WL_CONNECTED   ) {

    delay ( 1000 );
    Serial.print ( "." );
    tryCount++ ;
    if ( (tryCount % 60) == 0 ) Serial.println() ;

    WiFi.begin( ssid , psk );
    status = WiFi.waitForConnectResult();
  }
  Serial.println() ;

  if ( status != WL_CONNECTED ) {
    Serial.println("failed  to join wlan" ) ;
  }
  else {
    Serial.println("joined wlan" ) ;
    signalStatus( 2 ) ;
    signalStatus( 2 ) ;
  }
  Serial.println( "WiFi.localIP(): " ) ;
  Serial.println( WiFi.localIP() ) ;
  Serial.print("Wifi RSSI=");
  Serial.println(WiFi.RSSI());
}


void setupTime() {
  // now get NTP time

  Serial.println("Setting up time");

  const char * timezone = "CET-1CEST,M3.5.0,M10.5.0/3" ;
  struct tm timeinfo;

  sntp_set_sync_interval(120 * 1000UL ) ; // 120 seconds
  configTime(0, 0, "1.ch.pool.ntp.org" ); // First connect to NTP server, with 0 TZ offset

  uint16_t tryCount = 0;
  bool tryOK = false ;


  while (  !tryOK ) { // try forever
    Serial.println("Attempting to get the time from NTP: ");
    // try batch of 60 then clean and retry
    while (  !tryOK && tryCount < 60 ) {
      delay( 1000 ) ;
      tryCount++ ;
      Serial.print('.') ;
      if ( (tryCount % 60) == 0 ) Serial.println() ;
      if (getLocalTime(&timeinfo)) {
        tryOK = true ;
      }
    }
    if ( !tryOK ) {
      Serial.println("clean and retry");
      tryCount = 0 ;
      // reset sntp
      setupWlan() ;
      esp_sntp_stop() ;
      delay(1000) ;
      esp_sntp_init() ;
      delay(3000) ;
      sntp_set_sync_interval(120 * 1000UL ) ; // 120 seconds
      configTime(0, 0, "0.ch.pool.ntp.org" );
    }
  }

  Serial.println() ;
  if ( tryOK ) {
    Serial.println("  Got the time from NTP");
    signalStatus( 4 ) ;
    signalStatus( 4 ) ;
  }
  else {
    Serial.println("  Failed to obtain time from NTP");
  }

  // Now we can set the real timezone
  Serial.printf("  Setting Timezone to %s\n", timezone);
  setenv("TZ", timezone, 1); //  Now adjust the TZ.  Clock settings are adjusted to show the new local time
  tzset();
  delay(1000) ;
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S zone %Z %z "); // special ESP32 print( tm*, const char[] )
}






void setup() {

  pinMode( led, OUTPUT ) ;
  digitalWrite( led, HIGH ) ;

  Serial.begin( 115200 ) ;
  
  // only defined if option "USB CDC on boot" selected in the IDE
  // Serial.setTxTimeoutMs(0) ; // https://github.com/espressif/arduino-esp32/pull/7583

  while ( !Serial && millis() < 10000 ) {
    delay(500) ;
  }

  // pulse led for 4 seconds if serial connection found.
  if ( millis() < 10000 ) {
    Serial.println( "found Serial") ;
    digitalWrite( led, LOW ) ;
    delay( 4000 ) ;
    digitalWrite( led, HIGH ) ;
    delay( 1000 ) ;
  }
  else {
    // no Serial found
  }


  setupWlan() ;
  setupTime() ;

}



void loop() {
  for ( int i = 0; i < 500 ; i++ ) {
    Serial.print( i ) ;
    Serial.print( '\t' ) ;
    Serial.println( "the quick brown fox jumps over the lazy dog" ) ;
    delay(1) ;
  }
  digitalWrite( led, LOW ) ;
  delay( 1000 ) ;
  digitalWrite( led, HIGH ) ;
  delay( 1000 ) ;

}

EDIT

I have also now, after a long debugging session, discovered that Serial.flush() causes a hang if a serial monitor is NOT connected to the USB port and IDE option "USB CDC on boot : enabled" is set. Finding this solves my main problem.

/*
    esp32-c3 supermini test
    similar to: https://www.tindie.com/products/adz1122/esp32-c3-development-board-esp32-supermini/

    set up IDE with
    (a) Board ESP32-C3 dev module
    (b) "USB CDC on boot : enabled"
    (c) JTAG adapter disabled

    Test generates lots of serial output and then forces a Serial.flush

    This test appears to function correctly whether or not Serial.setTxTimeoutMs(0) is set :
    (a) if the supermini is connected via USB to a PC and the serial monitor is active. 
    (c) if the supermini is powered via a phone charger with no PC connection.

    This test appear to work only if Serial.setTxTimeoutMs(0) is set :
    (b) if the supermini is connected via USB to a PC and the serial monitor is NOT active. 
    
    Serial.flush() appears to cause a hang in case (c)

*/


const uint8_t led = 8 ;  // led wired HIGH side





void setup() {

  pinMode( led, OUTPUT ) ;
  digitalWrite( led, HIGH ) ;

  Serial.begin( 115200 ) ;

  // only defined if option "USB CDC on boot" selected in IDE
  // Serial.setTxTimeoutMs(0) ; // https://github.com/espressif/arduino-esp32/pull/7583

  while ( !Serial && millis() < 10000 ) {
    delay(500) ;
  }

  // pulse led for 4 seconds if serial connection found.
  if ( millis() < 10000 ) {
    Serial.println( "found Serial") ;
    digitalWrite( led, LOW ) ;
    delay( 4000 ) ;
    digitalWrite( led, HIGH ) ;
    delay( 1000 ) ;
  }
  else {
    // no Serial found
  }

}



void loop() {

  for ( int j = 0; j < 10 ; j++ ) {
    for ( int i = 0; i < 500 ; i++ ) {
      // Serial.print( i ) ;
      // Serial.print( '\t' ) ;
      // Serial.println(  "the quick brown fox jumps over the lazy dog" ) ;
      Serial.printf( "%4d \t %s \r\n",  i, "the quick brown fox jumps over the lazy dog" ) ;
      delay(1) ;
    }
    digitalWrite( led, LOW ) ;
    delay( 1000 ) ;
    digitalWrite( led, HIGH ) ;
    delay( 1000 ) ;
    if ( j == 9 ) { 
     // this kills it if there is no serial monitor connected 
     Serial.flush() ;
    }
  }
}
2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.