ESP32 UART Hardware Serial Ports Help

Hello there, I am working out on ESP32 for one of my projects as it says that it has the advantage of direct access to use 3 hardware UART serial ports. But I found that it has only one hardware UART serial port which works actually only i.e RX 16, TX 17 and other 2 UART hardware serial ports not work at all as they are internally connected and can not use externally and if tried to use they don't work and crash the ESP32. So its wrongly described about the advantage of direct access to use 3 hardware UART serial ports on ESP32. If someone has successfully used these UART0, UART1 ports externally just like UART2 (RX 16, TX 17) please let me assist with the same. Thanking you.

As you failed to provide a link to the actual hardware you're using I felt free to choose any available ESP32 board as a reference.

That one has the pins 1 and 3 (UART0) and 9 and 10 (UART1) wired to the header, so the hardware serial is available.

You also don't tell us what "don't work" actually means. Do you have software problems? Does the sketch compile but you don't get a signal on the pin?

#include <HardwareSerial.h>

HardwareSerial GPSSerial ( 1 );
HardwareSerial LIDARSerial ( 2 );

voiding setup()
{

  LIDARSerial.begin ( SerialDataBits, SERIAL_8N1, 26, 25 );
  GPSSerial.begin ( GPS_DataBits, SERIAL_8N1, 2, 15 ); // begin GPS hardware serial
}

void fReceiveSerial_LIDAR( void * parameters  )
{
  bool BeginSentence = false;
  sSerial.reserve ( StringBufferSize300 );
  char OneChar;
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( LIDARSerial.available() >= 1 )
    {
      while ( LIDARSerial.available() )
      {
        OneChar = LIDARSerial.read();
        if ( BeginSentence )
        {
          if ( OneChar == ‘>’)
          {
            if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
            {
              xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &sSerial );
              xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
              //
            }
            BeginSentence = false;
            break;
          }
          sSerial.concat ( OneChar );
        }
        else
        {
          if ( OneChar == ‘<’ )
          {
            sSerial = “”; // clear string buffer
            BeginSentence = true; // found begining of sentence
          }
        }
      } //  while ( LIDARSerial.available() )
    } //if ( LIDARSerial.available() >= 1 )
    xSemaphoreGive( sema_ReceiveSerial_LIDAR );
  }
  vTaskDelete( NULL );
} //void fReceiveSerial_LIDAR( void * parameters  )


using more than one serial port with an esp32. works great lasts a long time.

1 Like

I am using ESP32-WROOM-32:

Actually, I want to use GPS module on UART1 serial port and when run the code sketch it didn't work at all on UART1 serial port and when run the same code sketch on UART2 i.e. RX 16, TX 17 it works without any issue. Please have check for the code below:

#include "TinyGPS++.h";
#define RXD2 16
#define TXD2 17

TinyGPSPlus gps;
int COUNT = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);
}

void loop() {

delay(1000);

if (COUNT ==0)
 {
  Serial2.write("@GSTP\r\n", 7);

  delay(500);

  Serial2.write("@GNS 0x0B\r\n", 11);

  delay(500);

  Serial2.write("@GSR\r\n", 7);

   delay(500);
   COUNT ++;
  }   
else   
  {
    while (Serial2.available() > 0)
    gps.encode(Serial2.read());
  }

   Serial.print("LAT=");  Serial.println(gps.location.lat(), 6);
    Serial.print("LONG="); Serial.println(gps.location.lng(), 6);
    Serial.print("ALT=");  Serial.println(gps.altitude.meters());
}

Thanks.

1 Like

Hello @Idahowalker, Thank you for helping by sharing the code as per understanding the problem. May I know please which ESP32 board's pins you have mentioned? Could you please share the code to run GPS on UART1 serial1 port? Thanking you.

testing ESP32 Serial1 and Serial2 using loopback

// ESP32 serial1 and serial2 hardware loop back test 

// see https://circuits4you.com/2018/12/31/esp32-hardware-serial2-example/
/* There are three serial ports on the ESP known as U0UXD, U1UXD and U2UXD.
 * 
 * U0UXD is used to communicate with the ESP32 for programming and during reset/boot.
 * U1UXD is unused and can be used for your projects. Some boards use this port for SPI Flash access though
 * U2UXD is unused and can be used for your projects.
*/

#define RXD1 12  // for loopback jumper these pins
#define TXD1 13

#define RXD2 16
#define TXD2 15

void setup() {
  // Note the format for setting a serial port is as follows: Serial2.begin(baud-rate, protocol, RX pin, TX pin);
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);
  Serial.println("ESP32 hardware serial test on Serial1 and Serial2");
  Serial.println("Serial Txd is on pin: "+String(TX));
  Serial.println("Serial Rxd is on pin: "+String(RX));
  Serial.println("Serial1 Txd1 is on pin: "+String(TXD1));
  Serial.println("Serial1 Rxd1 is on pin: "+String(RXD1));
  Serial.println("Serial2 Txd2 is on pin: "+String(TXD2));
  Serial.println("Serial2 Rxd2 is on pin: "+String(RXD2));
}

void loop() { //Choose Serial1 or Serial2 as required
  while (Serial2.available()) {
    Serial.println("Serial2 = " + Serial2.readStringUntil('\n'));
  }
  while (Serial1.available()) {
    Serial.println("Serial1 = " + Serial1.readStringUntil('\n'));
  }
  while (Serial.available()) {
    String s = Serial.readStringUntil('\n');
    if(s.charAt(0)=='1') Serial1.print( s);
    else                 Serial2.print( s);
  }
}

