Mega R3 ATMega2560+ESP8266 won't talk to each other

I have been at this a month, and I'm going around in circles. Searched all relevant articles on this forum, but still no joy.

I have an ATMega2560+ESP8266 R3 board. Separately, the sketches on the ATMega2560 and ESP8266 work fine using the Serial monitor from within the IDE. The ESP8266 connects to my home network, gets an NTP packet, and sends the UNIX time out the serial port. From within the IDE, the ATMega2560 part also works fine. It receives a command on the serial port and updates its connected RTC. Both halves work perfectly, but separately, from within the IDE. Baud rate is 115200.

When I connect the 2 halves together (DIP SW 1&2 ON) however, they don't seem to talk. It's difficult to know what, if anything, is happening as I can't monitor the serial port. The onboard slider switch is set to serial 0.

I can't use Serial3 because, for reasons unknown, I get a "Serial3 not declared in this scope error".

It must be some sort of subtle timing problem, and I'm interested in theories. In about 50 attempts it has actually worked twice. I'd like it to be a little more reliable than this.

Try setting the board type to Arduino Mega 2560.

what do you have the target board set too?
if I set tools>Board: Arduino Mega or Mega 2560 I can access Serial3 OK

have a look at Mega-WiFi_R3_ATmega2560_ESP8266 for switch settings, e.g.
Setting DIP switches ON ON ON ON OFF OFF OFF should direct the ESP8266 serial to Serial3 of Mega and mega Serial output to the serial monitor
I also set the switch RXD0/TXD0 RXD3/TXD3 switch to RXD3/TXD3

I had intermittent problems loading code into processors and with the Mega Serial3 connection to the ESP8266 serial - when I used contact cleaner on the DIL switches this appeared to clear up the immediate problems

Try a lower speed.

Is your board an "XC4421 Duinotech MEGA board with an integrated ESP8266"?
Is there a circuit diagram available? There doesn't seem to be much information on the web.

My board is the XC4421. I have not been able to find a circuit diagram.

I cannot access Serial3 on the ESP8266. Suspect it only has one serial port. The instructions are pretty vague. I'm beginning to suspect that I should be using Serial3 on the Mega and Serial1 on the ESP. It should still work with Serial1 on both processors, so I think the Serial3 issue is a red herring.

In this configuration, which Serial do you reference in code on the Mega and the ESP? I'm guessing it's Serial3 on the Mega, and Serial1 on the ESP?

I used Serial3 on the mega and Serial on the ESP8266

Interesting. What is the advantage of using Serial3 on the Mega? They've obviously gone to a lot of trouble to make this possible, but why do it?

on the Mega-WiFi_R3_ATmega2560_ESP8266 board the Mega Serial3 is connected to the Serial of the ESP8266 when the DIP swithes are set ON ON ON ON OFF OFF OFF OFF

test code for the ESP8266 outputs 500mSec pulse to GPIO2 (connect LED) and * on serial monitor
if character received on Serial echo it + 1

// Blink modified for Mega-WiFi_R3_ATmega2560_ESP8266

// for pinout etc see https://content.instructables.com/ORIG/FZG/PCR2/K490QMC7/FZGPCR2K490QMC7.pdf

// will output 500mSec pulse to GPIO2 and * on serial monitor
// if character received on Serial  echo it + 1

#define LED 2   // blink GPIO2 - connect LED to ESP8266 header

// Programming the ESP8266
//   Set dip switches 1-4 and 8  OFF and 5-7  ON. 
//   Arduino IDE under Tools|Board: set "NodeMCU 1.0 (ESP12E Module)" 
//   press reset - press Mode button
//   upload code
//
// to run code
//   set the dip switches 1-4 and 7-8 OFF and 5-6 ON
//   press reset - GPIO2 will blink and ESP8266 Serial output will appear on serial monitor

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("output 500mSec pulse to GPIO2 and * on serial monitor");
  Serial.println("   if character received echo it + 1");
  pinMode(LED, OUTPUT);
}

void loop() {
  Serial.print('*');
  digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                  
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(500);                 
  if (Serial.available()){   // read from Serial and echo printable char + 1
    char ch= Serial.read(); 
    if(ch >=' ') Serial.write(ch+1);
  }
}

code for Mega blinks LED and communicates over Serial3 with ESP8266

// Arduino  Mega-WiFi_R3_ATmega2560_ESP8266 Serial3 (connected to onboard ESP8266) test
//    blinks LED and communicates over Serial3 with ESP8266

