Optimize read speed?

Hello, my program has a self-test function to check a SD-Card for Bit-Flips. This function checks the Data in a file "big_file.txt", which contains 1GB of Data (filled with letter 'A'). Also i want to log few events into internal EEPROM, such as: e0 (Start test), e2 (test corrupt), e4 (test complete).
I want to optimize my function, so I can read from the file as fast as possible. When i comment out the "logMsg" calls in "testMemory" i need approx. 1hour for reading the file. When i have "logMsg" calls in "testMemory" it takes about 5hours. Can anyone find the twist in my code? Or anyone have other tips?

main program:

#include "eprom.h"
#include "safety.h"
#include "eventCodes.h"

#define BAUD 9600

const int chipSelect = 10;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(BAUD);

  Serial.println(F("Initializing SD card..."));
  if (!sd.begin(chipSelect)) {
    Serial.println(F("SD Card error"));
    return;
  }
  Serial.println(F("card initialized"));    //INITIALIZE SD CARD
  
  delay(3000);
}

void loop() {
  if (millis() > 15000 + deStart1) {
    deStart1 = 10800000;   //millis();
    testMemory ();
  }

  //Ausgabe der LogFile
  if (Serial.available()) {
    char ch = Serial.read();
    int idx = 0;
    switch (ch) {
      case 'x':                         //Warte auf Eingabe
        while (EEPROM[idx] != 0xFF) {    //LOG_LENGTH
          Serial.print (EEPROM[idx]);         //Stunde
          Serial.print (":");
          idx++;
          Serial.print (EEPROM[idx]);         //Minute
          Serial.print (":");
          idx++;
          Serial.print (EEPROM[idx]);         //Sekunde
          idx++;
          Serial.print ("  ");
          Serial.println (EEPROM[idx], HEX);  //EventCode
          idx++;

        } break;
      case 'y':
        readEEPROM();
        break;
      default: Serial.println(F("Ungueltiges Kommando"));
    }
  }
}

safety.h:

#ifndef SAFETY_H
#define SAFETY_H
#include "eventCodes.h"
#include <Time.h>
#include <TimeLib.h>
#include <SPI.h>
#include <SdFat.h>

unsigned int addr = 0;       //REFERENZ EEPROM ADRESSE
unsigned long deStart1 = 0;  //INTERVALL ZEIT
SdFat sd;
SdFile myFile;

byte arr[512];               //DATENBLOCK
uint32_t blockcnt = 0;   //ANZAHL GETESTETER BLOECKE

uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
  uint16_t crc = 0;
  for (size_t i = 0; i < n; i++) {
    crc = (uint8_t)(crc >> 8) | (crc << 8);
    crc ^= data[i];
    crc ^= (uint8_t)(crc & 0xff) >> 4;
    crc ^= crc << 12;
    crc ^= (crc & 0xff) << 5;
  }
  return crc;
}

void logMsg(int EventCode) {
  if (EEPROM[addr] == 0xFF) {
    EEPROM.write (addr, hour());
    addr++;
    EEPROM.write (addr, minute());
    addr++;
    EEPROM.write (addr, second());
    addr++;
    EEPROM.write (addr, EventCode);
    addr++;
  }
  else {
    while (EEPROM[addr] != 0xFF) {
      addr++;
    }
    EEPROM.write (addr, hour());
    addr++;
    EEPROM.write (addr, minute());
    addr++;
    EEPROM.write (addr, second());
    addr++;
    EEPROM.write (addr, EventCode);
    addr++;
  }
}

