Code works UNO 4 WIFI OK but Fails on Nano

Hello. I've developed this code on an Arduino UNO 4 WiFi to display the time on a single IV-4 VFD Tube. It works perfectly for days at a time and never fails. However, when I move it to a Nano it corrupts unless I comment out the first 2 steps of the animation sequence. It appears to loop forever picking up random corrupted data. This can be reproduced without being connected to my project. Just run the code on a NANO and look at the serial monitor. I hope I'm posting this in the correct place. Any advice gratefully received.


#include <Arduino.h>
#include <RTClib.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <Wire.h>

TinyGPSPlus gps; // The TinyGPS++ object
RTC_DS3231 rtc;

const int RX_PIN = 9, TX_PIN = 10; // GPS Pins
const int rtc_address = 0x68;// I2C address of RTC module

int TimeSync = 11; // Sets the timesync pin to 5
int Adjust = 12;
int timezone = 10; // timezone offset
int W = 30; // Delay between each layer of the digit

int latchPin = 4; // connect to the ST_CP of 74HC595 (pin 3,latch pin)
int clockPin = 5; // connect to the SH_CP of 74HC595 (pin 4, clock pin)
int dataPin = 2; // connect to the DS of 74HC595 (pin 2, data pin)

SoftwareSerial gps_serial(RX_PIN, TX_PIN); // The serial interface to the GPS device
String gps_data; // I think i need this

// +++++++++++++ Segment definitions. Two bytes per digit. (16 segment digits)

byte SegDisplay[10][13] = { 

{B00101110,B11110110,B00011110,B10001110,B01011101,B10011100,B11011100,B10101110,B00011100,B00011100,B00000000,B11111111,B11100011}, // A Seg
{B00110000,B10101011,B10110011,B00111011,B01111110,B00111010,B00111000,B11101111,B00111000,B00111110,B00000000,B11111111,B11101111}, // B Seg
{B01101111,B11110111,B01011111,B11001111,B01011101,B11011101,B11011101,B11101111,B01011101,B01011101,B00000000,B11111111,B11100011}, // C Seg
{B00110000,B10101011,B10110011,B00111011,B01111110,B00111010,B00111000,B11101111,B00111000,B00111110,B00000000,B11111111,B11100011}, // D Seg
{B11111111,B11111111,B11011111,B11011111,B11011101,B11011101,B11011101,B11111111,B11011101,B11011101,B00000000,B11111111,B11100011}, // E Seg
{B00110001,B10101011,B10110011,B00111011,B01111111,B00111011,B00111001,B11101111,B00111001,B00111111,B00000000,B11111111,B11100011}, // F Seg
{B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B00000000,B11111111,B11100011}, // G Seg
{B00110001,B10101011,B10110011,B00111011,B01111111,B00111011,B00111001,B11101111,B00111001,B00111111,B00000000,B11111111,B11100011}, // H Seg
{B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B00000000,B11111111,B11100011}, // I Seg
{B10111011,B10111011,B10111011,B10111011,B11111111,B10111011,B10111011,B11111111,B10111011,B10111111,B00000000,B11111111,B11100011} // J Seg
};

// Function "Shift2Bytes" that gets called 10 times in the main loop
void Shift2Bytes(byte Byte1, byte Byte2,int Delay)
{
    // 1 set the latchPin to low potential, before sending data
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, Byte1);
    // Send First Half of Digit
    shiftOut(dataPin, clockPin, LSBFIRST, Byte2);
    // Send Second Half of Digit
    // set the latchPin to high potential, after sending data
    digitalWrite(latchPin, HIGH);
    // while (Serial.available() == 0) { };
    // Serial.read();
    // Serial.println("Key pressed! Exiting the loop.");
    delay(Delay);
}


 // Set RTC with GPS Function - Get NEMA String, make sure its valid data and extract hhmmss digits
