ESP32-S3 parallel communication with Serial & Serial0 (USB & UART)

Hi Guys

I have a use case where I would need to communicate via the USB & UART whenever required, and the code should be able to check and act accordingly wherever the data is available (whether over Serial or Serial0). I have tried to do this with the below platformio.ini and a small cpp code snippet. Individually, the communication works with Serial (when connected to USB) & Serial0 (when connected via UART). I would appreciate it if someone could give me a few insights on how I might achieve my goal of making both communications work simultaneously.

Platformio.ini :

[env:esp32cam]
platform = espressif32@^6.5.0
board = esp32-s3-devkitc-1
framework = arduino

platform_packages = 
	platformio/tool-openocd-esp32

board_build.mcu = esp32s3
board_build.flash_mode = dio 
board_build.partitions = huge_app.csv
board_upload.flash_size: 4MB
board_build.memory_type= dio_opi
board_build.f_flash = 80000000L
board_build.f_cpu = 240000000L
board_upload.maximum_ram_size = 2097152         ;RAM - 2MB
board_upload.maximum_size = 4194304             ;FLASH - 4MB

build_unflags = -std=gnu++11

build_flags = 
        -std=gnu++17
        -DBOARD_HAS_PSRAM
        -DARDUINO_ESP32S3_DEV
        -DARDUINO_USB_CDC_ON_BOOT=1
        ; -DARDUINO_USB_MODE=1           

lib_deps = 
	espressif/esp32-camera@^2.0.4
	bblanchon/ArduinoJson @ ^7.0.3
	fhessel/esp32_https_server @^1.0.0

upload_speed = 115200
monitor_speed = 115200

In my application code, I try to handle this in this way (open to suggestions and feedback):

Serial.begin(115200);
Serial0.begin(115200);

Stream *stream;
    // Check which Serial interface has available data
    if (Serial.available()) {
        stream = &Serial;    
    } else if(Serial0.available()) {
        stream = &Serial0;
    }
    ...
    ...
    ...
    if (Serial0.available() || Serial.available()) {
        stream->println("Data available");

I really appreciate any help you can provide. :slight_smile:

Unfortunately, this is unclear (to me).
What do you want to acheive exactly?

Do you want to have a kind of bridge where everything received on Serial0 is written to Serial and vice versa?

Hi @sivar2311

Thanks for your response.

Umm no, not really a bridge between Serial and Serial0. Rather, 2 bridges in parallel, both ready to work whenever required. For example, if I send data using Serial, the code should send the response back through Serial. If I send data through Serial0, the response should be received back through Serial0.

Does this make sense at all?

Thanks,
Garvit

This is getting more and more confusing for me - sorry.
What do you mean by “send data” and response back through?

If you send data to Serial0 : Serial0.println("Some data"); this is already sent to Serial0… what response do you mean here?

Ah, my apologies for this confusion. Let me try harder.

Let’s say the ESP32 is connected through both USB (Serial) and UART (Serial0). I have an application code that expects some kind of request. Let’s say, esp32 is waiting for a command through Serial or Serial0 (both should be listening). For the response, I have to print “Command received”. So, I should know whether the request came through Serial or Serial0 so that I could accordingly do Serial.print("Command received"); or Serial0.print("Command received");

That’s why I was trying something like this:

Serial.begin(115200);
Serial0.begin(115200);

Stream *stream;
    // Check which Serial interface has available data
    if (Serial.available()) {
        stream = &Serial;    
    } else if(Serial0.available()) {
        stream = &Serial0;
    }
    ...
    ...
    ...
    if (Serial0.available() || Serial.available()) {
        stream->println("Command received");

Is it better now?

Thanks a lot for your patience. I really appreciate it.

Ok, I got it now. Thanks for the explenation.

The issue with your code might be that after reading from the Stream object (Serial / Serial0) another call to available() will always return 0 (if all data has been read from that stream).

Maybe this is what you’re looking for:

void processStream(Stream* stream) {
  int available = stream->available();

  if (!available) return; // nothing to process? -> return

  char buf[available];
  stream->readBytes(buf, available); // after this line stream->available() returns 0!

  // process content of buf
  // ...

  // send response
  stream->println("Command received");
}

void loop() {
  processStream(&Serial);
  processStream(&Serial0);
}

Thanks so much for your solid suggestions.
I will give these a go and let you know the outcome. :slight_smile:

1 Like

@sivar2311 Thanks so much. I worked on your suggestions and was able to fulfil my requirements. Really appreciate your support!! :smiley: