Serial link between arduino and esp32 not working

I have two devices:

A) arduino pro mini, powered with two AA bateries.
B) ESP32 device with a small tft screen.

I want to use the ESP32 as a mobile serial monitor to debug sensor nodes (using mysensors) without having to attach a PC. I have all the separate things working, but when I connect the two, the ESP32 does not display the serial data on screen. Proven so far:

  1. When I connect the ESP32 to the Serial Monitor in the IDE and I enter a message, it's displayed on the TFT screen.
  2. When I connect the Arduino (only the TX, RX and additional GND), still battery powered) to the Serial Monitor in the IDE it displays the message in the serial monitor.
  3. Both are working at 9600 baud

When I connect the two together, it doesn't work. The way I do this is as follows:

Powerbank by USB to the ESP32 device.
2AA batteries to VCC and GND on the Arduino
GND from ESP32 to GND arduino
TX (ESP32) to RX(Arduino)

But nothing works. What am I missing here?

Code Arduino:

void setup() {
  Serial.begin(9600); // for serial debugging over USB.
  pinMode(13, OUTPUT);
}
void loop() {
  Serial.println("Ping");
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
} // end of main loop.

Code TFT:


#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();       // Invoke custom library
// The scrolling area must be a integral multiple of TEXT_HEIGHT
#define TEXT_HEIGHT 16 // Height of text to be printed and scrolled
#define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
#define TOP_FIXED_AREA 16 // Number of lines in top fixed area (lines counted from top of screen)
#define YMAX 320 // Bottom of screen area

// The initial y coordinate of the top of the scrolling area
uint16_t yStart = TOP_FIXED_AREA;
// yArea must be a integral multiple of TEXT_HEIGHT
uint16_t yArea = YMAX-TOP_FIXED_AREA-BOT_FIXED_AREA;
// The initial y coordinate of the top of the bottom text line
uint16_t yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;

// Keep track of the drawing x coordinate
uint16_t xPos = 0;

// For the byte we read from the serial port
byte data = 0;

// A few test variables used during debugging
bool change_colour = 1;
bool selected = 1;

// We have to blank the top line each time the display is scrolled, but this takes up to 13 milliseconds
// for a full width line, meanwhile the serial buffer may be filling... and overflowing
// We can speed up scrolling of short text lines by just blanking the character we drew
int blank[19]; // We keep all the strings pixel lengths to optimise the speed of the top line blanking

void setup() {
  // Setup the TFT display
  tft.init();
  tft.setRotation(0); // Must be setRotation(0) for this sketch to work correctly
  tft.fillScreen(TFT_BLACK);
  
  // Setup baud rate and draw top banner
  Serial.begin(9600);
  
  tft.setTextColor(TFT_WHITE, TFT_BLUE);
  tft.fillRect(0,0,240,16, TFT_BLUE);
  tft.drawCentreString(" Serial Terminal - 9600 baud ",120,0,2);

  // Change colour for scrolling zone text
  tft.setTextColor(TFT_WHITE, TFT_BLACK);

  // Setup scroll area
  setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA);

  // Zero the array
  for (byte i = 0; i<18; i++) blank[i]=0;
}


void loop(void) {
  //  These lines change the text colour when the serial buffer is emptied
  //  These are test lines to see if we may be losing characters
  //  Also uncomment the change_colour line below to try them
  //
  //  if (change_colour){
  //  change_colour = 0;
  //  if (selected == 1) {tft.setTextColor(TFT_CYAN, TFT_BLACK); selected = 0;}
  //  else {tft.setTextColor(TFT_MAGENTA, TFT_BLACK); selected = 1;}
  //}

  while (Serial.available()) {
    data = Serial.read();
    // If it is a CR or we are near end of line then scroll one line
    if (data == '\r' || xPos>231) {
      xPos = 0;
      yDraw = scroll_line(); // It can take 13ms to scroll and blank 16 pixel lines
    }
    if (data > 31 && data < 128) {
      xPos += tft.drawChar(data,xPos,yDraw,2);
      blank[(18+(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT)%19]=xPos; // Keep a record of line lengths
    }
    //change_colour = 1; // Line to indicate buffer is being emptied
  }
}

// ##############################################################################################
// Call this function to scroll the display one text line
// ##############################################################################################
int scroll_line() {
  int yTemp = yStart; // Store the old yStart, this is where we draw the next line
  // Use the record of line lengths to optimise the rectangle size we need to erase the top line
  tft.fillRect(0,yStart,blank[(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT],TEXT_HEIGHT, TFT_BLACK);

  // Change the top of the scroll area
  yStart+=TEXT_HEIGHT;
  // The value must wrap around as the screen memory is a circular buffer
  if (yStart >= YMAX - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA + (yStart - YMAX + BOT_FIXED_AREA);
  // Now we can scroll the display
  scrollAddress(yStart);
  return  yTemp;
}

// ##############################################################################################
// Setup a portion of the screen for vertical scrolling
// ##############################################################################################
// We are using a hardware feature of the display, so we can only scroll in portrait orientation
void setupScrollArea(uint16_t tfa, uint16_t bfa) {
  tft.writecommand(ILI9341_VSCRDEF); // Vertical scroll definition
  tft.writedata(tfa >> 8);           // Top Fixed Area line count
  tft.writedata(tfa);
  tft.writedata((YMAX-tfa-bfa)>>8);  // Vertical Scrolling Area line count
  tft.writedata(YMAX-tfa-bfa);
  tft.writedata(bfa >> 8);           // Bottom Fixed Area line count
  tft.writedata(bfa);
}

// ##############################################################################################
// Setup the vertical scrolling start address pointer
// ##############################################################################################
void scrollAddress(uint16_t vsp) {
  tft.writecommand(ILI9341_VSCRSADD); // Vertical scrolling pointer
  tft.writedata(vsp>>8);
  tft.writedata(vsp);
}


Your Arduino sends the text "Ping" out its Tx pin.

Your ESP32 is listening on its Rx pin.

But according to your connection list, there is nothing connected to either the Arduino's Tx pin, nor the ESP32's Rx pin.

I'll leave you to ponder that.

Oh: and when you do connect those two pins, there had better be level shifting (a voltage divider at minimum) to keep the 3.3V ESP32 from seeing a 5V signal and joining the choir invisible.

Thanks for your reply. Sorry my bad, the RX of esp32 was connected to TX of the Arduino. Since it concerns one way comms, I assumed it to be OK. That said, I tried both connected (Rx>tx and tx>Rx )but to no avail. From you answer I figure that won't work either.

I must say I forgot about the voltage difference. Is that the reason that its not registering? Receving 3.3v signal when expecting 5V?

I'm not sure what the voltage divider should do in this case, could you clarify that a bit more?

You are transmitting from the Arduino (5V) to the ESP32 (3.3V). You need a level shifter to reduce that 5V transmitted signal to a 3.3V one for the receiver.

No actually the pro mini is a 3.3v one (2xAA or via FTDI to usb).

I assumed the esp32 device is 5V since I attach it directly with a micro usb cable to my pc.

Oh, if the Arduino is 3.3V as well you're good to go then.

Even though the ESP32 is 5V? Because it won't work, and I can imagine that the 3.3v signal is not picked up by the 5V esp32

The ESP32 operates at 3.3V. You can use a meter to check the level of an output pin set to high to see for yourself.

Ok thanks. But if that's the case, we're back to square one: what reason could there be that it's not working?

ESP32 GPIO02 (onboard LED) should blink when ProMini
sends carriage return --

char inChar;

void setup() 
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  digitalWrite(2, LOW);
}

void loop() 
{
  if(Serial.available() > 0)
  {
    inChar = Serial.read();
    if(inChar == '\r')
    {
      digitalWrite(2, HIGH);
      delay(200);
      digitalWrite(2, LOW);
    }
  }
}

May get out of sync.

Now that I had some time, I threw together a very simple demo. I used an OLED display because I had one handy. And I used a 5V Pro Mini because a) that's what I already had on headers and b) it allowed me to use a voltage divider to drop the Rx voltage well below 3.3V in case that was the issue.

It wasn't.

Worked like a charm as far down as a 2.5V signal on the ESP32's Rx pin. I could have gone lower, but there wasn't really any point.

Pro Mini

void setup() {
  Serial.begin(9600); // for serial debugging over USB.
  pinMode(13, OUTPUT);
}

unsigned x = 1;

void loop() {
  Serial.print("Ping ");
  Serial.println(x);
  ++x;
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
} // end of main loop.

ESP32

#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(128, 64);

bool needsClear;

void setup() {
   Serial.begin(9600);
   display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
   display.setRotation(2);
   display.setTextSize(2);
   display.setTextColor(SSD1306_WHITE);
   display.clearDisplay();
   display.setCursor(0, 0);
   display.print("Waiting");
   display.display();
   needsClear = true;
}


void loop(void) {
   while( Serial.available() ) {
      if( needsClear ) {
         display.clearDisplay();
         display.setCursor(0, 0);
         needsClear = false;
      }
      char c = Serial.read();
      switch( c ) {
         case '\r':
            break;
         case '\n':
            display.display();
            needsClear = true;
            break;
         default:
            display.print(c);
            break;
      }
   }
}

Thanks for taking the time. I will try to make my setup as simple as possible and try again. The esp32-based device by the way is this one:

Ok, I tried to go as simple as possible. In the end I risked going to 5V anyway, just to see what happened. And sure enough, using a regular UNO at 5V worked as a charm. So assuming this is how it should be, I think a need a logic level converter.

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