Reboot loop on starting UART2 - ESP32-S3

Problem: ESP-S3-WROOM reboots when attempting to initialise Serial1/UART1.

Background:

This is my first programming project. I have tried to treat it as an educational project. The goal of the project is to mirror a relay state (HIGH/LOW) over the ModBus protocol to another set of relays.

I have prototyped it on a LOLIN S2 Mini board and all functions worked. I have then designed a prototype PCB with a ESP32-S3-WROOM 1 module.

IDE was in VSCode + PIO using the Arduino framework - no issues with the Lolin S2 Mini. Now using the Arduino IDE to allow easier setting of ESP32 options. It is connected via a USB to Serial adaptor (connected to the UART0 connections on the ESP32-S3, U0RXD pin 36 and U0TXD pin 37 respectively).

Link to ESP-S3-WROOM datasheet

Code:

#include <ModbusMaster.h>
#include <Arduino.h>
#include <driver/gpio_filter.h>

// initialise Modbus

ModbusMaster node;


// set RE/DE pin HIGH

#define RE_DE 38

// Define the digital input pins for the input relays
const int inputPins[] = {15, 17, 18, 19, 20};

// Define the MODBUS coil addresses for the relays
const int coilAddresses[] = {0x0000, 0x0001, 0x0002, 0x0003, 0x0004};


void setup() 
  {
  // Initialise serial communication
  Serial.begin(115200);
  
  Serial.println("Initialised ESP32 serial.");

  // Initialise serial connection for MODBUS
  Serial1.begin(9600, SERIAL_8E1, 28, 31);

  Serial.println("Initialised MODBUS serial.");
   
  // set RE_DE pin to PULLUP as Tx only device
  pinMode(RE_DE, INPUT_PULLUP); 

  // Initialize MODBUS
  node.begin(255,Serial1);

  Serial.println("Initialised MODBUS node.");

  // Set input pins as input with internal pull-up resistors
  for (int i = 0; i < 5; i++) 
    {
      pinMode(inputPins[i], INPUT_PULLUP);
    } // end input pin pull-up resistor routine.

  for (int i = 0; i < 5; i++) 
    {
      gpio_pin_glitch_filter_config_t config = {
        .gpio_num = (gpio_num_t)inputPins[i]
      };
      gpio_glitch_filter_handle_t filter_handle;
      gpio_glitch_filter_enable(filter_handle);
    } //end glitch filter setup

  Serial.println("Initial setup complete.");

  }   

void loop() 
  {

  Serial.println("Begin polling pins.");

    for (int i = 0; i < 5; i++) 
    {
      int inputPin = inputPins[i];
      int coilAddress = coilAddresses[i];

      bool inputValue = digitalRead(inputPin) == HIGH;
      bool valueToWrite = inputValue ? false : true;  // Explicitly map HIGH to false and LOW to true
      node.writeSingleCoil(coilAddress, valueToWrite);
      Serial.println(String("Pin ") + i + " set to " + valueToWrite + ".");
    }
  }

Error messages (took me about half a day to work out that I need to turn verbose debugging on!)