void testMemory () {     //LISTENEINTRAEGE ÜBER AUFGETRETENE BITFEHLER
  //Speicher-Selbstabbild: DATEN vs. CRC
  //STARTE TEST
  logMsg(e0);
  Serial.println(F("Test gestartet"));
  uint16_t crc_a = 0;
  //uint16_t crc_ini = 0xBF75;
  Serial.println(millis());
  myFile.open("big_file.txt", O_READ); //FILE_READ

  if (myFile) {
    while (myFile.available()) {
      int n = myFile.read(arr, sizeof(arr));
      for (int i = 0; i < n; i++) {
        if (i % 512 == 0 ) {
          blockcnt++;
          crc_a = CRC_CCITT (arr, 512);
          //Serial.println(crc_a, HEX);
          if (crc_a != 0xBF75) {
            logMsg(e2);
          }
          i = 0;
        }
      }
    }
    myFile.close();
  }
  Serial.println(blockcnt);       // ANZAHL GETESTETER 512 BYTE BLOECKE
  Serial.println(millis());
  Serial.println(F("Test beendet"));
  logMsg(e4);
}
#endif

Seriously?

Sorry im still a Noob, I dont want to use Serial anyway, i later will edit the code to get the Arduino work without Serial connection

what's the purpose of that (badly written) test?

For checking purpose i want to start the test after 15sec (later on it should be called every 5 hours).

just put a delay(15000); at the end of the setup()

I see your point. But I want the program later on to work for 2 weeks and the function "testMemory" should be called every 5 hours. I hope I dont sound too stupid lol

no fine.

post the whole code though...

thats the whole code actually.. i dont use eprom.h anyway and eventCode.h just defines e0 (Start test), e2 (test corrupt), e4 (test completed)

EEPROM erasing and writing is desperately slow - check the datasheet.

    while (myFile.available())
    {
      int n = myFile.read(arr, sizeof(arr));
      for (int i = 0; i < n; i++)
      {
        if (i % 512 == 0 )
        {
          blockcnt++;
          crc_a = CRC_CCITT (arr, 512);
          //Serial.println(crc_a, HEX);
          if (crc_a != 0xBF75)
          {
            logMsg(e2);
          }
          i = 0;
        }
      }
    }
    myFile.close();

Do you just comment out the one line logMsg(e2); and it takes 1/5th the time or are the differences more extensive?

Since you know that every byte contains 'A' you could test for that and save the trouble of calculating the same CRC two million times.

Commenting out logMsg(e2) makes the reading way faster. I wonder why though, because the if-statement hasnt been true yet.

I could leave out for CRC-checking yes, but for learning process I want to have that implemented (Later on I want to check files with random Data). I was thinking about to save e2 in a variable, and call logMsg(variable) later on when the file is closed?

@noobquestions
and to be fair I don't get what is done in that for loop.
you have your array defined as byte arr[512];
so you ask to read 512 bytes from the file.
n will be either 512 if you there were still enough bytes to read, or some amount les than 512 if there was not 512 bytes left.

so what's the blockcnt idea, the modulo etc ? why is the index modified within the loop?

you could just count the number of bytes that are not 'A'

myFile.open("big_file.txt", O_READ); //FILE_READ
size_t errorCount = 0;
while (myFile.available()) {
  size_t n = myFile.read(arr, sizeof(arr));
  for (size_t i = 0; i < n; i++)   {
    if (arr[i] != 'A') errorCount++;
  }
}

My guess: The compiler sees that the 'if' doesn't do anything so it optimizes it away. Since the only use for the 'crc_a' is now gone, and it somehow knows that the CRC_CCITT() function doesn't have any side-effects, it optimizes that function call away, thus saving 2 million CRC calculations.

if that is the case, then making 'crc_a' volatile should solve this problem, right?

'blockcnt' was for checking purpose, to be sure that all blocks were read in that file.

myFile.open("big_file.txt", O_READ); //FILE_READ
size_t errorCount = 0;
while (myFile.available()) {
  size_t n = myFile.read(arr, sizeof(arr));
  for (size_t i = 0; i < n; i++)   {
    if (arr[i] != 'A') errorCount++;
  }
}

but checking every byte is again slowly?

if (arr[i] != 'A') errorCount++;

what do you think CRC_CCITT() is doing?

If the problem is that it only takes 1 hour instead of five.

good point, I am so fixed with testMemory() and logMsg(), that i forgot about it. I will try out your suggestion, thank you

thank you, i hope ill get this work