user76726: I'm building a final project for a class that involves playing an audio file of a wave shield every time I scan an amiibo with an RFID scanner. I'm a pretty new programmer, so I'm not very familiar with the how to best reduce DRAM usage. As such, I got the following error when I attempted to run my most recent iteration of code:

Global variables use 2801 bytes (136%) of dynamic memory, leaving -753 bytes for local variables. Maximum is 2048 bytes.

Here is my code:
////// WAVE SHIELD HEADERS //////
#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"
/////////////////////////////////

/////// LCD HEADERS /////////////
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

//////////////////////////////////////////

////////// RFID HEADERS /////////////////
#include <SPI.h>
#include <Adafruit_PN532.h>

#define PN532_IRQ   (6)
#define PN532_RESET (3)  // Not connected by default on the NFC Shield

Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);

/////// various declarations /////////
uint8_t GLOBALUID[7];


//////////////////////////// WAVE SHIELD PORTION OF CODE ///////////////////////////////////


SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

#define DEBOUNCE 100  // button debouncer

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  }
  return free_memory; 
} 

void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  putstring("\n\rSD I/O error: ");
  Serial.print(card.errorCode(), HEX);
  putstring(", ");
  Serial.println(card.errorData(), HEX);
  while(1);
}

/////// MAIN SETUP /////////

void setup() {
  // set up serial port
  Serial.begin(115200);
  
  // Set the output pins for the DAC control in the wave shield.
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  // Set button outputs
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  
  // Set random seed for picking amiibo
  randomSeed(analogRead(A2));

  // initialize lcd
  lcd.init();
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  
   if (!card.init()) {
    putstring_nl("Card init. failed!");
    sdErrorCheck();
    while(1);
  }
  
  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);
 
// look for a FAT partition
  uint8_t part;
  for (part = 0; part < 5; part++) {
    if (vol.init(card, part)) 
      break;
  }
  if (part == 5) {
    putstring_nl("No valid FAT partition!");
    sdErrorCheck();
    while(1);
  }
  
  // tell the user about what was found
  putstring("Using partition ");
  Serial.print(part, DEC);
  putstring(", type is FAT");
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?
  
  // Try to open the root directory
  if (!root.openRoot(vol)) {
    putstring_nl("Can't open root dir!");
    while(1);
  }
}
//////////// END OF WAVE SHIELD ///////////////