// for pinout etc see https://content.instructables.com/ORIG/FZG/PCR2/K490QMC7/FZGPCR2K490QMC7.pdf

//Programming the Mega
//  DIP switches OFF OFF ON ON OFF OFF OFF OFF
//  press Reset then MODE 
//  upload code

// to run
//  DIP switches ON ON  ON ON OFF OFF OFF OFF
//  press Reset code will run

#define LED 13  // mega LED on pin 13

void setup() {
  Serial.begin(115200);   // serial monitor
  Serial3.begin(115200);  // serial to ESP8266
  Serial.write("Arduino Mega Serial3 to ESP8266 test \n");
  pinMode(LED,OUTPUT);
  delay(500);
}

void loop() {
   static long int i=0;
   /*if(i++==100000l) {
      i=0;
      Serial.print('&');
   }*/
   // blink LED
    digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(500);                  
    digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
    delay(500);                 

   if (Serial3.available())        // read from Serial3 output to Serial
      Serial.write(Serial3.read());
   if (Serial.available()) {       // read from Serial outut to Serial3
     int inByte = Serial.read();
     Serial.write(inByte);        // local echo if required
     Serial3.write(inByte);       // write to ESP8266 
  }
}

the Mega serial monitor shows

Arduino Mega Serial3 to ESP8266 test
******1*2****4**5****5***6*****9****:**

the ESP8266 transmits a * to the Mega every second which is displayed on the Mega serial monitor
a keyboard hit on the Mega, e.g. 1, is sent to the ESP8266 which adds 1 to the ASCII value and sends it to the Mega, e.g. which displays 2

Thanks very much for the test files. I can confirm that it runs perfectly. This at least proves that my hardware is OK, and that I am programming it correctly. Unfortunately, my sketches still aren't working. As much as I hate to post large sketches, I'm at the point where I don't know what else to do.

First is the Mega sketch, followed by the ESP sketch. The Mega sends the command [NTP] to the ESP. The ESP responds with [NTP,UNIX time]. The ESP also sends this same message 30s after startup. Both sketches perform correctly when running separately. I send messages on the Serial link and I get the correct responses. When connected together, I don't think serial data is happening.

The only curious thing is that when I startup the ESP, it sends about 100 characters of random junk out the serial port. I have put countermeasures in - a limit of 250 chars per message. I can't see how this would affect anything, but it's odd.

Mega code

// real-time clock
// Author: Marc Hillman VK3OHM
// Features:
//  LCD TFT display
//  inbuilt RTC
//  WiFi

//Programming the Mega
//  DIP switches OFF OFF ON ON OFF OFF OFF OFF
//  press Reset then MODE
//  upload code

// to run
//  DIP switches ON ON  ON ON OFF OFF OFF OFF
// Tx/Rx switch set to 3
//  press Reset code will run

//#define DEBUG true // setting true will enable Serial print statements
//
#define SERIAL_BAUD 115200
// TFT LCD display
#include <UTFT.h>  // Core graphics library
#include <SPI.h>
#include <SD.h>
#include <TimeLib.h>
#include "Grotesk32x64.c"
#include "wifi.c"  // wifi logo to indicate link status

// PicoDev RV3028 RTC
#include <RV-3028-C7.h>
RV3028 rtc;   // only the UNIX clock of the rtc is used. Time of day clock is not used.
/*
  pin             INTx    interrupt number for attachInterrupt()

  3       PE5     INT5    1
  2       PE4     INT4    0
  18 TX1  PD3     INT3    5
  19 RX1  PD2     INT2    4
  20 SDA  PD1     INT1    3
  21 SCL  PD0     INT0    2

  (nc)    PE6     INT6    -
  (nc)    PE7     INT7    - */
#define interruptPin 2  // use pin 2 (INT4) for clock input

// Declare which fonts we will be using
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
tmElements_t tod;   // time broken into components

UTFT myGLCD(ILI9481, 38, 39, 40, 41);  // create panel object
#define PORTRAIT 0
#define LANDSCAPE 1
#include <StringSplitter.h>
String receivedCommand = "";
bool dataIn = false;
volatile bool requestNTP = false;  // set to request NTP update
int timezone = 0;
const char *tz[] = { "UTC", "Local" };
const char *DaysOfWeek[] = {"  Sunday ", "  Monday ", " Tuesday ", "Wednesday", " Thursday", "  Friday ", " Saturday" };  // strings for day of week - padded to width 9
char buffer[100];                                                                                             // general purpose buffer

