CAN_BUS_Shield library working erratically WITHOUT Serial.begin activated.

Hello everyone,

My problem : my system works erratically when I don't activate Serial.begin. I can't understand why.

I'm building the control system of an electric airship.
Here is my system : I have 1 "Master" Arduino Mega 2560 giving orders to 2 "Slaves" Arduino Nano on a can bus. First the master sends instructions to a slave, the slave answers the order with its measures. Then the master talks to another node.

Inventory :
-Mega Pro CH340G /Atmega2560
x2-Mini Nano V3.0 ATmega328P
x3-CAN bus module MCP2515
I'm powering my system with a TENMA Digital-Control DC Power supply 30V 5A set to 5V, powering the 2 nanos, 2 CAN modules, + 4 servomotors. The master part is powered with USB to a laptop.
x4 servos + 1 brushless motor + 2 DS18b20 + 1 joystick + potentiometers + switches

I'm using the CAN_BUS_SHIELD library from Seeed-Studio.
Here is the code of the Mega, made with FSM :
(pardon my french but I won't rewrite every com)

#include <SPI.h>
#include <Wire.h>
#include <mcp_can.h>
#include <Arduino.h>
#include <U8x8lib.h>

//Définition des états de la FSM
#define STATE_INIT 1
#define STATE_ENVOI_MESSAGE 2
#define STATE_ATTEND_REP 3
#define STATE_GET_INFOS 4
#define STATE_DISPLAY 5

//Définition des noeuds attachés au système
#define EMPENNAGE 1
#define MOT_LAT_DROIT 2
#define MOT_LAT_GAUCHE 3
#define UNDEFINED 4

//Mappage des pins

//joystick
const int pinSW = 14; // digital pin connected to SW D2 (clic joystick)
const int pinX = 56; // analog pin connected to VRx A2
const int pinY = 57; // analog pin connected to VRy A3
//module CAN
const int pinSpiCS_CAN = 15;
//potentiomètre
const int pinPot1 = 54; //A0
//switch
const int pinSwitch = 23;

//objet CAN
MCP_CAN CAN(pinSpiCS_CAN);

U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);   // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED

void setup()
{
  u8x8.begin();

  Serial.begin(115200);
  pinMode(pinSW, INPUT); //clic joystick
  digitalWrite(pinSW, HIGH);
  pinMode(pinSwitch, INPUT_PULLUP);

  //initialisation bus CAN
  while (CAN_OK != CAN.begin(CAN_1000KBPS, MCP_16MHz))
  {
    Serial.println("CAN BUS Init Failed");
    delay(100);
  }
  Serial.println("CAN BUS  Init OK!");

  cli();//stop interrupts
  TCCR2A = 0; //default
  TCCR2B = 0b00000110; // clk/256 est incrémenté toutes les 16uS
  TIMSK2 = 0b00000001; // TOIE2
  sei();//allow interrupts
}

//définition/initialisation des variables
byte valPot1 = 0;
byte len = 0;
byte Compteur = 0;  //Compteur pour interruption
byte trameReception[4];
byte trameConsigne[4];
byte infos[4][4];
volatile bool flag1s = 0;
static byte state = STATE_ENVOI_MESSAGE;
static byte currentNode = 0;
unsigned long currentMillis = 0;
byte compt = 0;

ISR (TIMER2_OVF_vect) //interruption pour le timer2
{
  // 256-6 --> 250X16uS = 4mS
  // Recharge le timer pour que la prochaine interruption se déclenche dans 4mS
  TCNT2 = 6;
  if (Compteur++ == 250) {
    Compteur = 0;
    flag1s = 1;
  }
}