////////////// FUNCTION FOR SELECTING AUDIO FILES ////////////
void playSoundClip(){

  char charUID[7];

  for(int i = 0; i < 7; i++)
    charUID[i] = GLOBALUID[i];

  Serial.println();

/*
      {"Mario",                   { 4, 79, 119, 42, 55, 60, 128 },"MARIO"},     //0
      {"Meta Knight",             { 4, 243, 209, 58, 117, 76, 128},"MK"},       //1
      {"Inkling",                 { 4, 84, 47, 218, 87, 73, 128 },"INK"},       //2
      {"Donkey Kong",             { 4, 244, 122, 98, 249, 61, 128 },"DK"},      //3
      {"Lucas",                   { 4, 7, 52, 202, 178, 73, 129 },"LUCAS"},     //4
      {"Duck Hunt",               { 4, 40, 173, 146, 84, 73, 128 },"DUCKH"},    //5
      {"Ocarina of Time Link",    { 4 163 57 114 221 76 128 },"OOTL"},          //6
      {"Breath of The Wild Link", ( 4 133 61 74 120 76 128 },"BOTWL"},          //7
      {"8-bit Link",              { 4 192 150 130 221 76 128 },"8BITL"},        //8
      {"Toon Link",               { 4, 89, 88, 226, 161, 62, 128 },"TOONL"},    //9      
      {"Mr. Game and Watch",      { 4, 134, 32, 154, 85, 73, 128 },"GANDW"},    //10
      {"Falco",                   { 4, 23, 139, 178, 17, 74, 129 },"FALCO"},    //11
      {"King Dedede",             { 4, 108, 188, 242, 232, 73, 128 },"DEDEDE"}, //12
      {"Mewtwo",                  { 4, 241, 126, 202, 87, 73, 128 },"MEWTWO"},  //13
      {"Captain Falcon",          { 4, 11, 204, 178, 124, 72, 129 },"CAPF"},    //14
      {"ROB",                     { 4, 40, 208, 50, 3, 73, 128 },"ROB"},        //15
      {"PAC-MAN",                 { 4, 45, 26, 2, 114, 64, 129 },"PACMAN"},     //16
      {"Cloud",                   { 4, 107, 128, 26, 114, 64, 128 },"CLOUD"},   //17
      {"Ness",                    { 4, 107, 128, 26, 114, 64, 128 },"NESS"},    //18
      {"Ryu",                     { 4, 109, 252, 234, 33, 75, 128 },"RYU"}      //19
*/

  uint8_t amiiboNo = 0;
  
  if(strcmp(charUID,"479119425560128"))
    amiiboNo = 0; //Mario
  else if(strcmp(charUID,"42432095811776128"))
    amiiboNo = 1; //Meta Knight
  else if(strcmp(charUID,"484472188773128"))
    amiiboNo = 2; //Inkling
  else if(strcmp(charUID,"42441229824961128"))
    amiiboNo = 3;// Donkey Kong
  else if(strcmp(charUID,"475220217873129"))
    amiiboNo = 4;// Lucas
  else if(strcmp(charUID,"4401731468473128"))
    amiiboNo = 5;// Duck Hunt
  else if(strcmp(charUID,"41635711422176128"))
    amiiboNo = 6;// Ocarina of Time Link
  else if(strcmp(charUID,"4133617412076128"))
    amiiboNo = 7;// Breath of The Wild Link
  else if(strcmp(charUID,"419215013022176128"))
    amiiboNo = 8;// 8-bit link
  else if(strcmp(charUID,"4898822616162128"))
    amiiboNo = 9;// toon link
  else if(strcmp(charUID,"4134321548573128"))
    amiiboNo = 10;// Mr. Game and Watch
  else if(strcmp(charUID,"4231391781774129"))
    amiiboNo = 11;// Falco
  else if(strcmp(charUID,"410818824223273128"))
    amiiboNo = 12;// king dedede
  else if(strcmp(charUID,"42411262028773128"))
    amiiboNo = 13;// Mewtwo
  else if(strcmp(charUID,"41120417812472129"))
    amiiboNo = 14;// Captain Falcon
  else if(strcmp(charUID,"44020850373128"))
    amiiboNo = 15;// ROB
  else if(strcmp(charUID,"44526211464129"))
    amiiboNo = 16;// Pacman
  else if(strcmp(charUID,"424913721823376128"))
    amiiboNo = 17;// Cloud
  else if(strcmp(charUID,"41071282611464128"))
    amiiboNo = 18;// Ness
  else if(strcmp(charUID,"41092522343375128"))
    amiiboNo = 19;// Ryu

  Serial.println(amiiboNo);
  
  uint8_t clipNo = random(3);
  
  switch(amiiboNo){
    case 0:
      if(clipNo == 0)
        playComplete("MARIO01.WAV");
      else if(clipNo == 1)
        playComplete("MARIO02.WAV");
      else if(clipNo == 2)
        playComplete("MARIO03.WAV");
      break;
    case 1:
      if(clipNo == 0)
        playComplete("MK01.WAV");
      else if(clipNo == 1)
        playComplete("MK02.WAV");
      else if(clipNo == 2)
        playComplete("MK03.WAV");
      break;
    case 2:
      if(clipNo == 0)
        playComplete("INK01.WAV");
      else if(clipNo == 1)
        playComplete("INK02.WAV");
      else if(clipNo == 2)
        playComplete("INK03.WAV");
       break;
    case 3:
      if(clipNo == 0)
        playComplete("DK01.WAV");
      else if(clipNo == 1)
        playComplete("DK02.WAV");
      else if(clipNo == 2)
        playComplete("DK03.WAV");
       break;
    case 4:
      if(clipNo == 0)
        playComplete("LUCAS01.WAV");
      else if(clipNo == 1)
        playComplete("LUCAS02.WAV");
      else if(clipNo == 2)
        playComplete("LUCAS03.WAV");
       break;
    case 5:
      if(clipNo == 0)
        playComplete("DUCKH01.WAV");
      else if(clipNo == 1)
        playComplete("DUCKH02.WAV");
      else if(clipNo == 2)
        playComplete("DUCKH03.WAV");
       break;
    case 6:
      if(clipNo == 0)
        playComplete("OOT01.WAV");
      else if(clipNo == 1)
        playComplete("OOT02.WAV");
      else if(clipNo == 2)
        playComplete("OOT03.WAV");
       break;
    case 7:
      if(clipNo == 0)
        playComplete("BOTWL01.WAV");
      else if(clipNo == 1)
        playComplete("BOTWL02.WAV");
      else if(clipNo == 2)
        playComplete("BOTWL03.WAV");
       break;
    case 8:
      if(clipNo == 0)
        playComplete("8BITL01.WAV");
      else if(clipNo == 1)
        playComplete("8BITL02.WAV");
      else if(clipNo == 2)
        playComplete("8BITL03.WAV");
       break;
    case 9:
      if(clipNo == 0)
        playComplete("TOONL01.WAV");
      else if(clipNo == 1)
        playComplete("TOONL02.WAV");
      else if(clipNo == 2)
        playComplete("TOONL03.WAV");
       break;
    case 10:
      if(clipNo == 0)
        playComplete("GANDW01.WAV");
      else if(clipNo == 1)
        playComplete("GANDW02.WAV");
      else if(clipNo == 2)
        playComplete("GANDW03.WAV");
       break;
    case 11:
      if(clipNo == 0)
        playComplete("FALCO01.WAV");
      else if(clipNo == 1)
        playComplete("FALCO02.WAV");
      else if(clipNo == 2)
        playComplete("FALCO03.WAV");
       break;
    case 12:
      if(clipNo == 0)
        playComplete("DEDEDE01.WAV");
      else if(clipNo == 1)
        playComplete("DEDEDE02.WAV");
      else if(clipNo == 2)
        playComplete("DEDEDE03.WAV");
       break;
    case 13:
      if(clipNo == 0)
        playComplete("MEWTWO01.WAV");
      else if(clipNo == 1)
        playComplete("MEWTWO02.WAV");
      else if(clipNo == 2)
        playComplete("MEWTWO03.WAV");
       break;
    case 14:
      if(clipNo == 0)
        playComplete("CAPF01.WAV");
      else if(clipNo == 1)
        playComplete("CAPF02.WAV");
      else if(clipNo == 2)
        playComplete("CAPF03.WAV");
       break;
    case 15:
      if(clipNo == 0)
        playComplete("ROB01.WAV");
      else if(clipNo == 1)
        playComplete("ROB02.WAV");
      else if(clipNo == 2)
        playComplete("ROB03.WAV");
       break;
    case 16:
      if(clipNo == 0)
        playComplete("PACMAN01.WAV");
      else if(clipNo == 1)
        playComplete("PACMAN02.WAV");
      else if(clipNo == 2)
        playComplete("PACMAN03.WAV");
       break;
    case 17:
      if(clipNo == 0)
        playComplete("CLOUD01.WAV");
      else if(clipNo == 1)
        playComplete("CLOUD02.WAV");
      else if(clipNo == 2)
        playComplete("CLOUD03.WAV");
       break;
    case 18:
      if(clipNo == 0)
        playComplete("NESS01.WAV");
      else if(clipNo == 1)
        playComplete("NESS02.WAV");
      else if(clipNo == 2)
        playComplete("NESS03.WAV");
       break;
    case 19:
      if(clipNo == 0)
        playComplete("RYU01.WAV");
      else if(clipNo == 1)
        playComplete("RYU02.WAV");
      else if(clipNo == 2)
        playComplete("RYU03.WAV");
       break;
       
    }
}