void GPSSync(){
 
  // Send the WiFi Symbol to the Tube. This will stay until GPS string is valid
  Shift2Bytes(SegDisplay[1][12], SegDisplay[0][12], W);
  delay(10000); // Time for the GPS to settle down (300000 for 5 minutes)

  while (true) { 
    String gps_data = gps_serial.readStringUntil('\n');
    Serial.println(gps_data);                 // Serial Monitor Heatbeat Only
    int S = gps_data.substring(7, 9).toInt(); // Grabs the seconds string in advance and converts to Big S 
    if ((gps_data.startsWith("$GPGGA")) && (S != 0)) // Makes sure that $GPGGA is present and makes sure seconds is NOT zero

    { // If good above, do all this Now
      int hh = gps_data.substring(7, 9).toInt(); // Extract Hour
      int mm = gps_data.substring(9, 11).toInt(); // Extract Minutes
      int ss = gps_data.substring(11, 13).toInt(); // Extract Seconds (again but diff variable)
      hh = hh + timezone; // add the timezone offset. Need to automate this.
      if (hh >= 24) hh = hh - 24; // Normalise so we dont get 33 o'clock for example
      rtc.adjust(DateTime(gps.date.year(), gps.date.month(), gps.date.day(), hh, mm, ss)); // Need to also get Date info for auto DLS
      break; 
    } // End get time set time
  } // End check GPS for valid time loop
}

void setup() {
  Serial.begin(9600);
  gps_serial.begin(9600);
  Wire.begin(); // Dont think i need this now
  rtc.begin(); 
  
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Only use if GPS breaks

// Define the Pin Funtions
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(TimeSync, INPUT_PULLUP); // Holds Pin 11 High waiting for ground contact
  pinMode(Adjust, INPUT_PULLUP); // Holds Pin 12 High waiting for ground contact
} // End Setup


void loop() {

  DateTime now = rtc.now();
  
  char timeString[4]; // Convert the time and date values into strings
  sprintf(timeString, "%02d%02d%02d%02", now.hour(), now.minute());
 
  // Select the 4 timestring array values one digit at a time. This is the engine that steps through the timestring elements above. 
  // It's working with strings so later on I convert string -> char -> byte

    for (int i = 0; i < 4; i++) // Loops 1 to 4 for each digit HHMM
     { //x 
      String the_number = String(timeString[i]); // looks at each of the 4 char/numbers in timestring and allocates them in turn to "the number"

      { // y
     Serial.println(the_number[0]); // Should see the number digit displayed in IDE serial monitor
     char x = the_number[0];     // convert the number[0] to a character variable named x
     byte b = x - '0';    // convert x to a byte value called b for use below

// THIS SECTION Lights and unlights the Digit a layer at a time
// I have to comment out the first, or any 2 lines for it to work on a NANO. 9 Steps or more breaks the NANO

    // Shift2Bytes(SegDisplay[9][b], SegDisplay[8][b], W); Commented out for NANO
    // Shift2Bytes(SegDisplay[7][b], SegDisplay[6][b], W); Commented out for NANO
    Shift2Bytes(SegDisplay[5][b], SegDisplay[4][b], W);
    Shift2Bytes(SegDisplay[3][b], SegDisplay[2][b], W);
    Shift2Bytes(SegDisplay[1][b], SegDisplay[0][b], 1000);
    Shift2Bytes(SegDisplay[3][b], SegDisplay[2][b], W);
    Shift2Bytes(SegDisplay[5][b], SegDisplay[4][b], W);
    Shift2Bytes(SegDisplay[7][b], SegDisplay[6][b], W);
    Shift2Bytes(SegDisplay[9][b], SegDisplay[8][b], W);
    Shift2Bytes(SegDisplay[1][11], SegDisplay[0][11], 200); // Blank Display

       } // End of individual digit / NANO loops here forever with corrupted values unless first two steps are commented out
 
    } // End of block of 4 digits
        
    delay(1600); // 1500 milliseconds blank time between each time display block is about right
    
   } // END. Back to start to get new time

Project

Your buffer is 4 bytes long, but you write 6+length(brokenFmt) bytes to it...

For some reason I like snprintf()...

Mate, you fixed it, thank you! Your reply also gave me a lead to dig a bit deeper and I then noticed I had 4 x %02d where I should have had only 2, one for each of now.hour() and now.minute().

Code has been running solid on the Nano for over an hour so far. Thanks!!!!