Problem with MEGA Serial Port#1 driven by SimpleModbusSlave

I have designed and installed a building management system that consists of a string of Arduino UNOs and MEGAs (all slaves) all controlled by a central Programmable Logic Controller (the master) over MODBUS RS485. It has generally been working well. The issue I am having is that the first serial port (Pin 0, 1) on the MEGA boards that drive the TTL-RS485 external transceiver board seems to only work occasionally and at random when powered up. This is a new problem that didn't exist when I first designed the system. When I say it "doesn't work" I mean that the MEGA is not responding to a request. If I cycle power on the MEGA enough, eventually it starts working and it stays working forever (essentially). If I switch the port to one of the other hardware ports on the MEGA, there are no issues. Has something changed in the MEGA firmware as this has seemed to occur later in the project? Here are some of the things I have tried:

  • Tried multiple new boards, including a genuine Arduino board, same result
  • Hard coded the MODBUS address in software, instead of reading from dip switches.
  • I have done testing both on the bench and in the field with the same results
  • Put an oscilloscope on the incoming RS485 request and the TTL signal going into the MEGA, all look healthy
  • The issue does not appear to be the TTL-RS485 transceiver as switching the serial port on the MEGA solves the problem.

My feeling is that there is a software issue with the port. I have attached the code. Please let me know if anyone has any ideas. It's really important I can get this issue solved quickly. Thanks for your help!!

// Building Management System - Output Unit

// This includes code from the MODBUS library
#include <SimpleModbusSlave.h>

//////////////// registers of your slave ///////////////////
enum 
{     
  // just add or remove registers and your good to go...
  // The first register starts at address 0
  Board_1,     
  Board_2,
  Board_3,
  HOLDING_REGS_SIZE // leave this one
  // total number of registers for function 3 and 16 share the same register array
  // i.e. the same address space
};

unsigned int holdingRegs[HOLDING_REGS_SIZE];

int Dip0 = 0;
int Dip1 = 0;
int Dip2 = 0;
int Dip3 = 0;
int Dip4 = 0;
int Modbus_Addr = 0;
word Board1_New = 0;
word Board2_New = 0;
word Board3_New = 0;
word Board1_Old = 0;
word Board2_Old = 0;
word Board3_Old = 0;
// End of declaring objects

void WriteOutput(word value, int start)
{
   digitalWrite(start, HIGH && (bool)(value & 1));
   digitalWrite(start+1, HIGH && (bool)(value & 2));
   digitalWrite(start+2, HIGH && (bool)(value & 4));
   digitalWrite(start+3, HIGH && (bool)(value & 8));
   digitalWrite(start+4, HIGH && (bool)(value & 16));
   digitalWrite(start+5, HIGH && (bool)(value & 32));
   digitalWrite(start+6, HIGH && (bool)(value & 64));
   digitalWrite(start+7, HIGH && (bool)(value & 128));
   digitalWrite(start+8, HIGH && (bool)(value & 256));
   digitalWrite(start+9, HIGH && (bool)(value & 512));
   digitalWrite(start+10, HIGH && (bool)(value & 1024));
   digitalWrite(start+11, HIGH && (bool)(value & 2048));
   digitalWrite(start+12, HIGH && (bool)(value & 4096));
   digitalWrite(start+13, HIGH && (bool)(value & 8192));
   digitalWrite(start+14, HIGH && (bool)(value & 16384));
   digitalWrite(start+15, HIGH && (bool)(value & 32768));

}