using a NodeMCU-32S with pins jumpered for loopback test
if Serial Monitor input starts with a 1 line of text is transmited over Serial1 anything else over Serial2

ESP32 hardware serial test on Serial1 and Serial2
Serial Txd is on pin: 1
Serial Rxd is on pin: 3
Serial1 Txd1 is on pin: 13
Serial1 Rxd1 is on pin: 12
Serial2 Txd2 is on pin: 15
Serial2 Rxd2 is on pin: 16
Serial1 = ⸮
Serial1 = 1 test serial 1
Serial1 = 1 second test serial 1
Serial2 = serial 2 test
Serial2 = serial2 test 2

pins used

LIDARSerial.begin ( SerialDataBits, SERIAL_8N1, 26, 25 );
  GPSSerial.begin ( GPS_DataBits, SERIAL_8N1, 2, 15 ); 

gps code

void fGPS_Parse(  void *pvParameters )
{
  // int iBit = 1;
  for (;;)
  {
    xEventGroupWaitBits (eg, evtGPS_Parse, pdTRUE, pdTRUE, portMAX_DELAY) ;
    if ( xSemaphoreTake( sema_GPS_Gate, xTicksToWait0 ) == pdTRUE )
    {
      //query GPS: has a new complete chunk of data been received?
      if ( GPSSerial.available() > 1 )
      {
        if ( GPS.encode(GPSSerial.read()) )
        {
          if (  GPS.location.isValid())
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.Lat = GPS.location.lat();// store data into structure
              xPosit.Lon = GPS.location.lng();
              xSemaphoreGive( sema_Posit );
            }
          } // if (  GPS.location.isValid())
          if (GPS.speed.isValid())
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.MPH = GPS.speed.mph();
              xPosit.KPH = GPS.speed.kmph();
              xSemaphoreGive( sema_Posit );
            }
          } //  if (GPS.speed.isValid())
          if (GPS.time.isValid())
          {
            if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xTime.iSeconds = GPS.time.second();
              xTime.iMinutes = GPS.time.minute();
              xTime.iHours = GPS.time.hour();
              xSemaphoreGive( sema_Time );
            }
          } // if (GPS.time.isValid())
          if (GPS.date.isValid())
          {
            if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xDate.iMonth = GPS.date. month();
              xDate.iDay = GPS.date.day();
              xDate.iYear = GPS.date.year();
              xSemaphoreGive( sema_Date );
            }
          } // if (GPS.date.isValid())
          if (  GPS.altitude.isValid() )
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.Alti = GPS.altitude.meters();
              xSemaphoreGive( sema_Posit );
            }
          } //  if (  GPS.altitude.isValid() )
          if ( GPS.course.isUpdated() )
          {
            if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
            {
              xPosit.Hdg = GPS.course.deg();
              xSemaphoreGive( sema_Posit );
            }
          } // if ( GPS.course.isUpdated() )
          if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
          {
            xQueueOverwrite( xQ_Posit, (void *) &xPosit );
            xSemaphoreGive( sema_Posit );
          }
        } // if ( GPS.encode(GPSSerial.read()))
      } // if ( GPSSerial.available() > 0 )
      xSemaphoreGive( sema_GPS_Gate );
    }
  } // for (;;)
  vTaskDelete( NULL );
} // void fGPS_Parse(  void *pvParameters )

According to this the way to proceed is to map a second hardware serial port to pins not used by the SPI flash.

1 Like

SoftwareSerial(), anyone?

OR

Hello @cattledog, I have already been tried this secret serial port setup procedure by Andreas Spiess, but sorry to say that it didn't work and giving compiling error. Thanks.

Hello @horace, tried to run your provided code with using NodeMCU-32S, but sorry to say it didn't work at all. Thanks.

Hello @Idahowalker, sorry to say that i am still confusing which board's TX/RX pins used in your provided code?. Thanks.

IIRC, ONLY the Tx pin of Serial2 can be used on the ESP32. The Rx pin is already used for something else. I use TX2 as the debug output.

Hello @RayLivingston, sorry didn't understand could you please explain a bit more on this? Thanks.

I believe that's ESP8266.

Hello @runaway_pancake, I think so, as I am using ESP32. Thanks.

checked the board I am using and it is a ESP-WROOM-32_38_pin
using the Arduino IDE under Tools>ESP32 Arduino I select ESP32 Dev Module
After loaded did you try pressing the reset button

what board are you using?

The sketch from @horace compiles and works correctly for me an ESP32 development board from ezsbc.

I jumpered pin 12 to pin 15 and pin 13 to pin 16 (i.e. cross connect Rx and Tx from Serial1 and Serial2). I set all baud rates to 115200.

When I enter text from the Serial monitor I see the expected function of Serial1 and Serial2.

ESP32 hardware serial test on Serial1 and Serial2
Serial Txd is on pin: 1
Serial Rxd is on pin: 3
Serial1 Txd1 is on pin: 13
Serial1 Rxd1 is on pin: 12
Serial2 Txd2 is on pin: 15
Serial2 Rxd2 is on pin: 16
Serial2 = 1TestSerial1
Serial1 = 2TestSerial2

Hello @horace , i am using this esp32 board:

And I think it has very different RX/TX pins than yours one.

even if the serial communications do not work when the program starts the Serial Monitor should display

ESP32 hardware serial test on Serial1 and Serial2
Serial Txd is on pin: 1
Serial Rxd is on pin: 3
Serial1 Txd1 is on pin: 13
Serial1 Rxd1 is on pin: 12
Serial2 Txd2 is on pin: 15
Serial2 Rxd2 is on pin: 16

can you run any code on the board? e.g. blink program
what board do you select under the Tools menu