08:58:40.399 -> =========== Before Setup Start ===========
08:58:40.399 -> Chip Info:
08:58:40.399 -> ------------------------------------------
08:58:40.399 ->   Model             : ESP32-S3
08:58:40.399 ->   Package           : 0
08:58:40.399 ->   Revision          : 0.02
08:58:40.399 ->   Cores             : 2
08:58:40.399 ->   CPU Frequency     : 240 MHz
08:58:40.399 ->   XTAL Frequency    : 40 MHz
08:58:40.399 ->   Features Bitfield : 0x00000012
08:58:40.399 ->   Embedded Flash    : No
08:58:40.399 ->   Embedded PSRAM    : No
08:58:40.399 ->   2.4GHz WiFi       : Yes
08:58:40.399 ->   Classic BT        : No
08:58:40.399 ->   BT Low Energy     : Yes
08:58:40.399 ->   IEEE 802.15.4     : No
08:58:40.399 -> ------------------------------------------
08:58:40.399 -> INTERNAL Memory Info:
08:58:40.399 -> ------------------------------------------
08:58:40.399 ->   Total Size        :   400572 B ( 391.2 KB)
08:58:40.399 ->   Free Bytes        :   369608 B ( 360.9 KB)
08:58:40.399 ->   Allocated Bytes   :    26140 B (  25.5 KB)
08:58:40.399 ->   Minimum Free Bytes:   364560 B ( 356.0 KB)
08:58:40.399 ->   Largest Free Block:   327668 B ( 320.0 KB)
08:58:40.399 -> ------------------------------------------
08:58:40.399 -> SPIRAM Memory Info:
08:58:40.399 -> ------------------------------------------
08:58:40.399 ->   Total Size        :  8388608 B (8192.0 KB)
08:58:40.399 ->   Free Bytes        :  8385672 B (8189.1 KB)
08:58:40.399 ->   Allocated Bytes   :      576 B (   0.6 KB)
08:58:40.399 ->   Minimum Free Bytes:  8385672 B (8189.1 KB)
08:58:40.399 ->   Largest Free Block:  8257524 B (8064.0 KB)
08:58:40.399 ->   Bus Mode          : OPI
08:58:40.399 -> ------------------------------------------
08:58:40.399 -> Flash Info:
08:58:40.399 -> ------------------------------------------
08:58:40.399 ->   Chip Size         : 16777216 B (16 MB)
08:58:40.399 ->   Block Size        :    65536 B (  64.0 KB)
08:58:40.399 ->   Sector Size       :     4096 B (   4.0 KB)
08:58:40.399 ->   Page Size         :      256 B (   0.2 KB)
08:58:40.399 ->   Bus Speed         : 80 MHz
08:58:40.399 ->   Bus Mode          : QIO
08:58:40.399 -> ------------------------------------------
08:58:40.399 -> Partitions Info:
08:58:40.399 -> ------------------------------------------
08:58:40.399 ->                 nvs : addr: 0x00009000, size:    20.0 KB, type: DATA, subtype: NVS
08:58:40.399 ->             otadata : addr: 0x0000E000, size:     8.0 KB, type: DATA, subtype: OTA
08:58:40.399 ->                app0 : addr: 0x00010000, size:  1280.0 KB, type:  APP, subtype: OTA_0
08:58:40.399 ->                app1 : addr: 0x00150000, size:  1280.0 KB, type:  APP, subtype: OTA_1
08:58:40.399 ->              spiffs : addr: 0x00290000, size:  1408.0 KB, type: DATA, subtype: SPIFFS
08:58:40.399 ->            coredump : addr: 0x003F0000, size:    64.0 KB, type: DATA, subtype: COREDUMP
08:58:40.497 -> ------------------------------------------
08:58:40.497 -> Software Info:
08:58:40.497 -> ------------------------------------------
08:58:40.497 ->   Compile Date/Time : Oct  4 2024 08:50:18
08:58:40.497 ->   Compile Host OS   : windows
08:58:40.497 ->   ESP-IDF Version   : v5.1.4-828-g33fbade6b8-dirty
08:58:40.497 ->   Arduino Version   : 3.0.5
08:58:40.497 -> ------------------------------------------
08:58:40.497 -> Board Info:
08:58:40.497 -> ------------------------------------------
08:58:40.497 ->   Arduino Board     : ESP32S3_DEV
08:58:40.497 ->   Arduino Variant   : esp32s3
08:58:40.497 ->   Arduino FQBN      : esp32:esp32:esp32s3:UploadSpeed=921600,USBMode=hwcdc,CDCOnBoot=default,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,CPUFreq=240,FlashMode=qio,FlashSize=16M,PartitionScheme=default,DebugLevel=verbose,PSRAM=opi,LoopCore=1,EventsCore=1,EraseFlash=all,JTAGAdapter=default,ZigbeeMode=default
08:58:40.497 -> ============ Before Setup End ============
08:58:40.626 -> [   612][V][esp32-hal-uart.c:408] uartBegin(): UART0 baud(115200) Mode(800001c) rxPin(44) txPin(43)
08:58:40.626 -> [   621][V][esp32-hal-uart.c:497] uartBegin(): UART0 not installed. Starting installation
08:58:40.626 -> [   629][V][esp32-hal-uart.c:560] uartBegin(): UART0 initialization done.
08:58:40.626 -> Initialised ESP32 serial.
08:58:40.626 -> [   636][V][esp32-hal-uart.c:408] uartBegin(): UART1 baud(9600) Mode(800001e) rxPin(28) txPin(31)
08:58:40.626 -> [   647][V][esp32-hal-uart.c:497] uartBegin(): UART1 not installed. Starting installation
08:58:41.960 -> [    88][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RX (2) successfully set to 0x42004510
08:58:41.960 -> [   100][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_TX (3) successfully set to 0x420044dc
08:58:41.960 -> [   111][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_CTS (4) successfully set to 0x420044a8
08:58:41.960 -> [   122][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RTS (5) successfully set to 0x42004474
08:58:41.960 -> [   134][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RX (2) successfully set to 0x42004510
08:58:41.960 -> [   145][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_TX (3) successfully set to 0x420044dc
08:58:41.960 -> [   156][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_CTS (4) successfully set to 0x420044a8
08:58:41.960 -> [   168][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RTS (5) successfully set to 0x42004474
08:58:41.960 -> [   179][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RX (2) successfully set to 0x42004510
08:58:41.960 -> [   190][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_TX (3) successfully set to 0x420044dc
08:58:41.960 -> [   201][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_CTS (4) successfully set to 0x420044a8
08:58:41.960 -> [   213][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type UART_RTS (5) successfully set to 0x42004474
08:58:41.960 -> [   225][I][esp32-hal-psram.c:90] psramInit(): PSRAM enabled
08:58:41.960 -> [   235][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 44 successfully set to type UART_RX (2) with bus 0x3fc92800
08:58:41.960 -> [   246][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 43 successfully set to type UART_TX (3) with bus 0x3fc92800
08:58:41.960 -> =========== Before Setup Start ===========

My thoughts:

I included some serial printouts to try and work out where things were going wrong. I am probably wrong, but it seems that Serial0/UART0 initialised OK as the verbose output reports that initialization was 'OK' and I can see my serial printout. Then, Serial1/UART1 attempts to be started, but then the pins for Serial/UART0 are then assigned to the UART1 serial bus? (based upon the last two lines before the reboot occurs)

Many thanks for any assistance you can offer me.

It is no problem to implement additional hardware serial ports on the ESP32, but if you spend some time looking on line, as I did, you will find a number of reports describing problems to do so with the ESP32-S3, with no solutions.

If this is your first project, I suggest to drop the ESP32-S3 and choose a standard ESP32 module. There are vast resources for support, if you run into difficulties.

Thank you very much for your reply. Could you clarify what you mean by a 'standard ESP32 module'? (I did try to Google that). I do find the naming system quite confusing.

Do you mean an ESP32 non-S2 or S3 variants? Perhaps an older module such as an ESP32-WROOM-32D (seems quite popular on AliExpress).

Several pins are connected to internal resources and are not recommended for general use.

Here is a site with some information...

SPI Flash and PSRAM

GPIOs 26 to 32 are connected to the integrated SPI flash and PSRAM and are not recommended for other uses. They are not exposed in this particular board, but if they are exposed on your board, avoid using them:

GPIO 26 (Flash/PSRAM SPICS1)
GPIO 27 (Flash/PSRAM SPIHD)
GPIO 28 (Flash/PSRAM SPIWP)
GPIO 29 (Flash/PSRAM SPICS0)
GPIO 30 (Flash/PSRAM SPICLK)
GPIO 31 (Flash/PSRAM SPIQ)
GPIO 32 (Flash/PSRAM SPID)

Thanks for your reply. I am a little confused though. On looking at the Espressif datasheet, I avoided the strapping pins and I cannot see any of the GPIOs that you have mentioned.

I also avoided pins 28-30 as suggested by the datasheet as these can be used for PSRAM usage?

Yes. Tried and well understood.

See sections 2.3 and 2.6

Thanks, I've read that now. But I am still confused - the ESP32-S3 datasheet you linked, and the ES32-S3-WROOM datasheet I have been using (and linked in my OP) have completely different pinouts?

For example, Pin 5 on the WROOM module I am using is IO5, whereas on the ESP32-S2 it is IO0??

One is chip and other is module. Have a look what's going on under the chip.
Just use the GPIOs and you are fine.
Esp32-s3 has UART1 on Gpio17&18, for UART2 you can choose GPIOs.

I'm aware one is a chip and another is a module. The GPIOs are different. I'd prefer to use pin numbering to avoid ambiguity. ESP32 multiplexing should mean that I can assign UART1 to any pin that is otherwise unallocated - which I have done.

Other way around.

Then it should work.
You want to scratch your head with spi-flash pins or try with default GPIO17/18?

The ESP32-S3-WROOM does not have a GPIO28 or a GPIO31

Thanks for your reply. When I wrote this code, I referred to the physical pin numbers. Are you saying I should refer to the IO in the code?

So, if I wanted to use pin 28 that is on the internal aspect of the pin layout as I referenced above, I should actually use '35' in the code?

You can only use GPIO numbering, pin numbers don't have any purpose here.

Unless you have written a custom board support package for your custom PCB, the Arduino IDE will not know what to do with module pin numbers. So you have no choice but to use GPIO numbers.

Which board do you select from the board manager?

@jim-p and @kmin,

Thank you both so much for your efforts - I can confirm that by using the GPIO numbering in my code instead of the actual pins, the code now works! My little device I have made works brilliantly. I am over the moon.

@jim-p the board definition I am using in Arduino IDE is the 'ESP32S3 Dev Module'.

However, I am still extremely confused by this issue. In the hopes of preventing many more hours of teeth gnashing in the future, would you be able to explain the pin numbering vs IO issue to me in a bit more detail?

My thinking is that on a chip OR a module, the physical pins are the constants here. They are the physical aspects of the device that are soldered to a PCB. They are numbered like any other IC pins are numbered. However, the GPIO numbering seems to be different - it differs according to the device/type of dev board used, if any, etc.

Looking through the datasheets, a physical pin can have multiple different roles. E.g. for the ESP32-S3-WROOM datasheet, pin 19, can have multiple functions, with different numbering schemes:

  • GPIO11
  • TOUCH11
  • FSPIIO5

Surely this is a source of confusion??

Yep, it can be very confusing, flexibility has its price. But GPIO definition is solid, just abandon the pin numbering.
If you play with different Esp32 family chips, it's getting even "better".
Nothing Esp specific anyway, for example STM32 MCUs offer the same fun as well...

Good job. To help others who run across this or a similar problem, please post the working code, using code tags.

So this is what the IDE thinks you are using.
Did you design your custom board the exact same way with the same pinout?

Well, no. I did not bring any pins out to headers - I layed a footprint down and soldered the module directly to the board.

Hence my confusion - I was directly referencing the physical pins which are the same as the actual module that makes up the dev board linked!