void setup() {
  Serial.begin(SERIAL_BAUD);
  Serial.println(F("Entered setup"));
  Serial3.begin(SERIAL_BAUD);

  // Set LCD

  myGLCD.InitLCD(LANDSCAPE);
  myGLCD.clrScr();

  // Setup RTC
  Wire.begin();
  if (rtc.begin() == false) {
    Serial.println(F("Something went wrong, check wiring"));
    //while (1);
  } else
    Serial.println(F("RTC online!"));
  rtc.enableTrickleCharge(TCR_3K);   // trickle charge backup battery
  Serial.print(F("UNIX time is ")); Serial.println(rtc.getUNIX());
  // The master date/time is the UNIX value in the RTC. The calendar (year, month, day, etc) is ignored.
  // The system clock is regularly synced to the master clock
  setSyncProvider(syncProvider);   // the function to get the time from the RTC
  setSyncInterval(60 * 60); // onboard clock is terrible. Needs synching at least every hour
  if (timeStatus() != timeSet)
    Serial.println(F("Unable to sync with the RTC"));
  else
    Serial.println(F("RTC has set the system time"));
  rtc.disableClockOut();
  delay(1000);
  rtc.enableClockOut(FD_CLKOUT_1); // Start the 1 Hz timer
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), displayTime, FALLING);    // 1Hz pulse from rtc
}
void loop() {
  if (requestNTP) {
    // Request an NTP update
    wifiIcon(false);    // indicate time may be invalid by removing icon
    Serial3.println(F("[NTP]"));   // request NTP time
    requestNTP = false;
  }
  // listen for commands from other processor
  while (Serial3.available()) {
    char c = Serial3.read();  //read it
    if (c == '[') {
      //this is the start of the command string
      receivedCommand = "";
      dataIn = true;
    }
    //otherwise, we are still reading the command string:
    else if (dataIn && c != ']') {
      if (receivedCommand.length() < 250)   // enforce maximum command length
        receivedCommand += c;
      else {
        // maximum command length exceeded. Restart
        receivedCommand = "";
        dataIn = false;
        Serial.println(F("[ERR]"));  // unrecognised command
      }
    } else if (dataIn && c == ']') {
      //finished receiving the command, process it
      Serial.print(receivedCommand); Serial.println(F(" -> Arduino"));
      StringSplitter *splitter = new StringSplitter(receivedCommand, ',', 10);  // parse the command
      String command = splitter->getItemAtIndex(0);                             // process based on first word
      if (command == "NTP" and splitter->getItemCount() == 2) {
        wifiIcon(true);   // indicate time is valid by showing wifi icon
        // set the RTC time. The Real Time and UNIX time are independent, so need to set both
        time_t epoch = splitter->getItemAtIndex(1).toInt();  // get UNIX TS
        Serial.print("Setting system clock to: "); Serial.println(epoch);
        setTime(epoch);      // set the time of day clock
        rtc.setUNIX(epoch);   // and the RTC
        // Update rtc Time of Day
        breakTime(epoch, tod);    // break unix time into components
        rtc.setTime(tod.Second, tod.Minute, tod.Hour, tod.Wday, tod.Day, tod.Month, tod.Year);
      } else
        Serial.println(F("[ERR]"));  // unrecognised command
      delete splitter;            // destroy when finished
      receivedCommand = "";
      dataIn = false;
    }
  }
  delay(100);
  //displayTime();
}

uint32_t syncProvider()
{
  // You cannot read the RTC during an interrupt, so set the onboard clock to sync to RTC
  return rtc.getUNIX();
}