//////// MAIN LOOP /////////
void loop() {

      lcd.print("Scan an");
      lcd.setCursor(0,1);
      lcd.print("amiibo!");
      delay(3000);
    
    uint8_t * ID{};
        
    waitForRFID();
    
    playSoundClip();
    
  
}


//////////////// MORE WAVE SHIELD ///////////////////////

// Plays a full file from beginning to end with no pause.
void playComplete(char *name) {
  // call our helper to find and play this name
  playfile(name);
  while (wave.isplaying) {
  // do nothing while its playing
  }
  // now its done playing
}

void playfile(char *name) {
  // see if the wave object is currently doing something
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }
  // look in the root directory and open the file
  if (!f.open(root, name)) {
    putstring("Couldn't open file "); Serial.println(name); return;
  }
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) {
    putstring_nl("Not a valid WAV"); return;
  }
  
  // ok time to play! start playback
  wave.play();
}

/////////////// END OF WAVE SHIELD //////////////////////

//////////////// RFID FUNCTION /////////////////////////
uint8_t* waitForRFID(){
    nfc.SAMConfig();
  
  Serial.println("Waiting for an amiibo ...");

  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  uint8_t uidLength;
  uint8_t testuid[7];
  while(true){
    if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)){

      Serial.print("Hex UID: ");
      nfc.PrintHex(uid, uidLength);
      Serial.print("Octal UID: { ");
      for(int i = 0; i < uidLength; i++){
        Serial.print(uid[i]);
        GLOBALUID[i] = uid[i];
        if (i != uidLength - 1)
          Serial.print(", ");
      }
      Serial.println(" }");

      Serial.print("GLOBALUID: ");
      for(int i = 0; i < 7; i++)
        Serial.print(GLOBALUID[i]);
        
      Serial.println();
      Serial.println();
    }
    return testuid;
  }
  
}

//////////////// END OF RFID FUNCTION /////////////////

My first guess for what may be taking up the most memory is the switch statement. When I uncomment that, the memory usage jumps from 90% to over 130%. I've tried other ways to get this code to work, like concatenating text, but this is the only way that seemed to work reliably, until I ran out of memory.
I'm also using a lot of libraries to help use the shields and LCD I have attached to the Uno. I couldn't get rid of those libraries without compromising the project.
Other than that, I don't know what to do. If anyone has any suggestions for condensing the code down, I'd really appreciate any advice you have to offer.
Thanks.

user14095: Just a SWAG try switching from a UNO to a MEGA the code should work once the decelerations are fixed. What the compiler is not telling you is how much memory is actually used. You have the Heap and Stack etc.

user773: As a minor addendum to Edgar Bonet's excellent answer, you could simplify your code further and save even more memory by renaming your files.
In particular, instead of storing a list of character names indexed by Amiibo number and using those as the filename prefix, why not use the Amiibo numbers directly?  That is, instead of your files being named

MARIO01.WAV, MARIO02.WAV, MARIO03.WAV, MK01.WAV, MK02.WAV, MK02.WAV, etc.

you could just name them e.g.

AMI01_01.WAV, AMI01_02.WAV, AMI01_03.WAV, AMI02_01.WAV, AMI02_02.WAV, AMI02_03.WAV, etc.

and construct the name in your code e.g. like this:
char filename[13];
int len = snprintf(filename, sizeof(filename), "AMI%02d_%02d.WAV", amiiboNo + 1, clipNo + 1);
if (len < 0 || len >= sizeof(filename)) {
  // TODO: handle error or insufficient buffer size here
}

The main advantage here is that you'll save memory by not having to store the list of character names.  The tradeoff, of course, is that your filenames will now be a lot less descriptive.
You could probably optimize this a bit more by manipulating the bytes of the filename directly like Edgar does.  But personally I'd suggest starting with the generic snprintf based solution and only switching to direct byte manipulation if it's still too much. At least I'd assume that the snprintf implementation in the standard library is probably going to be fairly well optimized for a low footprint.  Of course I could be wrong.

user7508: You have a huge switch...case here to decide the name of the file that
should be played. This costs a lot of code space, but also data space,
because every single literal string in this portion of code gets copied
to RAM during initialization.
There is no need to spend all this cost, as the file names have been
assigned in a very regular fashion, so you can build the file name
algorithmically. As a general rule, whenever you find yourself
programming by copying, pasting, then applying some predictable
modifications to the copies, you are almost certainly doing something
wrong. Making repeated copies of the same thing, with predictable
changes is what computers are best for. So you have to ask yourself how
you can instruct the computer (in this case, the Arduino) to do that for
you. Do not do the computer's job yourself!
In this case, the file name is built by gluing three pieces together:

