Constant string in the middle of a program changed

This exactly my problem. Small tweaks to the code make the glitch jump to another string (I cannot show it on a simulator because the missing hardware) or break the functionality. I wonder what and how changes this text in the first place..

Wrap every Serial.print("Never gonna give! you! up!"); in the F macro to put the text in non-program memory.

Serial.print(F("Never gonna give! you! up!"));

I count 40 occurrences of Serial.print(" and Serial.println("

Variables declared in case code means that the entirety of that case's code must be { embraced }.

I'm in transit, but I think I saw that not being done?

In any case, go to the IDE prefernces and dial up the warning level and verbosity and heed the red ink.

a7

Got no warnings from the compiler...

Compiling will show memory status. Would you post that, here? (I can not find your libraries, so I can not install them on my system)

... I made exactly three replacements (out of 40) with the F macro... and your sketch did not have the garbage character.

So... this is not a "software" issue, this is a memory issue. Do the 40 macro changes and your program should run. It might choke if not enough space remains for stacks and swaps and stuff. See post #44.

#include <TroykaTextLCD.h>

If this library supports the F macro, then I would suggest using it with all the text in the lcd.print( ) statements as well. RAM on these small Atmega's is precious.

Last time it was like 63% used. Did not look like it is the edge and i don't do any big local variables.
Anyway, will do Fs tomorrow, thank you for you suggestions!

If "Sketch uses" is 63%, I imagine "Global variables" will probably be "leaving" only a few bytes, or negative (100%+). Check the "before" against "after."

Sketch uses 8832 bytes (28%) of program storage space. Maximum is 30720 bytes.
Global variables use 618 bytes (30%) of dynamic memory, leaving 1430 bytes for local variables. Maximum is 2048 bytes.

I wish a global thingy existed that forces non-program data into non-program space.

I played around a bit with the wokwi simulation, looks almost like something in the code writing to a fixed memory location. I could move the problem character around by changing the size of the "lines" array, decreasing the 2nd dimension from 11 to 10 takes three bytes less memory, and the erroneous character moves three characters to the right, overwriting the terminating null. Increasing the size by three bytes shifts the error left, overwriting the "r" in "reader".

Odd that printing the offending text at the very beginning of the code, then inserting a very long delay, still shows the error. Almost as if a constructor or other code that is executed before setup() is altering the memory.

Don't seem to be able to replicate the problem on a Leonardo here, possibly because I'm using a different version of a library, or different version of the compiler.

Yes. It seems that the compiler can overlook this and issue no warning.

Even if it wasn't the problem here, remains the fact that variables local to a case in a switch/case require the braces, I recommend you just get in that habit now.

a7

That's where I'd be looking.

Thank you for trying. I eyeballed constructors of all non-standard libraries (Adafruit, Troyka, etc), with no luck so far.

Dear team!
With all your comments I think I found a root cause!!!
Adafruit_PN532 nfc(PIN_PN532_IRQ, 100);
I copy-pasted this line from an example. Second argument is a reset pin that is not used in this model of the shield.
Then the constructor uses this argument and runs this
pinMode(_reset, OUTPUT);
I found the source code for the pinMode. It does not do the range check AND IT DOES DO THE BIT OR operation

		uint8_t oldSREG = SREG;
                cli();
		*reg |= bit;
		SREG = oldSREG;

I changed 100 to harmless 9 and problem went away.

Some important lessons learned from this:

  1. Arduino community is amazing
  2. Do not blindly copy the examples
  3. Do not put any weird parameter values even if they look unused
  4. If problem does not solve - have a break, get some sleep and it will definitely solve in the morning

Thanks again everybody, you guys are awesome!
Will keep the topic open for day for some extra questions/comments if any.

Great that you found that out! This is definitely not astarters kevel issue!

I did not even look at the Adafruit library, wrongly assuming that it was common enough that a problem like this would have been addressed already.

You might want to post this on the github site for the library, the general convention seems to be using -1 for an unused pin, but the library does not check for that either.

Is it safe to specify "-1"? As I got burned with 100, I used one of the real pin numbers.

I do not think it's safe; it's used in two places (for your I2C use, as far as I can see) in the library

Adafruit_PN532::Adafruit_PN532(uint8_t irq, uint8_t reset, TwoWire *theWire)
    : _irq(irq), _reset(reset) {
  pinMode(_irq, INPUT);
  pinMode(_reset, OUTPUT);
  i2c_dev = new Adafruit_I2CDevice(PN532_I2C_ADDRESS, theWire);
}

and

void Adafruit_PN532::reset(void) {
  // see Datasheet p.209, Fig.48 for timings
  if (_reset != -1) {
    digitalWrite(_reset, LOW);
    delay(1); // min 20ns
    digitalWrite(_reset, HIGH);
    delay(2); // max 2ms
  }
}

The first one might cause a problem; the second one has the safeguard.

It is a reported bug in GitHub, but is not likely to get fixed.

https://github.com/arduino/ArduinoCore-avr/issues/149

So, in the first call, the reset pin value is typed uint8_t, hence 0-255.
But, in the second snippet, the _reset value must be -1. To be that value, it would have to have been passed as 255 as a uint8_t.

Rather strangely sloppy code, to my way of thinking. What have I missed?