void wifiIcon(bool display) {
  // display the wifi Icon (or not)
  if (display)
    myGLCD.drawBitmap(myGLCD.getDisplayXSize() - 32, 0, 32, 32, wifi);  // wifi logo top right
  else {
    myGLCD.setColor(VGA_BLACK);   // foreground colour
    myGLCD.fillRect(myGLCD.getDisplayXSize() - 32, 0, 32, 32);
  }
}
void displayTime() {    // display date/time ISR
  // Note: you cannot use Serial, or the I2C bus, in an interrupt routine
  tmElements_t t;   // time broken into components
  char buffer[100];

  interrupts();   // enable interupts so we don't slow down the time of day clock. Risky, but no choice.
  breakTime(now(), t);  // break current time into pieces
  myGLCD.setFont(BigFont);
  myGLCD.setColor(VGA_RED);
  myGLCD.print(tz[timezone], CENTER, 0);  // show timezone
  myGLCD.setColor(VGA_YELLOW);
  myGLCD.print(DaysOfWeek[t.Wday - 1], CENTER, 300); // show Day of Week

  myGLCD.setFont(Grotesk32x64);
  myGLCD.setColor(0, 255, 0);
  snprintf(buffer, sizeof(buffer), "%02d.%02d.%04d", t.Day, t.Month, t.Year + 1970);
  myGLCD.print(buffer, CENTER, 60);
  snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", t.Hour, t.Minute, t.Second);
  myGLCD.print(buffer, CENTER, 200);
  if (t.Minute == 0 and t.Second == 0) requestNTP = true; // request NTP update once per hour.
}

ESP code



// Programming the ESP8266
//   Set dip switches 1-4 and 8  OFF and 5-7  ON.
//   Arduino IDE under Tools|Board: set "NodeMCU 1.0 (ESP12E Module)"
//   press reset - press Mode button
//   upload code
//
// to run code
//   set the dip switches 1-4 and 7-8 OFF and 5-6 ON
//   press reset - GPIO2 will blink and ESP8266 Serial output will appear on serial monitor

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <StringSplitter.h>

#ifndef STASSID
#define STASSID F("BigPond0277")
#define STAPSK  F("********")
#endif

unsigned int localPort = 2390;      // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
    Lookup the IP address for the host name instead */
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
WiFiUDP udp;  // A UDP instance to let us send and receive packets over UDP
#define SERIAL_BAUD 115200 //make sure this is the same in arduino.ino
String receivedCommand = "";
bool dataIn = false;

void setup(void)
{
  Serial.begin(SERIAL_BAUD);
  delay(500);
  Serial.println(F("Entered setup"));

  // We start by connecting to a WiFi network
  Serial.print(F("Connecting to "));
  Serial.println(STASSID);
  WiFi.mode(WIFI_STA);
  String newHostname = F("UTC_Clock");   // pretty host name
  WiFi.hostname(newHostname.c_str());
  WiFi.begin(STASSID, STAPSK);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println(F("WiFi connected"));
  Serial.print(F("IP address: ")); Serial.println(WiFi.localIP());

  Serial.println(F("Starting UDP"));
  udp.begin(localPort);
  Serial.print(F("Local port: "));  Serial.println(udp.localPort());
  delay(20000);   // allow time for the ATMega half to boot up
  NTP();    // perform an NTP, sending result to ATMega half
}

void loop(void)
{
  // listen for commands from other processor
  while (Serial.available())
  {
    char c = Serial.read(); //read it
    if (c == '[') {
      //this is the start of the command string
      receivedCommand = "";
      dataIn = true;
    }
    //otherwise, we are still reading the command string:
    else if (dataIn && c != ']') {
      if (receivedCommand.length() < 250)   // enforce maximum command length
        receivedCommand += c;
      else {
        // maximum command length exceeded. Restart
        receivedCommand = "";
        dataIn = false;
        Serial.println(F("[ERR]"));  // unrecognised command
      }
    }
    else if (dataIn && c == ']')
    {
      //finished receiving the command, process it
      StringSplitter *splitter = new StringSplitter(receivedCommand, ',', 5);   // parse the command
      String command = splitter->getItemAtIndex(0);   // process based on first word
      Serial.print(command); Serial.println(F(" -> WiFi"));
      if (command == "NTP") NTP();
      else
        Serial.println(F("[ERR]"));    // unrecognised command
      delete splitter;   // destroy when finished
      receivedCommand = "";
      dataIn = false;
    }
  }
}
// get the time from NTP
void NTP() {
  char buffer[100];     // general purpose buffer
  //get a random server from the pool
  WiFi.hostByName(ntpServerName, timeServerIP);

  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);

  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println(F("no packet yet"));
  } else {
    Serial.print(F("packet received, length="));
    Serial.println(cb);
    // We've received a packet, read the data from it
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // Send data to other processor
    snprintf(buffer, sizeof(buffer), "[NTP,%d]", epoch);
    Serial.println(buffer);
  }
  // wait ten seconds before asking for the time again
  delay(10000);
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress & address) {
  Serial.println(F("sending NTP packet..."));
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  udp.beginPacket(address, 123); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}