a prefix that depends on amiiboNo
a two-digit number between "01" and "03", depending on clipNo
the constant suffix ".WAV"

The prefix cannot be computed algorithmically, so you still have to
write down all the possible prefixes. You could use a big
switch...case for this, but it is way more convenient to pick the
right prefix from an array indexed by amiiboNo:
const char *file_prefixes[] = {
    "MARIO", "MK",    "INK",    "DK",    "LUCAS", "DUCKH",  "OOT",
    "BOTWL", "8BITL", "TOONL",  "GANDW", "FALCO", "DEDEDE", "MEWTWO",
    "CAPF",  "ROB",   "PACMAN", "CLOUD", "NESS",  "RYU"
};

Then, you declare an array of char for holding the file name, and you
build that file name by putting together the three pieces listed above.
Your whole switch...case can then be replaced by this:
char filename[13];           // longest file name: 12 characters + NUL
char file_number[3] = "01";  // 2 digits + NUL
file_number[1] += clipNo;    // file_number: "01", "02" or "O3"
strcpy(filename, file_prefixes[amiiboNo]);
strcat(filename, file_number);
strcat(filename, ".WAV");
playComplete(filename);

This will already save you a lot of RAM, but probably not enough. I did
not see any obvious inefficient use of variables in your program (but I
did not look in too much detail), so we will continue to aim at literal
strings.
The problem with literal strings is the fact that they get copied from
flash to RAM during initialization, and whereas you probably have enough
flash, the RAM is in short supply. This is a problem specific to Harvard
architectures, as they have separate address spaces for code and data.
We can use some AVR-specific tricks to instruct the compiler not to
perform this copying. This makes it harder to access the data because
C++ does not natively know about address spaces. Fortunately, there are
some macros and helper functions that can make it easy in specific
cases.
The best know such helper in Arduino world is the F() macro. Use it
every time you print() or println() a literal string, as in:
Serial.println(F("Waiting for an amiibo ..."));

Next, we have to get rid of the very long list of numeric UIDs. For
this, we use the PSTR() macro and strcmp_P() function provided by
the avr-libc. Replace every line that looks like
if (strcmp(charUID, "479119425560128"))

by something like
if (strcmp_P(charUID, PSTR("479119425560128")) == 0)

Note that the value returned by strcmp_P() has to be compared to 0, as
this is what that function, just like strcmp(), returns in case of
equality. Thanks to timemage for noticing this issue.
Last, we could also keep all the file prefixes in flash, but this would
be trickier. For now, I suggest you apply the tricks described here and
see whether they are enough to make your program fit.
Edit: more on the somewhat obscure statement:
file_number[1] += clipNo;
In C++, a char is an 8-bit number. Depending on the platform, it can
be either signed (range: −128…+127) or unsigned (0…255). The name comes
from the fact that it is most often used to store the numeric value of an
ASCII character. For example, the numeric value 33 means '!', 48 means
'0', and 65 means 'A'.
The definition
char file_number[3] = "01";

creates a 3-cell array initialized with the following content:
             ┌─────┬─────┬─────┐
file_number: │  48 │  49 │   0 │
             └─────┴─────┴─────┘

Using the language notation for characters, the contents could also be
written as follows:
             ┌─────┬─────┬─────┐
file_number: │ '0' │ '1' │ '\0'│
             └─────┴─────┴─────┘

The last cell with the ASCII NUL is there to inform library functions
such as strcat() that this is where the string of characters ends.
The statement
file_number[1] += clipNo;

accesses the second element of the array (array indexing starts at 0)
and increments its numeric value by the amount of clipNo. For example,
if clipNo is 1, then the value in the middle cell will be changed
from 49 (i.e. '1') to 50 (i.e. '2'). This relies on the fact that
ASCII digits have consecutive numeric values, which would also be
expected from any sane character encoding.

76726: <p>I'm building a final project for a class that involves playing an audio file of a wave shield every time I scan an amiibo with an RFID scanner. I'm a pretty new programmer, so I'm not very familiar with the how to best reduce DRAM usage. As such, I got the following error when I attempted to run my most recent iteration of code:</p>
<blockquote>
<p>Global variables use 2801 bytes (136%) of dynamic memory, leaving -753 bytes for local variables. Maximum is 2048 bytes.</p>
</blockquote>
<p>Here is my code:</p>
<pre><code>////// WAVE SHIELD HEADERS //////
#include &lt;FatReader.h&gt;
#include &lt;SdReader.h&gt;
#include &lt;avr/pgmspace.h&gt;
#include &quot;WaveUtil.h&quot;
#include &quot;WaveHC.h&quot;
/////////////////////////////////

/////// LCD HEADERS /////////////
#include &lt;Wire.h&gt; 
#include &lt;LiquidCrystal_I2C.h&gt;
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

//////////////////////////////////////////

////////// RFID HEADERS /////////////////
#include &lt;SPI.h&gt;
#include &lt;Adafruit_PN532.h&gt;

#define PN532_IRQ   (6)
#define PN532_RESET (3)  // Not connected by default on the NFC Shield

Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);

/////// various declarations /////////
uint8_t GLOBALUID[7];


//////////////////////////// WAVE SHIELD PORTION OF CODE ///////////////////////////////////


SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play

WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

#define DEBOUNCE 100  // button debouncer

// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&amp;free_memory) - ((int)&amp;__bss_end); 
  }
  else {
    free_memory = ((int)&amp;free_memory) - ((int)__brkval); 
  }
  return free_memory; 
} 

void sdErrorCheck(void)
{
  if (!card.errorCode()) return;
  putstring(&quot;\n\rSD I/O error: &quot;);
  Serial.print(card.errorCode(), HEX);
  putstring(&quot;, &quot;);
  Serial.println(card.errorData(), HEX);
  while(1);
}

/////// MAIN SETUP /////////

void setup() {
  // set up serial port
  Serial.begin(115200);
  
  // Set the output pins for the DAC control in the wave shield.
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  // Set button outputs
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  
  // Set random seed for picking amiibo
  randomSeed(analogRead(A2));

  // initialize lcd
  lcd.init();
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  
   if (!card.init()) {
    putstring_nl(&quot;Card init. failed!&quot;);
    sdErrorCheck();
    while(1);
  }
  
  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);
 
// look for a FAT partition
  uint8_t part;
  for (part = 0; part &lt; 5; part++) {
    if (vol.init(card, part)) 
      break;
  }
  if (part == 5) {
    putstring_nl(&quot;No valid FAT partition!&quot;);
    sdErrorCheck();
    while(1);
  }
  
  // tell the user about what was found
  putstring(&quot;Using partition &quot;);
  Serial.print(part, DEC);
  putstring(&quot;, type is FAT&quot;);
  Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?
  
  // Try to open the root directory
  if (!root.openRoot(vol)) {
    putstring_nl(&quot;Can't open root dir!&quot;);
    while(1);
  }
}
//////////// END OF WAVE SHIELD ///////////////


