Garbled Serial output when sketch includes .cpp files

On an Arduino Mega 2560:
I have two sketches. The .ino file in each is the same. However, one has a bunch of other .cpp and .h files in the same folder. They both do one simple thing:

Serial.begin(9600);
delay(1000);
Serial.print("DEADBEEF");

The Test sketch (just the .ino file) works fine: DEADBEEF is printed to the Serial console. However, the MinePlusPlus sketch (.ino plus a bunch of .cpp files) prints garbage, like:

⸮⸮xr5⸮VM⸮Rcrrgz``Dl@bF4⸮B⸮⸮bcza``⸮⸮xrb⸮h⸮⸮F⸮LNCH_z⸮⸮y⸮"⸮sW⸮

In case your browser doesn't handle that well, here it is in hex:

e2 b8 ae e2 b8 ae 78 72 35 e2 b8 ae 03 56 4d e2 b8 ae 05 52 63 72 03 72 67 7a 60 60 44 6c 40 62 46 34 e2 b8 ae 13 42 e2 b8 ae e2 b8 ae 01 62 63 7a 61 60 60 e2 b8 ae e2 b8 ae 78 72 62 e2 b8 ae 68 e2 b8 ae e2 b8 ae 46 e2 b8 ae 4c 0f 4e 43 48 5f 7a 05 e2 b8 ae 00 e2 b8 ae 79 e2 b8 ae 00 22 e2 b8 ae 73 57 e2 b8 ae

Some things I've tried:
I have tried two cables, both about 0.6m (2ft) long. My baud rate is set correctly in the Serial console. I have tried both IDEs. I have also tried a terminal Serial viewer (minicom). The problematic sketch takes up about 17kB in flash, which is a very small portion of the Mega's storage.

For reference, here is the full program (almost everything is commented out, but included just in case?):

//VERSION: storage development version
//#include "includes.h"
bool selectedGenerateButton = false;

void setup() {
  //iostream.init(9600);
  Serial.begin(9600);
  delay(1000);
  Serial.print("DEADBEEF");
  /*cout << prefix << F("\n\nCommunication Channel(s) Initialized") << endl;
  uint16_t table [8] {
    1100, 1200,
    32  , 500 ,
    2000, 4095,
    501 , 1000
  };
  storage.printTable();
  cout << F("Free space: ") << storage.getFreeSpace() << endl;
  world.setTickRate(10);
  
#ifdef PRESET_SEED
  randomSeed(PRESET_SEED);
#endif
#ifndef PRESET_SEED
  randomSeed(analogRead(A15));
#endif
  cout << prefix << F("Initializing Display") << endl;
  GLCD.Init();
  cout << prefix << F("\tComplete") << endl;
#ifndef GENERATE_ON_START
  screen.renderBitmap(Bitmaps::UI::loadIcon, 16, 2, 31, 23);
  screen.renderBitmap(Bitmaps::UI::generateIcon, 16, 2, 79, 23);
  screen.renderBitmap(Bitmaps::UI::upArrow, 8, 1, 35, 40);
#endif*/
}
void loop() {
  /*if (world.isRunning)
    worldLoop();
  else {
#ifdef GENERATE_ON_START
    GLCD.ClearScreen();
    world.isRunning = true;
    world.generate(Default);
#endif
    if (leftButton.read()) {
      selectedGenerateButton = false;
      GLCD.ClearScreen();
      screen.renderBitmap(Bitmaps::UI::loadIcon, 16, 2, 31, 23);
      screen.renderBitmap(Bitmaps::UI::generateIcon, 16, 2, 79, 23);
      screen.renderBitmap(Bitmaps::UI::upArrow, 8, 1, 35, 40);
    }
    if (rightButton.read()) {
      selectedGenerateButton = true;
      GLCD.ClearScreen();
      screen.renderBitmap(Bitmaps::UI::loadIcon, 16, 2, 31, 23);
      screen.renderBitmap(Bitmaps::UI::generateIcon, 16, 2, 79, 23);
      screen.renderBitmap(Bitmaps::UI::upArrow, 8, 1, 83, 40);
    }
    if (jumpButton.read()) {
      GLCD.ClearScreen();
      if (selectedGenerateButton) {
        world.isRunning = true;
        world.generate(Default);
      } else {
        world.isRunning = true;
        storage.load(0);
      }
    }
  }*/
}
void worldLoop() {
/*#ifdef COMMANDS_ENABLED
  if (Command::runCommands())
    screen.renderWorld();
#endif
  if (world.tryUpdate())
    screen.renderWorld();
  if (leftButton.read(Normal, PLAYER_SPEED) && !rightButton.read()) {
    CoordPair newCoords {player.getCoords(-1)};
    if (newCoords.x >= -xLimit) {
      player.move(newCoords);
      screen.renderWorld();
    }
  }
  if (rightButton.read(Normal, PLAYER_SPEED) && !leftButton.read()) {
    CoordPair newCoords {player.getCoords(1)};
    if (newCoords.x <= xLimit) {
      player.move(newCoords);
      screen.renderWorld();
    }
  }
  if (jumpButton.read(Normal, PLAYER_SPEED)) {
    CoordPair newCoords {player.getCoords(0, 1)};
    if (newCoords.y <= yLimit) {
      player.move(newCoords);
      screen.renderWorld();
    }
  }
  if (leftMouseButton.read(Normal, PLAYER_SPEED)) {
    CoordPair newCoords {player.getCoords(0, -1)};
    if (newCoords.y >= 0) {
      player.move(newCoords);
      screen.renderWorld();
    }
  }
  if (rightMouseButton.read()) {
    GLCD.ClearScreen();
    storage.save();
    exit(0);
  }
  screen.updateAnimations();*/
}