void loop()
{
  switch (state) {

    case STATE_ENVOI_MESSAGE:
      {
        //delay(2); //?? n'améliore pas les choses
        if (flag1s == 1)
        {
          state = STATE_DISPLAY;
          flag1s = 0;
          break;
        }
        increaseNode();
        Serial.println("");
        Serial.println("*******************************");
        Serial.print(millis());
        Serial.print("Communication avec le noeud ");
        Serial.println(currentNode);
        Serial.println("STATE_ENVOI_MESSAGE");
        if (currentNode == EMPENNAGE)
        {
          trameConsigne[1] = byte(analogRead(pinX) / 4);
          trameConsigne[2] = byte(analogRead(pinY) / 4);
          trameConsigne[3] = byte(digitalRead(pinSW));
        }
        if (currentNode == MOT_LAT_DROIT)
        {
          trameConsigne[1] = byte(analogRead(pinPot1) / 4);
          trameConsigne[2] = 0;
          trameConsigne[3] = byte(digitalRead(pinSwitch));
        }
        if (currentNode == MOT_LAT_GAUCHE)
        {

        }
        if (currentNode == UNDEFINED)
        {

        }
        trameConsigne[0] = compt;
        compt++;
        byte adresseCAN = ((1 << 4) | currentNode );
        CAN.sendMsgBuf(adresseCAN, 0, 4, trameConsigne);
        state = STATE_ATTEND_REP;
        break;
      }

    case STATE_ATTEND_REP:
      Serial.println("STATE_ATTEND_REP");
      static bool pasDeMessageDuBonNoeud;
      pasDeMessageDuBonNoeud = true;
      currentMillis = millis();
      while ( ((unsigned long)(millis() - currentMillis) < 6) && pasDeMessageDuBonNoeud )
      {
        if (CAN_MSGAVAIL == CAN.checkReceive())
        {
          //Serial.println("Message recu");
          CAN.readMsgBuf(&len, trameReception);
          if (CAN.getCanId() == ((2 << 4) | currentNode ))
          {
            afficherMessageSerial();
            Serial.println("Message du bon noeud");
            pasDeMessageDuBonNoeud = false;
            rstErr(); //reset du compteur d'erreur propre au noeud
          }
        }
      }
      if (pasDeMessageDuBonNoeud == true)
      {
        addErr(); //augmente le compteur d'erreur propre au noeud
        Serial.print("Pas de rep du noeud ");
        Serial.println(currentNode);
        state = STATE_ENVOI_MESSAGE;
      }
      else
      {
        state = STATE_GET_INFOS;
      }
      break;

    case STATE_GET_INFOS:
      Serial.println("STATE_GET_INFOS");
      infos[currentNode - 1][1] = trameReception[1];
      infos[currentNode - 1][2] = trameReception[2];
      infos[currentNode - 1][3] = trameReception[3];
      state = STATE_ENVOI_MESSAGE;
      break;

    case STATE_DISPLAY:
      Serial.println("");
      Serial.println("-------------------------------");
      Serial.println("STATE_DISPLAY");
      Serial.println("-------------------------------");
      //      u8x8.setFont(u8x8_font_px437wyse700b_2x2_r);
      u8x8.setFont(u8x8_font_chroma48medium8_r);
      u8x8.setCursor(0, 0);
      u8x8.print("Emp.:");
      u8x8.print(infos[0][0]); //erreur Emp
      u8x8.print("  ");
      u8x8.setCursor(0, 1);
      u8x8.print("MLD.:");
      u8x8.print(infos[1][0]); //erreur MLD
      u8x8.print("  ");
      u8x8.setCursor(8, 1);
      if ((infos[1][1] >> 7) == 0) //détermine si c'est une valeur positive ou négative
      {
        u8x8.print(infos[1][1]); //Temp
      }
      else
      {
        u8x8.print("-"); //Temp
        u8x8.print(infos[1][1] - 128); //Temp
      }
      u8x8.setCursor(11, 1);
      if ((infos[1][2] >> 7) == 0) //détermine si c'est une valeur positive ou négative
      {
        u8x8.print(infos[1][2]); //Temp
      }
      else
      {
        u8x8.print("-"); //Temp
        u8x8.print(infos[1][2] - 128); //Temp
      }
      u8x8.setCursor(0, 2);
      u8x8.print("MLG.:");
      u8x8.print(infos[2][0]); //erreur MLG
      u8x8.print("  ");
      u8x8.setCursor(0, 3);
      u8x8.print("Und.:");
      u8x8.print(infos[3][0]); //erreur Und
      u8x8.print("  ");

      state = STATE_ENVOI_MESSAGE;
      break;

    default:
      Serial.println("STATE_DEFAULT");
      state = STATE_ENVOI_MESSAGE;
      currentNode = 0;
      break;
  }


//************************* Fonctions *************************

void increaseNode(void) {
  if (currentNode == UNDEFINED) {
    currentNode = EMPENNAGE;
  }
  else {
    currentNode++;
  }
}

void rstErr(void) {
  infos[currentNode - 1][0] = 0;
}

void addErr(void) {
  if (infos[currentNode - 1][0] < 255)
  {
    infos[currentNode - 1][0]++;
  }
}

void afficherMessageSerial(void) {
  unsigned long canId = CAN.getCanId();
  Serial.println("-----------------------------");
  Serial.print("Data from ID: 0x");
  Serial.println(canId, HEX);
  for (int i = 0; i < len; i++)
  {
    Serial.print(trameReception[i]);
    Serial.print("\t");
  }
  Serial.println();
}

Here is one of the node :

#include <SPI.h>
#include <mcp_can.h>
#include <Servo.h>
#include <OneWire.h> //pour la sonde température

//Variables à modifier :
#define SEC_AVANT_RESET 2
#define CE_NOEUD 2

//Définition des états de la FSM
#define STATE_INIT 1
#define STATE_MAIN 2
#define STATE_ENVOI_MESSAGE 3

#define EMPENNAGE 1
#define MOT_LAT_DROIT 2
#define MOT_LAT_GAUCHE 3
#define UNDEFINED 4

//Définition des broches /!\ interdit d'utiliser pin 3 et et 11 car utilisation du timer2
const int pinCSSpi = 10; //module CAN
const int pinMot = 5;
const int pinServoDir = 6;
const byte interruptPin = 2; //interruption pour le CAN
const int pinPot1 = 23; //A0
const byte BROCHE_ONEWIRE = 9; //sondes DS18B20

//Définition des variables
volatile bool flagRecv = 0;
volatile bool flag1s = 0;
unsigned char len = 0;
byte trameReception[4];
byte consigne = 0;
byte destination = 0;
unsigned long currentMillis = 0;
unsigned long motMillis = 0;
byte Compteur = 0;  //Compteur pour interruption
byte trameInfos[4];
int erreur_compteur = 0;
static int state = STATE_MAIN;
byte adresseCAN = ((2 << 4) | CE_NOEUD ); //adresse CAN pour l'envoi de ce noeud
byte monMessageDuPupitre = ((1 << 4) | CE_NOEUD ); //adresse CAN pour la réception
unsigned int angleDir = 0;
unsigned int angleMot = 0;
const byte SENSOR_ADDRESS_1[] = { 0x28, 0x32, 0x07, 0x79, 0xA2, 0x01, 0x03, 0x68 };
const byte SENSOR_ADDRESS_2[] = { 0x28, 0x4B, 0x7B, 0x79, 0xA2, 0x01, 0x03, 0x2A };

MCP_CAN CAN(pinCSSpi);                   // Set CS pin
Servo servoMot;
Servo servoDir;
//objet sonde temp
OneWire ds(BROCHE_ONEWIRE);

void setup() {
  //Serial.begin(115200);
  //  delay(100); // on s'assure que les servos soient réveillés, module CAN etc
  delayMicroseconds(16000);
  servoMot.attach(pinMot, 1000, 2000);
  servoDir.attach(pinServoDir, 771, 2740);
  servoDir.write(0);
  servoMot.write(0);
  while (CAN_OK != CAN.begin(CAN_1000KBPS, MCP_16MHz)) {
    //Serial.println("CAN BUS init fail");
    delayMicroseconds(16000);
    delayMicroseconds(16000);
    delayMicroseconds(16000);
  }
  //Serial.println("CAN BUS init ok!");
  CAN.init_Mask(0, 0, 0x3ff);                         // there are 2 mask in mcp2515, you need to set both of them
  CAN.init_Mask(1, 0, 0x3ff);
  CAN.init_Filt(0, 0, monMessageDuPupitre);                          // there are 6 filter in mcp2515

  setupTemperatureMeasure(SENSOR_ADDRESS_1);
  setupTemperatureMeasure(SENSOR_ADDRESS_2);

  cli();//stop interrupts
  TCCR2A = 0; //default
  TCCR2B = 0b00000110; // clk/256 est incrémenté toutes les 16uS
  TIMSK2 = 0b00000001; // TOIE2
  sei();//allow interrupts
  currentMillis = millis();
  attachInterrupt(digitalPinToInterrupt(interruptPin), MCP2515_ISR, FALLING); // start interrupt
}

void MCP2515_ISR() { //interruption du module CAN
  flagRecv = 1;
}

ISR (TIMER2_OVF_vect) //interruption pour le timer2
{
  // 256-6 --> 250X16uS = 4mS
  // Recharge le timer pour que la prochaine interruption se déclenche dans 4mS
  TCNT2 = 6;
  if (Compteur++ == 250) {
    Compteur = 0;
    flag1s = 1;
  }
}

void loop() {

  switch (state) {

    case STATE_INIT:
      //Serial.println("STATE_INIT");
      cli();
      erreur_compteur = 0;
      //On réinitialise la position des servos en cas de rupture liaison
      servoMot.write(0);
      servoDir.write(65);
      while (CAN_OK != CAN.begin(CAN_1000KBPS, MCP_16MHz)) {
        //Serial.println("CAN BUS init fail");
        delayMicroseconds(16000);
      }
      CAN.init_Mask(0, 0, 0x3ff);                         // there are 2 mask in mcp2515, you need to set both of them
      CAN.init_Mask(1, 0, 0x3ff);
      CAN.init_Filt(0, 0, monMessageDuPupitre);                          // there are 6 filter in mcp2515
      sei();
      currentMillis = millis();
      state = STATE_MAIN;
      break;

    case STATE_MAIN:
      //Serial.println("STATE_MAIN");
      if (flagRecv) {// check if get data
        //Serial.println("RECU");
        CAN.readMsgBuf(&len, trameReception); // read data,  len: data length, trameReception: data buf
        if (CAN.getCanId() == monMessageDuPupitre)
        {
          if (trameReception[3] == 0) //check si la consigne moteur est OFF
          {
            destination = 0;
          }
          else
          {
            destination = map(byte(trameReception[1]), 0, 255, 0, 179);
          }
          angleDir = map(trameReception[1], 0, 255, 0, 130);
          angleMot = map(consigne, 0, 255, 0, 130);
          erreur_compteur = 0;
          //Serial.println(trameReception[0]);
          CAN.sendMsgBuf(adresseCAN, 0, 4, trameInfos);
          currentMillis = millis();
        }
        flagRecv = 0;                // clear flag
        if (flag1s) {                // check if 1s
          cli();
          startTemperatureMeasure(SENSOR_ADDRESS_1);
          startTemperatureMeasure(SENSOR_ADDRESS_2);
          trameInfos[1] = readTemperatureMeasure(SENSOR_ADDRESS_1);
          trameInfos[2] = readTemperatureMeasure(SENSOR_ADDRESS_2);
          sei();
          flag1s = 0;                // clear flag
        }
      }
      if ( ((unsigned long)(millis() - currentMillis) > 1000))
      {
        erreur_compteur++;
        //Serial.print("Pas d'ordre du pupitre depuis ");
        //Serial.print(erreur_compteur);
        //Serial.println(" sec");
        if (erreur_compteur >= SEC_AVANT_RESET)
        {
          state = STATE_INIT;
        }
        currentMillis = millis();
      }
      //gestion du "ramp-up" pour le moteur
      if ( (unsigned long)(millis() - motMillis) > 10)
      {
        if (destination > consigne)
        {
          consigne++;
        }
        if (destination < consigne)
        {
          consigne--;
        }
        servoDir.write(angleDir);
        servoMot.write(angleMot);
        motMillis = millis();
      }
      break;


    default:
      //Serial.println("STATE_DEFAULT");
      state = STATE_MAIN;
      break;
  }
}

/**
   Fonction de démarrage de la prise de mesure de la température via un capteur DS18B20.
*/
void startTemperatureMeasure(const byte addr[]) {
  // addr[] : Adresse du module 1-Wire détecté

  /* Reset le bus 1-Wire et sélectionne le capteur */
  ds.reset();
  ds.select(addr);

  ds.write(0x44, 1);
}

void setupTemperatureMeasure(const byte addr[]) {
  // addr[] : Adresse du module 1-Wire détecté
  /* Reset le bus 1-Wire et sélectionne le capteur, passe en mode 9bits, copie dans l'EEPROM, vérifie le changement */
  cli();
  ds.reset();
  ds.select(addr);
  ds.write(0x4E);//change le registre pour mettre le mode 9 bits
  ds.write(0x00);
  ds.write(0x00);
  ds.write(B00011111);
  ds.write(0x48); //copy scratchpad
  ds.write(0xB8); //recall eeprom
  sei();
}

/**
   Fonction de récupération de la prise de mesure de la température via un capteur DS18B20.
*/
byte readTemperatureMeasure(const byte addr[]) {
  byte data[9];
  // data[] : Données lues depuis le scratchpad
  // addr[] : Adresse du module 1-Wire détecté
  /* Reset le bus 1-Wire, sélectionne le capteur et envoie une demande de lecture du scratchpad */
  ds.reset();
  ds.select(addr);
  ds.write(0xBE);
  /* Lecture du scratchpad */
  for (byte i = 0; i < 9; i++) {
    data[i] = ds.read();
  } 
  /* Calcul de la température en degré Celsius output sur 1 octet*/
  return (byte) ((data[1] << 4) | data[0] >> 4);
}

I made a program to see messages on the bus, here is what I see when I activate Serial.begin on the master :

Message du pupitre         -
MESSAGE pupitre => noeud
---------------------------
Get data from ID: 0x11
98 7C 7D 1 a bien rep


  Message d'un noeud         |
---------------------------
Get data from ID: 0x21
0 0 0 0 

  Message du pupitre         -
---------------------------
Get data from ID: 0x12
99 FF 0 1 

  Message du pupitre         -
---------------------------
Get data from ID: 0x13
9A FF 0 1 

  Message du pupitre         -
---------------------------
Get data from ID: 0x14
9B FF 0 1

If I don't activate Serial.begin :

  Message du pupitre         -
---------------------------
Get data from ID: 0x12
61 FF 0 1 

  Message du pupitre         -
---------------------------
Get data from ID: 0x13
62 FF 0 1 

  Message d'un noeud         |
---------------------------
Get data from ID: 0x21
0 0 0 0 

  Message du pupitre         -
---------------------------
Get data from ID: 0x12
65 FF 0 1 

  Message du pupitre         -
---------------------------
Get data from ID: 0x14
67 FF 0 1 

  Message d'un noeud         |
---------------------------
Get data from ID: 0x21
0 0 0 0

We can see that the system starts to work erratically when I disable Serial.begin from the master.

I had another issue in the same way. I'm using filters to allow only messages sent from the master to a slave to make an interrupt. It works well when the slave has Serial.begin activated and doesn't work at all without Serial.begin.
Edit : This issue seems fixed with several changes made recently (can't understand why)

What am I missing With the Serial.begin implication ?

Any help or suggestion would be appreciated.

Thank you very much.

No idea about the serial initialisation.

Does the CAN bus speed need to be that high?
The Mega takes about 1.6ms to receive a message from the MCP2515. At CAN bus speeds above 500 kpbs messages can arrive at intervals of less than a millisecond. The MCP2515 has a small receive buffer so there is a high probability that it will fill up faster than the Mega can empty it. Once the MCP2515 receive buffer is full additional messages will be ignored.