////////////// FUNCTION FOR SELECTING AUDIO FILES ////////////
void playSoundClip(){

  char charUID[7];

  for(int i = 0; i &lt; 7; i++)
    charUID[i] = GLOBALUID[i];

  Serial.println();

/*
      {&quot;Mario&quot;,                   { 4, 79, 119, 42, 55, 60, 128 },&quot;MARIO&quot;},     //0
      {&quot;Meta Knight&quot;,             { 4, 243, 209, 58, 117, 76, 128},&quot;MK&quot;},       //1
      {&quot;Inkling&quot;,                 { 4, 84, 47, 218, 87, 73, 128 },&quot;INK&quot;},       //2
      {&quot;Donkey Kong&quot;,             { 4, 244, 122, 98, 249, 61, 128 },&quot;DK&quot;},      //3
      {&quot;Lucas&quot;,                   { 4, 7, 52, 202, 178, 73, 129 },&quot;LUCAS&quot;},     //4
      {&quot;Duck Hunt&quot;,               { 4, 40, 173, 146, 84, 73, 128 },&quot;DUCKH&quot;},    //5
      {&quot;Ocarina of Time Link&quot;,    { 4 163 57 114 221 76 128 },&quot;OOTL&quot;},          //6
      {&quot;Breath of The Wild Link&quot;, ( 4 133 61 74 120 76 128 },&quot;BOTWL&quot;},          //7
      {&quot;8-bit Link&quot;,              { 4 192 150 130 221 76 128 },&quot;8BITL&quot;},        //8
      {&quot;Toon Link&quot;,               { 4, 89, 88, 226, 161, 62, 128 },&quot;TOONL&quot;},    //9      
      {&quot;Mr. Game and Watch&quot;,      { 4, 134, 32, 154, 85, 73, 128 },&quot;GANDW&quot;},    //10
      {&quot;Falco&quot;,                   { 4, 23, 139, 178, 17, 74, 129 },&quot;FALCO&quot;},    //11
      {&quot;King Dedede&quot;,             { 4, 108, 188, 242, 232, 73, 128 },&quot;DEDEDE&quot;}, //12
      {&quot;Mewtwo&quot;,                  { 4, 241, 126, 202, 87, 73, 128 },&quot;MEWTWO&quot;},  //13
      {&quot;Captain Falcon&quot;,          { 4, 11, 204, 178, 124, 72, 129 },&quot;CAPF&quot;},    //14
      {&quot;ROB&quot;,                     { 4, 40, 208, 50, 3, 73, 128 },&quot;ROB&quot;},        //15
      {&quot;PAC-MAN&quot;,                 { 4, 45, 26, 2, 114, 64, 129 },&quot;PACMAN&quot;},     //16
      {&quot;Cloud&quot;,                   { 4, 107, 128, 26, 114, 64, 128 },&quot;CLOUD&quot;},   //17
      {&quot;Ness&quot;,                    { 4, 107, 128, 26, 114, 64, 128 },&quot;NESS&quot;},    //18
      {&quot;Ryu&quot;,                     { 4, 109, 252, 234, 33, 75, 128 },&quot;RYU&quot;}      //19
*/

  uint8_t amiiboNo = 0;
  
  if(strcmp(charUID,&quot;479119425560128&quot;))
    amiiboNo = 0; //Mario
  else if(strcmp(charUID,&quot;42432095811776128&quot;))
    amiiboNo = 1; //Meta Knight
  else if(strcmp(charUID,&quot;484472188773128&quot;))
    amiiboNo = 2; //Inkling
  else if(strcmp(charUID,&quot;42441229824961128&quot;))
    amiiboNo = 3;// Donkey Kong
  else if(strcmp(charUID,&quot;475220217873129&quot;))
    amiiboNo = 4;// Lucas
  else if(strcmp(charUID,&quot;4401731468473128&quot;))
    amiiboNo = 5;// Duck Hunt
  else if(strcmp(charUID,&quot;41635711422176128&quot;))
    amiiboNo = 6;// Ocarina of Time Link
  else if(strcmp(charUID,&quot;4133617412076128&quot;))
    amiiboNo = 7;// Breath of The Wild Link
  else if(strcmp(charUID,&quot;419215013022176128&quot;))
    amiiboNo = 8;// 8-bit link
  else if(strcmp(charUID,&quot;4898822616162128&quot;))
    amiiboNo = 9;// toon link
  else if(strcmp(charUID,&quot;4134321548573128&quot;))
    amiiboNo = 10;// Mr. Game and Watch
  else if(strcmp(charUID,&quot;4231391781774129&quot;))
    amiiboNo = 11;// Falco
  else if(strcmp(charUID,&quot;410818824223273128&quot;))
    amiiboNo = 12;// king dedede
  else if(strcmp(charUID,&quot;42411262028773128&quot;))
    amiiboNo = 13;// Mewtwo
  else if(strcmp(charUID,&quot;41120417812472129&quot;))
    amiiboNo = 14;// Captain Falcon
  else if(strcmp(charUID,&quot;44020850373128&quot;))
    amiiboNo = 15;// ROB
  else if(strcmp(charUID,&quot;44526211464129&quot;))
    amiiboNo = 16;// Pacman
  else if(strcmp(charUID,&quot;424913721823376128&quot;))
    amiiboNo = 17;// Cloud
  else if(strcmp(charUID,&quot;41071282611464128&quot;))
    amiiboNo = 18;// Ness
  else if(strcmp(charUID,&quot;41092522343375128&quot;))
    amiiboNo = 19;// Ryu

  Serial.println(amiiboNo);
  
  uint8_t clipNo = random(3);
  
  switch(amiiboNo){
    case 0:
      if(clipNo == 0)
        playComplete(&quot;MARIO01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;MARIO02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;MARIO03.WAV&quot;);
      break;
    case 1:
      if(clipNo == 0)
        playComplete(&quot;MK01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;MK02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;MK03.WAV&quot;);
      break;
    case 2:
      if(clipNo == 0)
        playComplete(&quot;INK01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;INK02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;INK03.WAV&quot;);
       break;
    case 3:
      if(clipNo == 0)
        playComplete(&quot;DK01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;DK02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;DK03.WAV&quot;);
       break;
    case 4:
      if(clipNo == 0)
        playComplete(&quot;LUCAS01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;LUCAS02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;LUCAS03.WAV&quot;);
       break;
    case 5:
      if(clipNo == 0)
        playComplete(&quot;DUCKH01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;DUCKH02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;DUCKH03.WAV&quot;);
       break;
    case 6:
      if(clipNo == 0)
        playComplete(&quot;OOT01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;OOT02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;OOT03.WAV&quot;);
       break;
    case 7:
      if(clipNo == 0)
        playComplete(&quot;BOTWL01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;BOTWL02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;BOTWL03.WAV&quot;);
       break;
    case 8:
      if(clipNo == 0)
        playComplete(&quot;8BITL01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;8BITL02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;8BITL03.WAV&quot;);
       break;
    case 9:
      if(clipNo == 0)
        playComplete(&quot;TOONL01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;TOONL02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;TOONL03.WAV&quot;);
       break;
    case 10:
      if(clipNo == 0)
        playComplete(&quot;GANDW01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;GANDW02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;GANDW03.WAV&quot;);
       break;
    case 11:
      if(clipNo == 0)
        playComplete(&quot;FALCO01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;FALCO02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;FALCO03.WAV&quot;);
       break;
    case 12:
      if(clipNo == 0)
        playComplete(&quot;DEDEDE01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;DEDEDE02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;DEDEDE03.WAV&quot;);
       break;
    case 13:
      if(clipNo == 0)
        playComplete(&quot;MEWTWO01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;MEWTWO02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;MEWTWO03.WAV&quot;);
       break;
    case 14:
      if(clipNo == 0)
        playComplete(&quot;CAPF01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;CAPF02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;CAPF03.WAV&quot;);
       break;
    case 15:
      if(clipNo == 0)
        playComplete(&quot;ROB01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;ROB02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;ROB03.WAV&quot;);
       break;
    case 16:
      if(clipNo == 0)
        playComplete(&quot;PACMAN01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;PACMAN02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;PACMAN03.WAV&quot;);
       break;
    case 17:
      if(clipNo == 0)
        playComplete(&quot;CLOUD01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;CLOUD02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;CLOUD03.WAV&quot;);
       break;
    case 18:
      if(clipNo == 0)
        playComplete(&quot;NESS01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;NESS02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;NESS03.WAV&quot;);
       break;
    case 19:
      if(clipNo == 0)
        playComplete(&quot;RYU01.WAV&quot;);
      else if(clipNo == 1)
        playComplete(&quot;RYU02.WAV&quot;);
      else if(clipNo == 2)
        playComplete(&quot;RYU03.WAV&quot;);
       break;
       
    }
}

//////// MAIN LOOP /////////
void loop() {

      lcd.print(&quot;Scan an&quot;);
      lcd.setCursor(0,1);
      lcd.print(&quot;amiibo!&quot;);
      delay(3000);
    
    uint8_t * ID{};
        
    waitForRFID();
    
    playSoundClip();
    
  
}