What is in these mysterious .cpp and .h files ?

1 Like

Have you set your Serial Monitor BAUD to 9600?

A lot. I branched my GitHub repo for the issue. Here it is.

Please note that in the main .ino file, I have not #included any of the files, so they shouldn’t even be linked into the compiled binary.

Yes. I have also tried baud rates 300, 115200, and 1000000 in both the sketch and the Serial Monitor.
I get different garbage at each rate.

I get pages of warnings:

/tmp/arduino_build_530200/sketch/ids.h:5:23: warning: inline variables are only available with -std=c++1z or -std=gnu++1z
 inline constexpr id_t air =            0x00;
                       ^~~

I see output at 56700 baud

That is the intended output when calling storage.sortTable(). Don’t run the sketch too much; it’s writing to EEPROM. However, in the code I linked, that function isn’t even called.
It’s strange that 57600 baud works, including for me. This may be the solution.

Oddly, the output is happen before the code runs in setup. If the first command in setup is changed to a long delay, this is the output:

Looks like the code crashes - so no telling exactly how far it gets after the last 'W' is displayed. Are you doing anything that might be attaching to a pre-defined interrupt and somehow running before setup?

Thanks to @david_2018 noticing a quirk in the sketch's behaviour, I have solved the issue.

I thought that only 3 lines were being run:

Serial.begin(9600);
delay(1000);
Serial.print("DEADBEEF");

But in fact, a lot more was happening before setup() even got called. In storage.cpp, a global instance of StorageClass was created, so its constructor was called. Since global variables are created before everything else (basically), the code in the constructor was called before setup(). In that constructor, sortTable() was called, which outputs all that "Swapping entry" stuff. It outputs it by calling operator<< on cout, which is a wrapper for Serial.print(). So Serial.print() was being called before Serial.begin(), hence causing undefined behaviour.

The lesson: be careful what you do in global or static constructors!

This is as far as I'm going to look at it. If I comment out the two lines sending data to cout in the sortTable function then the code in setup executes at the proper baudrate. I'm going to assume the serial port comes up at 57600 baud even without a serial.begin and that's why you see any output at all.

My assumption too. I have moved the code from the StorageClass constructor to an init member function, to be called after upstream.init() or Serial.begin(). That fixed the issue.

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