could you show a run of the ESP8266 just using the serial monitor?
in the ESP8266 code it may be worth simplifing the string processing in loop() to read a complete command using readstringuntil() and then searching the string using String.indexOf()

I note the Mega is outputting to an LCD - timing may be critical
Try commenting out the LCD code and see what happens

Thank very much for looking at this. I have followed your suggestions, and made some structural improvements, but the problem persists.

As requested, I have included the serial monitor window of the ESP8266. It is completely as expected. The only anomaly is the 200+ characters of garbage before the "Entered setup" message. They shouldn't cause any issue with the interprocessor comms because they are protected by [ ] . The final act of the ESP is to send "[NTP,1659924591]", which it does 20s after connecting to the Internet.

As an aside, there appears to be something in that garbage which prevents me from copy/paste. When I highlight the first line, and copy, I only get "sd" in the clipboard. The other lines copy OK.

sd{about 200 chars of garbage}Entered setup
Connecting to BigPond0277
..........................................
WiFi connected
IP address: 192.168.0.8
Starting UDP
Local port: 2390
sending NTP packet...
packet received, length=48
Seconds since Jan 1 1900 = 3868913391
[NTP,1659924591]
..................................

I have simplified the structure of the program.

  1. I have adopted your suggestion of using readStringUntil. It simplifies things a little. It is blocking, but running at 115200, and with very short commands, it shouldn't be an issue.
  2. The previous version tried to keep the Time of Day clock up to date, and this necessitated enabling interrupts in an ISR. I was never happy with that, so I now just keep y,m,d h,m,s variables updated in loop, and display them in the ISR. The Time of Day clock is ignored.
  3. I agree with your suggestion to remove the LCD, but it is almost my only diagnostic aid. I nevertheless removed all references to the LCD, and the physical LCD, with no effect. No evidence of receiving commands from the ESP. It is unlikely to be an LCD conflict as this device uses the GPIO bus only.

There must be a conflict of some kind, but I can't see it.

// real-time clock
// Author: Marc Hillman VK3OHM
// Features:
//  LCD TFT display
//  inbuilt RTC
//  WiFi

//Programming the Mega
//  DIP switches OFF OFF ON ON OFF OFF OFF OFF
//  press Reset then MODE
//  upload code

// to run
//  DIP switches ON ON  ON ON OFF OFF OFF OFF
// Tx/Rx switch set to 3
//  press Reset code will run

//#define DEBUG true // setting true will enable Serial print statements
//
#define SERIAL_BAUD 115200
// TFT LCD display
#include <UTFT.h>  // Core graphics library
#include <SPI.h>
#include <SD.h>
#include <TimeLib.h>
#include "Grotesk32x64.c"
#include "wifi.c"  // wifi logo to indicate link status

// PicoDev RV3028 RTC
#include <RV-3028-C7.h>
RV3028 rtc;   // only the UNIX clock of the rtc is used. Time of day clock is not used.
/*
  pin             INTx    interrupt number for attachInterrupt()

  3       PE5     INT5    1
  2       PE4     INT4    0
  18 TX1  PD3     INT3    5
  19 RX1  PD2     INT2    4
  20 SDA  PD1     INT1    3
  21 SCL  PD0     INT0    2

  (nc)    PE6     INT6    -
  (nc)    PE7     INT7    - */
#define interruptPin 2  // use pin 2 (INT4) for clock input

// Declare which fonts we will be using
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
volatile bool tick = true;  // indicates a 1Hz tick has occurred
tmElements_t tod;   // time broken into components

UTFT myGLCD(ILI9481, 38, 39, 40, 41);  // create panel object
#define PORTRAIT 0
#define LANDSCAPE 1
#include <StringSplitter.h>
String receivedCommand = "";
volatile bool requestNTP = false;  // set to request NTP update
int timezone = 0;
const char *tz[] = { "UTC", "Local" };
const char *DaysOfWeek[] = {"  Sunday ", "  Monday ", " Tuesday ", "Wednesday", " Thursday", "  Friday ", " Saturday" };  // strings for day of week - padded to width 9
char buffer[100];    // general purpose buffer