//////////////// MORE WAVE SHIELD ///////////////////////

// Plays a full file from beginning to end with no pause.
void playComplete(char *name) {
  // call our helper to find and play this name
  playfile(name);
  while (wave.isplaying) {
  // do nothing while its playing
  }
  // now its done playing
}

void playfile(char *name) {
  // see if the wave object is currently doing something
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }
  // look in the root directory and open the file
  if (!f.open(root, name)) {
    putstring(&quot;Couldn't open file &quot;); Serial.println(name); return;
  }
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) {
    putstring_nl(&quot;Not a valid WAV&quot;); return;
  }
  
  // ok time to play! start playback
  wave.play();
}

/////////////// END OF WAVE SHIELD //////////////////////

//////////////// RFID FUNCTION /////////////////////////
uint8_t* waitForRFID(){
    nfc.SAMConfig();
  
  Serial.println(&quot;Waiting for an amiibo ...&quot;);

  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  uint8_t uidLength;
  uint8_t testuid[7];
  while(true){
    if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &amp;uidLength)){

      Serial.print(&quot;Hex UID: &quot;);
      nfc.PrintHex(uid, uidLength);
      Serial.print(&quot;Octal UID: { &quot;);
      for(int i = 0; i &lt; uidLength; i++){
        Serial.print(uid[i]);
        GLOBALUID[i] = uid[i];
        if (i != uidLength - 1)
          Serial.print(&quot;, &quot;);
      }
      Serial.println(&quot; }&quot;);

      Serial.print(&quot;GLOBALUID: &quot;);
      for(int i = 0; i &lt; 7; i++)
        Serial.print(GLOBALUID[i]);
        
      Serial.println();
      Serial.println();
    }
    return testuid;
  }
  
}

//////////////// END OF RFID FUNCTION /////////////////
</code></pre>
<p>My first guess for what may be taking up the most memory is the switch statement. When I uncomment that, the memory usage jumps from 90% to over 130%. I've tried other ways to get this code to work, like concatenating text, but this is the only way that seemed to work reliably, until I ran out of memory.</p>
<p>I'm also using a lot of libraries to help use the shields and LCD I have attached to the Uno. I couldn't get rid of those libraries without compromising the project.</p>
<p>Other than that, I don't know what to do. If anyone has any suggestions for condensing the code down, I'd really appreciate any advice you have to offer.</p>
<p>Thanks.</p>
 14095: <p>Just a SWAG try switching from a UNO to a MEGA the code should work once the decelerations are fixed. What the compiler is not telling you is how much memory is actually used. You have the Heap and Stack etc.</p>
 773: <p>As a minor addendum to Edgar Bonet's excellent answer, you could simplify your code further and save even more memory by renaming your files.</p>
<p>In particular, instead of storing a list of character names indexed by Amiibo number and using those as the filename prefix, why not use the Amiibo numbers directly?  That is, instead of your files being named</p>
<blockquote>
<p><code>MARIO01.WAV</code>, <code>MARIO02.WAV</code>, <code>MARIO03.WAV</code>, <code>MK01.WAV</code>, <code>MK02.WAV</code>, <code>MK02.WAV</code>, etc.</p>
</blockquote>
<p>you could just name them e.g.</p>
<blockquote>
<p><code>AMI01_01.WAV</code>, <code>AMI01_02.WAV</code>, <code>AMI01_03.WAV</code>, <code>AMI02_01.WAV</code>, <code>AMI02_02.WAV</code>, <code>AMI02_03.WAV</code>, etc.</p>
</blockquote>
<p>and construct the name in your code e.g. like this:</p>
<pre><code>char filename[13];
int len = snprintf(filename, sizeof(filename), &quot;AMI%02d_%02d.WAV&quot;, amiiboNo + 1, clipNo + 1);
if (len &lt; 0 || len &gt;= sizeof(filename)) {
  // TODO: handle error or insufficient buffer size here
}
</code></pre>
<p>The main advantage here is that you'll save memory by not having to store the list of character names.  The tradeoff, of course, is that your filenames will now be a lot less descriptive.</p>
<p>You could probably optimize this a bit more by manipulating the bytes of the filename directly like Edgar does.  But personally I'd suggest starting with the generic <code>snprintf</code> based solution and only switching to direct byte manipulation if it's still too much. At least I'd assume that the <code>snprintf</code> implementation in the standard library is probably going to be fairly well optimized for a low footprint.  Of course I could be wrong.</p>
 7508: <p>You have a huge <code>switch...case</code> here to decide the name of the file that
