char[] to SD.open resets the Arduino, pls help

hi

I'm trying to use the SD library to open different files from an SD card. If the file name is declared so:
myFile = SD.open("F2.txt", FILE_READ) it works

but if I use a char[] fileName array it resets the Arduino Uno:
myFile = SD.open(fileName, FILE_READ);
(myFIle is an instance of the File class).

I've tried everything I know but could not figure out why the Arduino keeps resetting, I only know that it happens when SD.open is invoked.
here is a working code:

void readFile(){
        
        Serial.println("opening file");
	myFile = SD.open("F2.txt", FILE_READ);
	if (myFile)
	{
		while (myFile.available()) {
			Serial.write(myFile.read());
		}
		myFile.close();
		Serial.println("myFile closed");
	} 
	else
	{
		Serial.println("ERROR opening file");
	}
}

and this keeps resetting the Atmega328p:

char fileName[30];

char label[30] = "";
label[0] = '\0';

strcat (label, "F2");
strcat (label, ".txt");
strcat (fileName, label);

Serial.print("fileName = ");
Serial.println(fileName); //this prints F2.txt in the serial monitor window, i.e. correct name

void readFile(){
        
        Serial.println("opening file"); //after this is printed in the serial monitor the Uno resets
	myFile = SD.open(fileName, FILE_READ);
	if (myFile)
	{
		while (myFile.available()) {
			Serial.write(myFile.read());
		}
		myFile.close();
		Serial.println("myFile closed");
	} 
	else
	{
		Serial.println("ERROR opening file");
	}

Thanks for any help!

It may be due to lack of RAM. Post the rest of your sketch.

You can also add this code in setup().

  Serial.println(FreeRam());
char fileName[30];

char label[30] = "";
label[0] = '\0';

strcat (label, "F2");
strcat (label, ".txt");
strcat (fileName, label);

Filename is never initialised and you are strcat'ing into it. You need to change that to strcpy() or better still

char fileName[30];

strcpy (fileName, "F2");
strcat (fileName, ".txt");

It may be due to lack of RAM. Post the rest of your sketch.
You can also add this code in setup().
Code:
Serial.println(FreeRam());

I tried that and a few times it did print values above 2000 and the UNO reset, but it also sometimes resets when the value is below 300.

I suspect that the problem might also have something to do with the serial buffer.

I could post the whole code but it's big and not tidy, so I'll post the part which makes the UNO hang or sometimes reset. By hang I mean it stops responding to key presses from PS2 keyboard but does not reset.

The scope of the code is to read incoming key presses from a PS2 keyboard and open the according text file, read a midi macro and send it over the Tx.
A midi macro is a set of midi messages that need to be sent fast one after another.

I organize the midi macros one per txt file. e.g.

seq_name.txt contains the following midi sequence:

76-12-12-12-12-12-12-12-12-9-9-9-9-9-11-11-11-11-77-11-113-

Each of these numbers is a midi note. The code uses the keyboard.read() function from the PS2Keyboard library, it reads one char at a time. When it gets to a '-' char it calculates the value of the note (previously read chars). Then the value of the midi note is transmitted over Tx by using the MIDI library MIDI.sendNoteOn() function.

Ok so by commenting out parts of my code I found the part that might be the problem:

I have this long list of switch cases, it sets the midi macro text file according to the incoming key from the PS2 keyboard.

This is the whole list, it crashes the Uno (if no parts are commented):

char macroName[30]; //stores the name of the macro, i.e. text file (global)

void loop()
{
	if (keyboard.available()){
		byte key = keyboard.read();		
		key2macro(key); //specifies the midi macro (macroName)
	}
}

void key2macro(byte keyName){

         char _macroName[30] = "";
	_macroName[0] = '\0';

	switch (keyName){
		case 'a': _macroName[0] = 'a'; break;
		case 'b': _macroName[0] = 'b'; break;
		case 'c': _macroName[0] = 'c'; break;
		case 'd': _macroName[0] = 'd'; break;
		case 'e': _macroName[0] = 'e'; break;
		case 'f': _macroName[0] = 'f'; break;
		case 'g': _macroName[0] = 'g'; break;
		case 'h': _macroName[0] = 'h'; break;
		case 'i': _macroName[0] = 'i'; break;
		case 'j': _macroName[0] = 'j'; break;
		case 'k': _macroName[0] = 'k'; break;
		case 'l': _macroName[0] = 'l'; break;
		case 'm': _macroName[0] = 'm'; break;
		case 'n': _macroName[0] = 'n'; break;
		case 'o': _macroName[0] = 'o'; break;
		case 'p': _macroName[0] = 'p'; break;
		case 'q': _macroName[0] = 'q'; break;
		case 'r': _macroName[0] = 'r'; break;
		case 's': _macroName[0] = 's'; break;
		case 't': _macroName[0] = 't'; break;
		case 'u': _macroName[0] = 'u'; break;
		case 'v': _macroName[0] = 'v'; break;
		case 'w': _macroName[0] = 'w'; break;
		case 'x': _macroName[0] = 'x'; break;
		case 'y': _macroName[0] = 'y'; break;
		case 'z': _macroName[0] = 'z'; break;
		//CAPS
		case 'A': strcpy (_macroName, "A_"); break;
		case 'B': strcpy (_macroName, "B_"); break;
		case 'C': strcpy (_macroName, "C_"); break;
		case 'D': strcpy (_macroName, "D_"); break;
		case 'E': strcpy (_macroName, "E_"); break;
		case 'F': strcpy (_macroName, "F_"); break;
		case 'G': strcpy (_macroName, "G_"); break;
		case 'H': strcpy (_macroName, "H_"); break;
		case 'I': strcpy (_macroName, "I_"); break;
		case 'J': strcpy (_macroName, "J_"); break;
		case 'K': strcpy (_macroName, "K_"); break;
		case 'L': strcpy (_macroName, "L_"); break;
		case 'M': strcpy (_macroName, "M_"); break;
		case 'N': strcpy (_macroName, "N_"); break;
		case 'O': strcpy (_macroName, "O_"); break;
		case 'P': strcpy (_macroName, "P_"); break;
		case 'Q': strcpy (_macroName, "Q_"); break;
		case 'R': strcpy (_macroName, "R_"); break;
		case 'S': strcpy (_macroName, "S_"); break;
		case 'T': strcpy (_macroName, "T_"); break;
		case 'U': strcpy (_macroName, "U_"); break;
		case 'V': strcpy (_macroName, "V_"); break;
		case 'W': strcpy (_macroName, "W_"); break;
		case 'X': strcpy (_macroName, "X_"); break;
		case 'Y': strcpy (_macroName, "Y_"); break;
		case 'Z': strcpy (_macroName, "Z_"); break;
		//Numeric
		case '0': strcpy (_macroName, "0"); break;
		case '1': strcpy (_macroName, "1"); break;
		case '2': strcpy (_macroName, "2"); break;
		case '3': strcpy (_macroName, "3"); break;
		case '4': strcpy (_macroName, "4"); break;
		case '5': strcpy (_macroName, "5"); break;
		case '6': strcpy (_macroName, "6"); break;
		case '7': strcpy (_macroName, "7"); break;
		case '8': strcpy (_macroName, "8"); break;
		case '9': strcpy (_macroName, "9"); break;
		//Special chars
		case '&': strcpy (_macroName, "&"); break;
		case '#': strcpy (_macroName, "#"); break;
		case '-': strcpy (_macroName, "-"); break;
		case '!': strcpy (_macroName, "!"); break;
		case '(': strcpy (_macroName, "("); break;
		case ')': strcpy (_macroName, ")"); break;
		case '_': strcpy (_macroName, "_"); break;
		//Function keys F1 - F12
		case 1: strcpy (_macroName, "seq_name"); break; //F1
		case 2: strcpy (_macroName, "tr_name"); break; //F2
		case 3: strcpy (_macroName, "prg_name"); break; //F3
		case 4: strcpy (_macroName, "sample_name"); break; //F4

If I comment some of the following lines then everything works ok, if not then I get a reset or it hangs. 

		case 5: strcpy (_macroName, "seq_double"); break; //F5
		case 6: strcpy (_macroName, "tr_duplicate_end"); break; //F6
		case 7: strcpy (_macroName, "del_first_bar"); break; //F7
		case 17: strcpy (_macroName, "del_last_bar"); break; //F8
		case 14: strcpy (_macroName, "tr_copy_next_replace"); break; //F9
		case 15: strcpy (_macroName, "seq_copy"); break; //F10
		case 16: strcpy (_macroName, "F11"); break; //F11
		case 12: strcpy (_macroName, "F12"); break; //F12
		
		case 32: strcpy (_macroName, "space"); break;//inserts underscore
		case 127: strcpy (_macroName, "del"); break; //[canc] delete
		case 8: strcpy (_macroName, "b_del"); break; //back space delete
		case 27: strcpy (_macroName, "esc"); break; //escape - MAIN screen
		
		case 42: strcpy (_macroName, "F1"); break; //[?]
		case 61: strcpy (_macroName, "F2"); break; //[^]
		case 91: strcpy (_macroName, "F3"); break; //[é]
		case 93: strcpy (_macroName, "F4"); break; //[*]
		case 46: strcpy (_macroName, "MIDI"); break; //[.]
		case 44: strcpy (_macroName, "BPM"); break; //[,]
	}

	strcat (_macroName, ".txt");
	strcpy (macroName, _macroName);
	_macroName[0] = '\0';
}

continued in next post:

So I also supsect that this might have something to do with the serial buffer.

E.g. this macro

76-12-12-12-12-12-12-12-12-9-9-9-9-9-11-11-11-11-77-11-113-

is 21 midi notes long. Each note is composed of two midi messages, Midi Note On and Midi Note off, each of them is composed of 3 bytes that specify (type of midi message and midi channel, note number, velocity). So we have a macro length of 21x2x3 = 126 bytes long.

This the code for the sending function:

midi_macro_delay = 10ms

void sendMidiMsg(unsigned int _numba){
	
	if (_numba < 1000) //smaller than 1000 = midi note
	{
		MIDI.sendNoteOn(_numba, 127, midiCh);
		delay(midi_macro_delay);
		MIDI.sendNoteOff(_numba, 0, midiCh);
		delay(midi_macro_delay);
	}
	else if (_numba >= 1000) // means Control Change message
	{
		_numba = _numba - 1000;
		MIDI.sendControlChange(_numba, 127, midiCh);
		delay(midi_macro_delay);
	}
	
}