void setup() {
  Serial.begin(SERIAL_BAUD);
  Serial.println(F("Entered setup"));
  Serial3.begin(SERIAL_BAUD);
  Serial3.setTimeout(200);    // timeout for read until

  // Set LCD

  myGLCD.InitLCD(LANDSCAPE);
  myGLCD.clrScr();

  // Setup RTC
  Wire.begin();
  if (rtc.begin() == false) {
    Serial.println(F("Something went wrong, check wiring"));
    //while (1);
  } else
    Serial.println(F("RTC online!"));
  rtc.enableTrickleCharge(TCR_3K);   // trickle charge backup battery
  Serial.print(F("UNIX time is ")); Serial.println(rtc.getUNIX());
  // The master date/time is the UNIX value in the RTC. The calendar (year, month, day, etc) is ignored.
  breakTime(rtc.getUNIX() + 1, tod); // break current time into pieces
  rtc.disableClockOut();
  delay(1000);
  rtc.enableClockOut(FD_CLKOUT_1); // Start the 1 Hz timer
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), displayTime, FALLING);    // 1Hz pulse from rtc
}
void loop() {
  if (tick) {
    breakTime(rtc.getUNIX() + 1, tod); // break current time into pieces
    tick = false;
  }
  if (requestNTP) {
    // Request an NTP update
    wifiIcon(false);    // indicate time may be invalid by removing icon
    Serial3.println(F("[NTP]"));   // request NTP time
    requestNTP = false;
  }
  // listen for commands from other processor
  while (Serial3.available()) {
    char c = Serial3.read();  //read it
    if (c == '[') {
      //this is the start of the command string
      receivedCommand = Serial3.readStringUntil(']');
      Serial.print(receivedCommand); Serial.println(F(" -> Arduino"));
      StringSplitter *splitter = new StringSplitter(receivedCommand, ',', 10);  // parse the command
      String command = splitter->getItemAtIndex(0);                             // process based on first word
      if (command == "NTP" and splitter->getItemCount() == 2) {
        wifiIcon(true);   // indicate time is valid by showing wifi icon
        // set the RTC time. The Real Time and UNIX time are independent, so need to set both
        time_t epoch = splitter->getItemAtIndex(1).toInt();  // get UNIX TS
        Serial.print("Setting rtc to: "); Serial.println(epoch);
        rtc.setUNIX(epoch);   // and the RTC
      } else
        Serial.println(F("[ERR]"));  // unrecognised command
      delete splitter;            // destroy when finished
    }
  }
  delay(100);
}

void wifiIcon(bool display) {
  // display the wifi Icon (or not)
  if (display)
    myGLCD.drawBitmap(myGLCD.getDisplayXSize() - 32, 0, 32, 32, wifi);  // wifi logo top right
  else {
    myGLCD.setColor(VGA_BLACK);   // foreground colour
    myGLCD.fillRect(myGLCD.getDisplayXSize() - 32, 0, 32, 32);
  }
}

void displayTime() {    // display date/time ISR
  // Note: you cannot use Serial, or the I2C bus, in an interrupt routine
  char buffer[100];

  tick = true;
  myGLCD.setFont(BigFont);
  myGLCD.setColor(VGA_RED);
  myGLCD.print(tz[timezone], CENTER, 0);  // show timezone
  myGLCD.setColor(VGA_YELLOW);
  myGLCD.print(DaysOfWeek[tod.Wday - 1], CENTER, 300); // show Day of Week

  myGLCD.setFont(Grotesk32x64);
  myGLCD.setColor(0, 255, 0);
  snprintf(buffer, sizeof(buffer), "%02d.%02d.%04d", tod.Day, tod.Month, tod.Year + 1970);
  myGLCD.print(buffer, CENTER, 60);
  snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", tod.Hour, tod.Minute, tod.Second);
  myGLCD.print(buffer, CENTER, 200);
  if (tod.Minute == 0 and tod.Second == 0) requestNTP = true; // request NTP update once per hour.
}

The mystery of the garbage output by the ESP8266 at startup is solved. It has nothing to do with the issue (I think).

At startup, the ESP outputs some diagnostic info at 74880 baud. It is a bit annoying, and I wish there was a way to stop it. My comms protocol will ignore this because there is no "[" to start a command.

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 3460, room 16 
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4 
tail 4
chksum 0xc9
csum 0xc9
v00043ee0

if I load your code into the ESP8266 and run this version of my Mega test

// Arduino  Mega-WiFi_R3_ATmega2560_ESP8266 Serial3 (connected to onboard ESP8266) test
//    blinks LED and communicates over Serial3 with ESP8266

// for pinout etc see https://content.instructables.com/ORIG/FZG/PCR2/K490QMC7/FZGPCR2K490QMC7.pdf