should be played. This costs a lot of code space, but also data space,
because every single literal string in this portion of code gets copied
to RAM during initialization.</p>
<p>There is no need to spend all this cost, as the file names have been
assigned in a very regular fashion, so you can build the file name
<em>algorithmically</em>. As a general rule, whenever you find yourself
programming by copying, pasting, then applying some predictable
modifications to the copies, you are almost certainly doing something
wrong. Making repeated copies of the same thing, with predictable
changes is what computers are best for. So you have to ask yourself how
you can instruct the computer (in this case, the Arduino) to do that for
you. Do not do the computer's job yourself!</p>
<p>In this case, the file name is built by gluing three pieces together:</p>
<ul>
<li>a prefix that depends on <code>amiiboNo</code></li>
<li>a two-digit number between <code>&quot;01&quot;</code> and <code>&quot;03&quot;</code>, depending on <code>clipNo</code></li>
<li>the constant suffix <code>&quot;.WAV&quot;</code></li>
</ul>
<p>The prefix cannot be computed algorithmically, so you still have to
write down all the possible prefixes. You could use a big
<code>switch...case</code> for this, but it is way more convenient to pick the
right prefix from an array indexed by <code>amiiboNo</code>:</p>
<pre class="lang-cpp prettyprint-override"><code>const char *file_prefixes[] = {
    &quot;MARIO&quot;, &quot;MK&quot;,    &quot;INK&quot;,    &quot;DK&quot;,    &quot;LUCAS&quot;, &quot;DUCKH&quot;,  &quot;OOT&quot;,
    &quot;BOTWL&quot;, &quot;8BITL&quot;, &quot;TOONL&quot;,  &quot;GANDW&quot;, &quot;FALCO&quot;, &quot;DEDEDE&quot;, &quot;MEWTWO&quot;,
    &quot;CAPF&quot;,  &quot;ROB&quot;,   &quot;PACMAN&quot;, &quot;CLOUD&quot;, &quot;NESS&quot;,  &quot;RYU&quot;
};
</code></pre>
<p>Then, you declare an array of <code>char</code> for holding the file name, and you
build that file name by putting together the three pieces listed above.
Your whole <code>switch...case</code> can then be replaced by this:</p>
<pre class="lang-cpp prettyprint-override"><code>char filename[13];           // longest file name: 12 characters + NUL
char file_number[3] = &quot;01&quot;;  // 2 digits + NUL
file_number[1] += clipNo;    // file_number: &quot;01&quot;, &quot;02&quot; or &quot;O3&quot;
strcpy(filename, file_prefixes[amiiboNo]);
strcat(filename, file_number);
strcat(filename, &quot;.WAV&quot;);
playComplete(filename);
</code></pre>
<p>This will already save you a lot of RAM, but probably not enough. I did
not see any obvious inefficient use of variables in your program (but I
did not look in too much detail), so we will continue to aim at literal
strings.</p>
<p>The problem with literal strings is the fact that they get copied from
flash to RAM during initialization, and whereas you probably have enough
flash, the RAM is in short supply. This is a problem specific to Harvard
architectures, as they have separate address spaces for code and data.
We can use some AVR-specific tricks to instruct the compiler not to
perform this copying. This makes it harder to access the data because
C++ does not natively know about address spaces. Fortunately, there are
some macros and helper functions that can make it easy in specific
cases.</p>
<p>The best know such helper in Arduino world is the <code>F()</code> macro. Use it
every time you <code>print()</code> or <code>println()</code> a literal string, as in:</p>
<pre class="lang-cpp prettyprint-override"><code>Serial.println(F(&quot;Waiting for an amiibo ...&quot;));
</code></pre>
<p>Next, we have to get rid of the very long list of numeric UIDs. For
this, we use the <code>PSTR()</code> macro and <code>strcmp_P()</code> function <a href="https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html" rel="nofollow noreferrer">provided by
the avr-libc</a>. Replace every line that looks like</p>
<pre class="lang-cpp prettyprint-override"><code>if (strcmp(charUID, &quot;479119425560128&quot;))
</code></pre>
<p>by something like</p>
<pre class="lang-cpp prettyprint-override"><code>if (strcmp_P(charUID, PSTR(&quot;479119425560128&quot;)) == 0)
</code></pre>
<p>Note that the value returned by <code>strcmp_P()</code> has to be compared to <code>0</code>, as
this is what that function, just like <code>strcmp()</code>, returns in case of
equality. Thanks to timemage for noticing this issue.</p>
<p>Last, we could also keep all the file prefixes in flash, but this would
be trickier. For now, I suggest you apply the tricks described here and
see whether they are enough to make your program fit.</p>
<p><strong>Edit</strong>: more on the somewhat obscure statement:
<code>file_number[1] += clipNo;</code></p>
<p>In C++, a <code>char</code> is an 8-bit number. Depending on the platform, it can
be either signed (range: −128…+127) or unsigned (0…255). The name comes
from the fact that it is most often used to store the numeric value of an
ASCII character. For example, the numeric value 33 means <code>'!'</code>, 48 means
<code>'0'</code>, and 65 means <code>'A'</code>.</p>
<p>The definition</p>
<pre class="lang-cpp prettyprint-override"><code>char file_number[3] = &quot;01&quot;;
</code></pre>
<p>creates a 3-cell array initialized with the following content:</p>
<pre><code>             ┌─────┬─────┬─────┐
file_number: │  48 │  49 │   0 │
             └─────┴─────┴─────┘
</code></pre>
<p>Using the language notation for characters, the contents could also be
written as follows:</p>
<pre><code>             ┌─────┬─────┬─────┐
file_number: │ '0' │ '1' │ '\0'│
             └─────┴─────┴─────┘
</code></pre>
<p>The last cell with the ASCII NUL is there to inform library functions
such as <code>strcat()</code> that this is where the string of characters ends.</p>
<p>The statement</p>
<pre class="lang-cpp prettyprint-override"><code>file_number[1] += clipNo;
</code></pre>
<p>accesses the second element of the array (array indexing starts at 0)
and increments its numeric value by the amount of <code>clipNo</code>. For example,
if <code>clipNo</code> is 1, then the value in the middle cell will be changed
from 49 (i.e. <code>'1</code>') to 50 (i.e. <code>'2'</code>). This relies on the fact that
ASCII digits have consecutive numeric values, which would also be
expected from any sane character encoding.</p>