void setup() {  // Put your setup code here, to run once:
 
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT); 
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(14,OUTPUT); 
  pinMode(15,OUTPUT);
  pinMode(16,OUTPUT);
  pinMode(17,OUTPUT);
  pinMode(18,OUTPUT);
  pinMode(19,OUTPUT);
  pinMode(20,OUTPUT); 
  pinMode(21,OUTPUT);
  pinMode(22,OUTPUT);
  pinMode(23,OUTPUT);
  pinMode(24,OUTPUT);
  pinMode(25,OUTPUT);
  pinMode(26,OUTPUT); 
  pinMode(27,OUTPUT);
  pinMode(28,OUTPUT);
  pinMode(29,OUTPUT);
  pinMode(30,OUTPUT);
  pinMode(31,OUTPUT);
  pinMode(32,OUTPUT);
  pinMode(33,OUTPUT);
  pinMode(34,OUTPUT);
  pinMode(35,OUTPUT);
  pinMode(36,OUTPUT);
  pinMode(37,OUTPUT);
  pinMode(38,OUTPUT);
  pinMode(39,OUTPUT);
  pinMode(40,OUTPUT);
  pinMode(41,OUTPUT);
  pinMode(42,OUTPUT);
  pinMode(43,OUTPUT);
  pinMode(44,OUTPUT);
  pinMode(45,OUTPUT);
  pinMode(46,OUTPUT);
  pinMode(47,OUTPUT);
  pinMode(48,OUTPUT);
  pinMode(49,OUTPUT);
  pinMode(50,OUTPUT);
  pinMode(51,OUTPUT);
  pinMode(52,OUTPUT);
  
  pinMode(A0,INPUT_PULLUP);
  pinMode(A1,INPUT_PULLUP);
  pinMode(A2,INPUT_PULLUP);
  pinMode(A3,INPUT_PULLUP);
  pinMode(A4,INPUT_PULLUP);
  
  //Assign the modbus device ID.
  Dip0 = (int) !digitalRead(A0);
  Dip1 = (int) !digitalRead(A1);
  Dip2 = (int) !digitalRead(A2); 
  Dip3 = (int) !digitalRead(A3); 
  Dip4 = (int) !digitalRead(A4);
  Modbus_Addr = Dip0*1+Dip1*2+Dip2*4+Dip3*8+Dip4*16;

  modbus_configure(&Serial, 19200, SERIAL_8E1, Modbus_Addr, 2, HOLDING_REGS_SIZE, holdingRegs); 
  
  WriteOutput(65535, 5);
  WriteOutput(65535, 21);
  WriteOutput(65535, 37);

}  // End of setup

void loop() {  // Put your main code here, to run repeatedly:

  
  Board1_New = holdingRegs[Board_1];
  Board2_New = holdingRegs[Board_2];
  Board3_New = holdingRegs[Board_3];

//  Write Output to Board #1 if ouput status has changed 
  if (Board1_New != Board1_Old)
  {
    WriteOutput(Board1_New,5);
    Board1_Old = Board1_New;
  }

//  Write Output to Board #2 if ouput status has changed 
  if (Board2_New != Board2_Old)
  {
    WriteOutput(Board2_New,21);
    Board2_Old = Board2_New;
  }
 
 //  Write Output to Board #3 if ouput status has changed  
  if (Board3_New != Board3_Old)
  {
    WriteOutput(Board3_New,37);
    Board3_Old = Board3_New;
  }
  
  modbus_update();
}  // End of loop

While powering on is there traffic on the Modbus? The only difference between the first and the other serial interface on the Mega2560 is the first one is used for software updates (so in the first two seconds after a power cycle/reset the bootloader controls the port and may stay on depending on what it receives on the interface).

Does it work if you disconnect the Modbus from the node while powering on? Have you tried to program the Mega buy a ICSP Programmer without the bootloader?

That is an excellent observation, I think you hit the nail on the head! If I stop the MODBUS polling and power up the MEGA first then reinitiate polling, the MEGA responds every time. The only thing is that I am also running SimpleModbusSlave on UNO boards and they don't appear to have this problem? Not sure what the difference is. Anyway, I am not very familiar with ICSP programmers. I'm assuming the solution would be to eliminate the bootloader and load the sketch through the ICSP? Can you point me to some simple instructions to do this? Thanks so much for your help.

Not sure what the difference is.

The bootloader. The UNO doesn't accept new sketches on power up, just after a reset. The Mega waits for new code in both cases.

I'm assuming the solution would be to eliminate the bootloader and load the sketch through the ICSP?

That depends on the intended usage. Is it normal that the Mega powers up while the Modbus is actively transmitting data?

Can you point me to some simple instructions to do this?

You need additional hardware (you can use a spare Arduino with a special sketch and a slight modification, google for "Arduino as ICSP programmer"). Once you have the programmer in place, just select "Upload using Programmer" instead of "Upload" to upload your sketch.

pylon, you have been extremely helpful! Thank you. The MEGAs are controlling ventilation equipment in the building and should they momentarily loose power or reset, it's really inconvenient to have them come back and not be able to connect to the network. I want the system to have resilience after a power interruption.

Instead of going the DIY route with an Arduino, I ordered the following, I believe this will be what's needed:

I'm assuming that the "upload using programmer" will both load the sketch and erase the bootloader? Thanks again for your help.

brunsda:
I'm assuming that the "upload using programmer" will both load the sketch and erase the bootloader?

That's correct.