//Programming the Mega
//  DIP switches OFF OFF ON ON OFF OFF OFF OFF
//  press Reset then MODE 
//  upload code

// to run
//  DIP switches ON ON  ON ON OFF OFF OFF OFF
//  press Reset code will run

#define LED 13  // mega LED on pin 13

void setup() {
  Serial.begin(115200);   // serial monitor
  Serial3.begin(115200);  // serial to ESP8266
  Serial.write("Arduino Mega Serial3 to ESP8266 test \n");
  pinMode(LED,OUTPUT);
  delay(500);
}

void loop() {
   static long int i=0;
   /*if(i++==100000l) {
      i=0;
      Serial.print('&');
   }*/
   static long timer=millis();
   // blink LED
   if((millis()-timer)>500) {
     timer=millis();
     digitalWrite(LED, !digitalRead(LED));
   }
   if (Serial3.available())        // read from Serial3 output to Serial
      Serial.write(Serial3.read());
   if (Serial.available()) {       // read from Serial outut to Serial3
     int inByte = Serial.read();
     Serial.write(inByte);        // local echo if required
     Serial3.write(inByte);       // write to ESP8266 
  }
}

I get on the Mega serial monitor

Arduino Mega Serial3 to ESP8266 test 
..............
WiFi connected
IP address: 192.168.1.215
Starting UDP
Local port: 2390
sending NTP packet...
packet received, length=48
Seconds since Jan 1 1900 = 3868931927
[NTP,1659943127]

which shows the ESP8266 to Mega communications is working

cannot run your Mega code as I don't have the LCD
is there anything displayed on the LCD or serial monitor when you run your mega code?

The Mega will run without the LCD. The Serial monitor is normal. You also don't have an RTC, so you'll get weird results. The Mega code should still run though. What I'm not seeing at the Mega is the arrival of the [NTP,1659943127] string. I have made some improvements (removing unused libraries and some delay statements), so you might as well have the latest Mega version.

// real-time clock
// Author: Marc Hillman VK3OHM
// Features:
//  LCD TFT display
//  inbuilt RTC
//  WiFi

//Programming the Mega
//  DIP switches OFF OFF ON ON OFF OFF OFF OFF
//  press Reset then MODE
//  upload code

// to run
//  DIP switches ON ON  ON ON OFF OFF OFF OFF
// Tx/Rx switch set to 3
//  press Reset code will run

//#define DEBUG true // setting true will enable Serial print statements
//
#define SERIAL_BAUD 115200
// TFT LCD display
#include <UTFT.h>  // Core graphics library
#include <TimeLib.h>
#include "Grotesk32x64.c"
#include "wifi.c"  // wifi logo to indicate link status

// PicoDev RV3028 RTC
#include <RV-3028-C7.h>
RV3028 rtc;   // only the UNIX clock of the rtc is used. Time of day clock is not used.
/*
  pin             INTx    interrupt number for attachInterrupt()

  3       PE5     INT5    1
  2       PE4     INT4    0
  18 TX1  PD3     INT3    5
  19 RX1  PD2     INT2    4
  20 SDA  PD1     INT1    3
  21 SCL  PD0     INT0    2

  (nc)    PE6     INT6    -
  (nc)    PE7     INT7    - */
#define interruptPin 2  // use pin 2 (INT4) for clock input

// Declare which fonts we will be using
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
volatile bool tick = true;  // indicates a 1Hz tick has occurred
tmElements_t tod;   // time broken into components

UTFT myGLCD(ILI9481, 38, 39, 40, 41);  // create panel object
#define PORTRAIT 0
#define LANDSCAPE 1
#include <StringSplitter.h>
String receivedCommand = "";
volatile bool requestNTP = false;  // set to request NTP update
int timezone = 0;
const char *tz[] = { "UTC", "Local" };
const char *DaysOfWeek[] = {"  Sunday ", "  Monday ", " Tuesday ", "Wednesday", " Thursday", "  Friday ", " Saturday" };  // strings for day of week - padded to width 9
char buffer[100];    // general purpose buffer

void setup() {
  Serial.begin(SERIAL_BAUD);
  Serial.println(F("Entered setup"));
  Serial3.begin(SERIAL_BAUD);
  Serial3.setTimeout(200);    // timeout for read until

  // Set LCD

  myGLCD.InitLCD(LANDSCAPE);
  myGLCD.clrScr();

  // Setup RTC
  Wire.begin();
  if (rtc.begin() == false) {
    Serial.println(F("RTC Something went wrong, check wiring"));
    //while (1);
  } else
    Serial.println(F("RTC online!"));
  rtc.enableTrickleCharge(TCR_3K);   // trickle charge backup battery
  Serial.print(F("UNIX time is ")); Serial.println(rtc.getUNIX());
  // The master date/time is the UNIX value in the RTC. The calendar (year, month, day, etc) is ignored.
  breakTime(rtc.getUNIX() + 1, tod); // break current time into pieces
  rtc.disableClockOut();
  delay(1000);
  rtc.enableClockOut(FD_CLKOUT_1); // Start the 1 Hz timer
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), displayTime, FALLING);    // 1Hz pulse from rtc
}
void loop() {
  if (tick) {
    breakTime(rtc.getUNIX() + 1, tod); // break current time into pieces
    tick = false;
  }
  if (requestNTP) {
    // Request an NTP update
    wifiIcon(false);    // indicate time may be invalid by removing icon
    Serial3.println(F("[NTP]"));   // request NTP time
    requestNTP = false;
  }
  // listen for commands from other processor
  if (Serial3.available()) {
    char c = Serial3.read();  //read it
    if (c == '[') {
      //this is the start of the command string
      receivedCommand = Serial3.readStringUntil(']');
      Serial.print(receivedCommand); Serial.println(F(" -> Arduino"));
      StringSplitter *splitter = new StringSplitter(receivedCommand, ',', 5);  // parse the command
      String command = splitter->getItemAtIndex(0);                             // process based on first word
      if (command == "NTP" and splitter->getItemCount() == 2) {
        wifiIcon(true);   // indicate time is valid by showing wifi icon
        // set the RTC time. The Real Time and UNIX time are independent, so need to set both
        time_t epoch = splitter->getItemAtIndex(1).toInt();  // get UNIX TS
        Serial.print(F("Setting rtc to: ")); Serial.println(epoch);
        rtc.setUNIX(epoch);   // and the RTC
      } else
        Serial.println(F("[ERR]"));  // unrecognised command
      delete splitter;            // destroy when finished
    }
  }
}

void wifiIcon(bool display) {
  // display the wifi Icon (or not)
  if (display)
    myGLCD.drawBitmap(myGLCD.getDisplayXSize() - 32, 0, 32, 32, wifi);  // wifi logo top right
  else {
    myGLCD.setColor(VGA_BLACK);   // foreground colour
    myGLCD.fillRect(myGLCD.getDisplayXSize() - 32, 0, 32, 32);
  }
}

void displayTime() {    // display date/time ISR
  // Note: you cannot use Serial, or the I2C bus, in an interrupt routine
  char buffer[100];
  tick = true;
  myGLCD.setFont(BigFont);
  myGLCD.setColor(VGA_RED);
  myGLCD.print(tz[timezone], CENTER, 0);  // show timezone
  myGLCD.setColor(VGA_YELLOW);
  myGLCD.print(DaysOfWeek[tod.Wday - 1], CENTER, 300); // show Day of Week

  myGLCD.setFont(Grotesk32x64);
  myGLCD.setColor(0, 255, 0);
  snprintf(buffer, sizeof(buffer), "%02d.%02d.%04d", tod.Day, tod.Month, tod.Year + 1970);
  myGLCD.print(buffer, CENTER, 60);
  snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", tod.Hour, tod.Minute, tod.Second);
  myGLCD.print(buffer, CENTER, 200);
  if (tod.Minute == 0 and tod.Second == 0) requestNTP = true; // request NTP update once per hour.
}

I slightly misunderstood what you had done. I understand now - clever. It certainly proves that the ESP is sending data, and that the Mega is receiving it. That narrows it down considerably. Now to work out why the Mega doesn't recognise the incoming command. I fear it will be something obvious :frowning:

I think you have almost solved it, and I'm giving you a Solution tick. It is working. I think the problem is that sometimes it takes much longer than normal to connect to the network, and the NTP string takes a LONG time to arrive. Looking closely at the connection sequence it sometimes takes over a minute, and I just assume the NTP message is never coming. If I'm patient enough, it does arrive. When the 2 halves are connected it's difficult to see what's happening. Anyway, it's now worked 3-4 times in a row, so I am VERY grateful for your help @horace . I have spent 3 weeks on what is a very straightforward problem. The whole thing was about to go in the bin, but now I have something that seems to be reliable. Thanks again VERY much.

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