Sketch fails after running successfully first time

I initialize the cardIndex to 0 and then there is a for loop going through all the known cards and I compare the number of bytes used to encode the card (some cards have their ID on 4 , 7 or 10 bytes) and if the count marches I compare the bytes in the arrays using memcmp()
If they match I’ve recognized a card so I break out of the for loop otherwise I test the next index.
If I run out of indexes, the for loop exits and cardIndex then is pointing at the last entry of the array (the catch all card)

Then I use this cardIndex to extract the necessary attributes from the structure

Hi,
I think initially the size_t threw me and wondered what it was for. I had looked it up and things were begining to come clearer, Your explanation is great.
Thanks ,
Brian

size_t is just a type like int or unsigned long.

It's the usual type you go for for anything that could be a size or an index in an array. Here you are likely to have less than 255 known cards so you could as well use byte instead of size_t to save some RAM (1 byte versus 4)

Is there any advantage to using size_t rather than a normal data type apart from the descriptive name ?

it's the "normal" data type, the spec states

std::size_t is commonly used for array indexing and loop counting. Programs that use other types, such as unsigned int, for array indexing may fail on, e.g. 64-bit systems when the index exceeds UINT_MAX or if it relies on 32-bit modular arithmetic.

basically it ensures you meet the requirements for the platform you compile on and don't need to worry about not being able to access all the elements in your array.

Now if you know you won't need larger indexes and especially on boards with very little memory, using a byte or a uint16_t is fine too as the subscript operator only expects something that is either an un-scoped enumeration or any integral type. It does not "need" to be size_t, it's just clean to use that when you can afford the extra bytes or for portability.

@J-M-L Thanks for the explanation

Hi,
A quick update !
I have edited the sketch to allow for the images and sounds, added a few more comments and tried not to get too much wrong !
I have also removed and common setup bits from the Loop to Setup areas as well.
The baud speed for the sketch runs at 115200 but for the Mini Player it needs to be run at 9600. With the 'player.play' lines commented out the sketch runs well, all seems normal.
When I uncomment the layer.play, the sketch runs for 1 full loop, image is displayed and sound played, for the 2nd tag (wether the same or different tag), the loop runs until the image is displayed and then seems to lock up - only re-uploading the sketch can unlock it but the same result occurs.
I have been looking into how to managed the player in a better way and am still investigating this.
My latest code:

#include <SPI.h>             // f.k. for Arduino-1.5.2
#define USE_SDFAT
#include <SdFat.h>           // Use the SdFat library
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

#if SPI_DRIVER_SELECT != 2
#error edit SdFatConfig.h .  READ THE SKETCH INSTRUCTIONS
#endif

//  SD Card Setup

SoftSpiDriver<12, 11, 13> softSpi; //Bit-Bang on the Shield pins SDFat.h v2
SdFat SD;
#define SD_CS SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)

//  RFID Setup
/*  Mega Connections for RFID
 *   RST - 43,  *   MOSO - 51, *   MISO - 50, *   SCK - 52, *   SDA - 53
 */
 
#include <MFRC522.h>  //include library code for RFID
const int SS_PIN = 53;  //define RFID pins
const int RST_PIN = 43;
MFRC522 mfrc522(SS_PIN, RST_PIN);   //create MFRC522 instance.

//  DF MiniPlayer setup
// Use pins 18 and 19 to communicate with DFPlayer Mini

static const uint8_t PIN_MP3_TX = 18; // Connects to module's RX
static const uint8_t PIN_MP3_RX = 19; // Connects to module's TX
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFRobotDFPlayerMini player;

//  TFT Setup

#include <Adafruit_GFX.h>    // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

#define NAMEMATCH ""         // "" matches any name
#define PALETTEDEPTH   8     // support 256-colour Palette

char namebuf[32] = "/";   //BMP files in root directory

File root;
int pathlen;

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//  Array through structuring 'Card'

struct Card {
  const char * imageName;
  const char * fileName;
  byte    size;     // Number of bytes in the UID. 4, 7 or 10.
  byte    uidByte[10];
  const char * soundName;
};

Card knownCards[] = {
  { "Talyllyn", "Talyllyn_400x267.bmp", 4, {0x49, 0x0E, 0x4F, 0xA2}, "0008_Talyllyn.wav"},
  { "Dolgoch",  "Dolgoch_400x267.bmp", 4, {0x61, 0x2C, 0x28, 0x27}, "0009_Dolgoch.wav"},
  { "Sir Haydn", "Sir_Haydn_400x267.bmp", 4, {0x60, 0xAB, 0x66, 0x1B}, "0010_Sir Haydn.wav"},
  { "Sir Henry", "Sir_Henry_400x267.bmp", 4, {0x91, 0x6B, 0x0E, 0x26}, "0011_Tom Rolt.wav"},
  {  "Unknown", " ", 0, {" "}, " "},  // this is a catch all card when unknown card is presented
};
constexpr size_t knownCardsCount = (sizeof knownCards / sizeof * knownCards) - 1; // -1 because the very last one is a catch all card

void hexDump(byte *buffer, size_t bufferSize) {
  for (size_t i = 0; i < bufferSize; i++) {
    Serial.write(buffer[i] < 0x10 ? '0' : ' ');
    Serial.print(buffer[i], HEX);
    Serial.write(' ');
  }
}

void setup()
{
    uint16_t ID;
    Serial.begin(115200);
    //  Serial.println("Show BMP files on TFT with ID:0x");
    ID = tft.readID();
    //  Serial.println(ID, HEX);
    if (ID == 0x0D3D3) ID = 0x9481;
    tft.begin(ID);
    tft.setRotation(3);
    tft.fillScreen(BLACK);
    tft.setTextSize(2);
    tft.setTextColor(GREEN);
    bool good = SD.begin(SD_CS);
    if (!good) 
    Serial.print(F("cannot start SD"));
    while (!Serial)
    delay(100);
    SPI.begin();          //initiate SPI bus
    mfrc522.PCD_Init();   //initiate MFRC522
    
//    Mini Player
    softwareSerial.begin(9600);// Start communication with DFPlayer Mini
    if (player.begin(softwareSerial, true, false)) //  true, false needed for mega, not uno
    Serial.println("OK");
// Set volume to maximum (0 to 30).
    player.volume(20);


{
  Serial.println("Put your RFID tag close to the reader...");
  Serial.println();
  }
    root = SD.open(namebuf);
    pathlen = strlen(namebuf);
  }
void loop()
  {
  if ( ! mfrc522.PICC_IsNewCardPresent()) return;
  if ( ! mfrc522.PICC_ReadCardSerial())   return;

  MFRC522::Uid currentCard = mfrc522.uid; // copy what we received

  mfrc522.PICC_HaltA();       // Halt PICC
  mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD

  size_t cardIndex = 0;  //  See notes
  for (; cardIndex < knownCardsCount; cardIndex++)
    if (knownCards[cardIndex].size == currentCard.size)
      if (memcmp(knownCards[cardIndex].uidByte, currentCard.uidByte, currentCard.size) == 0) break; // found (see https://cplusplus.com/reference/cstring/memcmp/)

  //Show UID and image name on serial monitor (if not found, cardIndex is equal to knownCardsCount which is the last "catch all" card
  Serial.print(F("Tag: "));
  hexDump(currentCard.uidByte, currentCard.size);
  Serial.print(F("-> "));
  Serial.println(knownCards[cardIndex].imageName);

    if (cardIndex == 0)  { // Talyllyn
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
      }
  else if (cardIndex == 1)  { // Dolgoch
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 2)  { // Sir Haydn
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 3)  { // Sir Henry
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else  { // Unknown card
    Serial.println("No cigar...");
  }
  
    tft.fillScreen(BLACK);  //resets screen to white after BMP loaded
    Serial.println("Put your RFID tag close to the reader...");
    
}

#define BMPIMAGEOFFSET 54

#define BUFFPIXEL      20  //  must be a divisor of 240

uint16_t read16(File& f) {
    uint16_t result;         // read little-endian
    f.read(&result, sizeof(result));
    return result;
}

uint32_t read32(File& f) {
    uint32_t result;
    f.read(&result, sizeof(result));
    return result;
}

uint8_t showBMP(char *nm, int x, int y)
{
    File bmpFile;
    int bmpWidth, bmpHeight;    // W+H in pixels
    uint8_t bmpDepth;           // Bit depth (currently must be 24, 16, 8, 4, 1)
    uint32_t bmpImageoffset;    // Start of image data in file
    uint32_t rowSize;           // Not always = bmpWidth; may have padding
    uint8_t sdbuffer[3 * BUFFPIXEL];    // pixel in buffer (R+G+B per pixel)
    uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL;
    uint8_t bitmask, bitshift;
    boolean flip = true;        // BMP is stored bottom-to-top
    int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx;
    uint32_t pos;               // seek position
    boolean is565 = false;      //

    uint16_t bmpID;
    uint16_t n;                 // blocks read
    uint8_t ret;

    if ((x >= tft.width()) || (y >= tft.height()))
        return 1;               // off screen

    bmpFile = SD.open(nm);      // Parse BMP header
    bmpID = read16(bmpFile);    // BMP signature
    (void) read32(bmpFile);     // Read & ignore file size
    (void) read32(bmpFile);     // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile);       // Start of image data
    (void) read32(bmpFile);     // Read & ignore DIB header size
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    n = read16(bmpFile);        // # planes -- must be '1'
    bmpDepth = read16(bmpFile); // bits per pixel
    pos = read32(bmpFile);      // format
    if (bmpID != 0x4D42) ret = 2; // bad ID
    else if (n != 1) ret = 3;   // too many planes
    else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565
    else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette 
    else {
        bool first = true;
        is565 = (pos == 3);               // ?already in 16-bit format
        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
        if (bmpHeight < 0) {              // If negative, image is in top-down order.
            bmpHeight = -bmpHeight;
            flip = false;
        }

        w = bmpWidth;
        h = bmpHeight;
        if ((x + w) >= tft.width())       // Crop area to be loaded
            w = tft.width() - x;
        if ((y + h) >= tft.height())      //
            h = tft.height() - y;

        if (bmpDepth <= PALETTEDEPTH) {   // these modes have separate palette
            //bmpFile.seek(BMPIMAGEOFFSET); //palette is always @ 54
            bmpFile.seek(bmpImageoffset - (4<<bmpDepth)); //54 for regular, diff for colorsimportant
            bitmask = 0xFF;
            if (bmpDepth < 8)
                bitmask >>= bmpDepth;
            bitshift = 8 - bmpDepth;
            n = 1 << bmpDepth;
            lcdbufsiz -= n;
            palette = lcdbuffer + lcdbufsiz;
            for (col = 0; col < n; col++) {
                pos = read32(bmpFile);    //map palette to 5-6-5
                palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8);
            }
        }

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
        for (row = 0; row < h; row++) { // For each scanline...
            // Seek to start of scan line.  It might seem labor-
            // intensive to be doing this on every line, but this
            // method covers a lot of gritty details like cropping
            // and scanline padding.  Also, the seek only takes
            // place if the file position actually needs to change
            // (avoids a lot of cluster math in SD library).
            uint8_t r, g, b, *sdptr;
            int lcdidx, lcdleft;
            if (flip)   // Bitmap is stored bottom-to-top order (normal BMP)
                pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
            else        // Bitmap is stored top-to-bottom
                pos = bmpImageoffset + row * rowSize;
            if (bmpFile.position() != pos) { // Need seek?
                bmpFile.seek(pos);
                buffidx = sizeof(sdbuffer); // Force buffer reload
            }

            for (col = 0; col < w; ) {  //pixels in row
                lcdleft = w - col;
                if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
                for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
                    uint16_t color;
                    // Time to read more pixel data?
                    if (buffidx >= sizeof(sdbuffer)) { // Indeed
                        bmpFile.read(sdbuffer, sizeof(sdbuffer));
                        buffidx = 0; // Set index to beginning
                        r = 0;
                    }
                    switch (bmpDepth) {          // Convert pixel from BMP to TFT format
                        case 24:
                            b = sdbuffer[buffidx++];
                            g = sdbuffer[buffidx++];
                            r = sdbuffer[buffidx++];
                            color = tft.color565(r, g, b);
                            break;
                        case 16:
                            b = sdbuffer[buffidx++];
                            r = sdbuffer[buffidx++];
                            if (is565)
                                color = (r << 8) | (b);
                            else
                                color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
                            break;
                        case 1:
                        case 4:
                        case 8:
                            if (r == 0)
                                b = sdbuffer[buffidx++], r = 8;
                            color = palette[(b >> bitshift) & bitmask];
                            r -= bmpDepth;
                            b <<= bmpDepth;
                            break;
                    }
                    lcdbuffer[lcdidx] = color;

                }
                tft.pushColors(lcdbuffer, lcdidx, first);
                first = false;
                col += lcdidx;
            }           // end cols
        }               // end rows
        tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
        ret = 0;        // good render
    }
    Serial.println();
    bmpFile.close();
    return (ret);
}

Will let you know how things go.
Kind regards,
Brian

you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

there is a pin on your DFPlayer that you can connect to to see if a MP3 is currently playing. That could help you decide what to do if a new card is presented and the previous song is not finished

Thanks for this, studying hard !
Brian

Hi, slowly getting to grips with the static machine ! I have built a sutable board with LEDS and switches and am trying to get to grips with the problems within the introduction to the static machine.
I have also been trying to get the busy pin on the DF mini player working correctly. Currently the sketch works for 1 pass of an RFID TAG then freezes, which was my original problem, although the sketch now looks better then the original. I have noted that the baud speed for the DF Player should be set at 9600 to give it enough time to reset. Running the Serial Monitor at 115200 at the same time does not seem to bother either, the sketch runs well - for the first time. Whilst the track is playing the busy light on the mini player is lit and goes out when the track finishes.
I cannot seem to get out of this loop.
Current sketch:

#include <SPI.h>             // f.k. for Arduino-1.5.2
#define USE_SDFAT
#include <SdFat.h>           // Use the SdFat library
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

#if SPI_DRIVER_SELECT != 2
#error edit SdFatConfig.h .  READ THE SKETCH INSTRUCTIONS
#endif

//  SD Card Setup

SoftSpiDriver<12, 11, 13> softSpi; //Bit-Bang on the Shield pins SDFat.h v2
SdFat SD;
#define SD_CS SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)

//  RFID Setup
/*  Mega Connections for RFID
 *   RST - 43,  *   MOSO - 51, *   MISO - 50, *   SCK - 52, *   SDA - 53
 */
 
#include <MFRC522.h>  //include library code for RFID
const int SS_PIN = 53;  //define RFID pins
const int RST_PIN = 43;
MFRC522 mfrc522(SS_PIN, RST_PIN);   //create MFRC522 instance.

//  DF MiniPlayer setup
// Use pins 18 and 19 to communicate with DFPlayer Mini

# define Busy_PIN 42
static const uint8_t PIN_MP3_TX = 18; // Connects to module's RX
static const uint8_t PIN_MP3_RX = 19; // Connects to module's TX
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

    int BusyState = 0;  //  Busy state variables
    int prevBusyState = 0;

// Create the Player object
DFRobotDFPlayerMini player;

//  TFT Setup

#include <Adafruit_GFX.h>    // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

#define NAMEMATCH ""         // "" matches any name
#define PALETTEDEPTH   8     // support 256-colour Palette

char namebuf[32] = "/";   //BMP files in root directory

File root;
int pathlen;

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//  Array through structuring 'Card'

struct Card {
  const char * imageName;
  const char * fileName;
  byte    size;     // Number of bytes in the UID. 4, 7 or 10.
  byte    uidByte[10];
  const char * soundName;
};

Card knownCards[] = {
  { "Talyllyn", "Talyllyn_400x267.bmp", 4, {0x49, 0x0E, 0x4F, 0xA2}, "0001_Talyllyn.wav"},
  { "Dolgoch",  "Dolgoch_400x267.bmp", 4, {0x61, 0x2C, 0x28, 0x27}, "0002_Dolgoch.wav"},
  { "Sir Haydn", "Sir_Haydn_400x267.bmp", 4, {0x60, 0xAB, 0x66, 0x1B}, "0003_Sir Haydn.wav"},
  { "Sir Henry", "Sir_Henry_400x267.bmp", 4, {0x91, 0x6B, 0x0E, 0x26}, "0004_Tom Rolt.wav"},
  {  "Unknown", " ", 0, {" "}, " "},  // this is a catch all card when unknown card is presented
};
constexpr size_t knownCardsCount = (sizeof knownCards / sizeof * knownCards) - 1; // -1 because the very last one is a catch all card

void hexDump(byte *buffer, size_t bufferSize) {
  for (size_t i = 0; i < bufferSize; i++) {
    Serial.write(buffer[i] < 0x10 ? '0' : ' ');
    Serial.print(buffer[i], HEX);
    Serial.write(' ');
  }
}

void setup()
{
    uint16_t ID;
    Serial.begin(9600);
    //  Serial.println("Show BMP files on TFT with ID:0x");
    ID = tft.readID();
    //  Serial.println(ID, HEX);
    if (ID == 0x0D3D3) ID = 0x9481;
    tft.begin(ID);
    tft.setRotation(3);
    tft.fillScreen(BLACK);
    tft.setTextSize(2);
    tft.setTextColor(GREEN);
    bool good = SD.begin(SD_CS);
    if (!good) 
    Serial.print(F("cannot start SD"));
    while (!Serial)
    delay(100);
    SPI.begin();          //initiate SPI bus
    mfrc522.PCD_Init();   //initiate MFRC522
    
//    Mini Player
    softwareSerial.begin(9600);// Start communication with DFPlayer Mini
    if (player.begin(softwareSerial, true, false)) //  true, false needed for mega, not uno
    Serial.println("OK");
    
// Set volume to maximum (0 to 30).
    player.volume(25);

    pinMode(Busy_PIN, INPUT);

{
  Serial.println("Put your RFID tag close to the reader...");
  Serial.println();
  }
    root = SD.open(namebuf);
    pathlen = strlen(namebuf);
  }

    
void loop()
  {
  if ( ! mfrc522.PICC_IsNewCardPresent()) return;
  if ( ! mfrc522.PICC_ReadCardSerial())   return;

  MFRC522::Uid currentCard = mfrc522.uid; // copy what we received

  mfrc522.PICC_HaltA();       // Halt PICC
  mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD

  size_t cardIndex = 0;  //  See notes
  for (; cardIndex < knownCardsCount; cardIndex++)
    if (knownCards[cardIndex].size == currentCard.size)
      if (memcmp(knownCards[cardIndex].uidByte, currentCard.uidByte, currentCard.size) == 0) break; // found (see https://cplusplus.com/reference/cstring/memcmp/)

  //Show UID and image name on serial monitor (if not found, cardIndex is equal to knownCardsCount which is the last "catch all" card
  Serial.print(F("Tag: "));
  hexDump(currentCard.uidByte, currentCard.size);
  Serial.print(F("-> "));
  Serial.println(knownCards[cardIndex].imageName);

    BusyState = digitalRead (Busy_PIN);

      if (BusyState != prevBusyState) {
      if (BusyState == LOW);
    }
    prevBusyState == BusyState;
    Serial.println ("playing");

  
  if (cardIndex == 0)  { // Talyllyn
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
      }
  else if (cardIndex == 1)  { // Dolgoch
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 2)  { // Sir Haydn
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 3)  { // Sir Henry
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else  { // Unknown card
    Serial.println("No cigar...");
  }
  
    tft.fillScreen(BLACK);  //resets screen to white after BMP loaded
    Serial.println("Put your RFID tag close to the reader...");
    
}

#define BMPIMAGEOFFSET 54

#define BUFFPIXEL      20  //  must be a divisor of 240

uint16_t read16(File& f) {
    uint16_t result;         // read little-endian
    f.read(&result, sizeof(result));
    return result;
}

uint32_t read32(File& f) {
    uint32_t result;
    f.read(&result, sizeof(result));
    return result;
}

uint8_t showBMP(char *nm, int x, int y)
{
    File bmpFile;
    int bmpWidth, bmpHeight;    // W+H in pixels
    uint8_t bmpDepth;           // Bit depth (currently must be 24, 16, 8, 4, 1)
    uint32_t bmpImageoffset;    // Start of image data in file
    uint32_t rowSize;           // Not always = bmpWidth; may have padding
    uint8_t sdbuffer[3 * BUFFPIXEL];    // pixel in buffer (R+G+B per pixel)
    uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL;
    uint8_t bitmask, bitshift;
    boolean flip = true;        // BMP is stored bottom-to-top
    int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx;
    uint32_t pos;               // seek position
    boolean is565 = false;      //

    uint16_t bmpID;
    uint16_t n;                 // blocks read
    uint8_t ret;

    if ((x >= tft.width()) || (y >= tft.height()))
        return 1;               // off screen

    bmpFile = SD.open(nm);      // Parse BMP header
    bmpID = read16(bmpFile);    // BMP signature
    (void) read32(bmpFile);     // Read & ignore file size
    (void) read32(bmpFile);     // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile);       // Start of image data
    (void) read32(bmpFile);     // Read & ignore DIB header size
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    n = read16(bmpFile);        // # planes -- must be '1'
    bmpDepth = read16(bmpFile); // bits per pixel
    pos = read32(bmpFile);      // format
    if (bmpID != 0x4D42) ret = 2; // bad ID
    else if (n != 1) ret = 3;   // too many planes
    else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565
    else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette 
    else {
        bool first = true;
        is565 = (pos == 3);               // ?already in 16-bit format
        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
        if (bmpHeight < 0) {              // If negative, image is in top-down order.
            bmpHeight = -bmpHeight;
            flip = false;
        }

        w = bmpWidth;
        h = bmpHeight;
        if ((x + w) >= tft.width())       // Crop area to be loaded
            w = tft.width() - x;
        if ((y + h) >= tft.height())      //
            h = tft.height() - y;

        if (bmpDepth <= PALETTEDEPTH) {   // these modes have separate palette
            //bmpFile.seek(BMPIMAGEOFFSET); //palette is always @ 54
            bmpFile.seek(bmpImageoffset - (4<<bmpDepth)); //54 for regular, diff for colorsimportant
            bitmask = 0xFF;
            if (bmpDepth < 8)
                bitmask >>= bmpDepth;
            bitshift = 8 - bmpDepth;
            n = 1 << bmpDepth;
            lcdbufsiz -= n;
            palette = lcdbuffer + lcdbufsiz;
            for (col = 0; col < n; col++) {
                pos = read32(bmpFile);    //map palette to 5-6-5
                palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8);
            }
        }

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
        for (row = 0; row < h; row++) { // For each scanline...
            // Seek to start of scan line.  It might seem labor-
            // intensive to be doing this on every line, but this
            // method covers a lot of gritty details like cropping
            // and scanline padding.  Also, the seek only takes
            // place if the file position actually needs to change
            // (avoids a lot of cluster math in SD library).
            uint8_t r, g, b, *sdptr;
            int lcdidx, lcdleft;
            if (flip)   // Bitmap is stored bottom-to-top order (normal BMP)
                pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
            else        // Bitmap is stored top-to-bottom
                pos = bmpImageoffset + row * rowSize;
            if (bmpFile.position() != pos) { // Need seek?
                bmpFile.seek(pos);
                buffidx = sizeof(sdbuffer); // Force buffer reload
            }

            for (col = 0; col < w; ) {  //pixels in row
                lcdleft = w - col;
                if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
                for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
                    uint16_t color;
                    // Time to read more pixel data?
                    if (buffidx >= sizeof(sdbuffer)) { // Indeed
                        bmpFile.read(sdbuffer, sizeof(sdbuffer));
                        buffidx = 0; // Set index to beginning
                        r = 0;
                    }
                    switch (bmpDepth) {          // Convert pixel from BMP to TFT format
                        case 24:
                            b = sdbuffer[buffidx++];
                            g = sdbuffer[buffidx++];
                            r = sdbuffer[buffidx++];
                            color = tft.color565(r, g, b);
                            break;
                        case 16:
                            b = sdbuffer[buffidx++];
                            r = sdbuffer[buffidx++];
                            if (is565)
                                color = (r << 8) | (b);
                            else
                                color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
                            break;
                        case 1:
                        case 4:
                        case 8:
                            if (r == 0)
                                b = sdbuffer[buffidx++], r = 8;
                            color = palette[(b >> bitshift) & bitmask];
                            r -= bmpDepth;
                            b <<= bmpDepth;
                            break;
                    }
                    lcdbuffer[lcdidx] = color;

                }
                tft.pushColors(lcdbuffer, lcdidx, first);
                first = false;
                col += lcdidx;
            }           // end cols
        }               // end rows
        tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
        ret = 0;        // good render
    }
    
  
    prevBusyState = BusyState;
    Serial.println();
    bmpFile.close();
    return (ret);
}

In addition, the sound track played is always the track related to the 3rd RFID TAG. Each tag always brings up the correct image but only playes the sound for 'Sir Haydn' the 3rd tag on the card index. Whilst learning lots, I am baffled by this !
Any pointers gratefully received.
Regards,
Brian

I don't think the library does take a filename to play a song. You have to provide a number like 0 for the first song on the SD card, 1 for the second one etc...

➜ the structure probably would need to be adjusted

struct Card {
  const char * imageName;
  const char * fileName;
  byte    size;     // Number of bytes in the UID. 4, 7 or 10.
  byte    uidByte[10];
  int soundIndex;
};

Card knownCards[] = {
  { "Talyllyn", "Talyllyn_400x267.bmp", 4, {0x49, 0x0E, 0x4F, 0xA2}, 1},
  { "Dolgoch",  "Dolgoch_400x267.bmp", 4, {0x61, 0x2C, 0x28, 0x27}, 2},
  { "Sir Haydn", "Sir_Haydn_400x267.bmp", 4, {0x60, 0xAB, 0x66, 0x1B}, 3},
  { "Sir Henry", "Sir_Henry_400x267.bmp", 4, {0x91, 0x6B, 0x0E, 0x26}, 4},
  {  "Unknown", " ", 0, {" "}, 0},  // this is a catch all card when unknown card is presented
};

and use

    player.play(knownCards[cardIndex]. soundIndex);

side note: everything being in a structure with an index, you don't have to do the big if where you repeat exactly the same code


  if (cardIndex == 0)  { // Talyllyn
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 1)  { // Dolgoch
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 2)  { // Sir Haydn
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else if (cardIndex == 3)  { // Sir Henry
    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex].soundName);
  }
  else  { // Unknown card
    Serial.println("No cigar...");
  }

you just need to check if the cardIndex is not the Unknown card then you can do

    Serial.println(knownCards[cardIndex].imageName);
    showBMP(knownCards[cardIndex].fileName, 40, 0);
    tft.setCursor(180, 285);
    tft.println(knownCards[cardIndex].imageName);
    player.play(knownCards[cardIndex]. soundIndex);
  if (BusyState != prevBusyState) {
    if (BusyState == LOW)
      ;
  }
  prevBusyState == BusyState;
  Serial.println("playing");

prevBusyState will always == BusyState EDIT: didn't even notice the double =
This statement checks to see if prevBusyState is equal to BusyState, it does not assign BusyState to prevBusyState
"playing" will always be printed

That is a bug in your code. Single '=' for assignment.

Sorry for my tardy response, I have been laid low with a bug !
Many thanks for the suggestions, trying them out,
Regards, Brian

Hi,
A few comments, I have removed the "Playing" being serial printed, this was just a check line for me.
I now have it playing the correct tracks with the corresponding tag - for some reason, the first track 0001 was causing the problem, renaming it to 0005 has got around this.
The sketch ran slightly better, one full round of displaying the image and then the sound - passing a second tag will display the image before the sketch freezes. I have noted that the voltage on the busy pin drops from 3.67V to 0.3V whilst the track is playing; it returns high - 3.67V once the track has finished playing. This remains at 3.67V when the sketch freezes.
I have tried running the sketch with the 'sound lines' in the loop both commented out and running, this does not seem to change anything. Running the sketch with all reference to sound commented out runs the image part of the sketch as required with no freezing.
I was begining to wonder if I have a library problem that causes the hang up even though it plays the sound first time around.
Having looked at the DF Mini Player libraries again I loaded the DFPlayerMini_Fast which has cured the problem - at last, the sketch seems to run well now and I have renamed 0005 back to 0001 and this works as well.
I have taken all reference to the busy pin out as it did not need it.
I have started to rewrite the sketch using the Static Machine 'case' setup but am wondering if this would be better than the array structure ?
Many thanks for all your asistance, been mind blowing at times but learnt a lot!
Many thanks and kind regards,
Brian
Latest sketch:

#include <SPI.h>             // f.k. for Arduino-1.5.2
#define USE_SDFAT
#include <SdFat.h>           // Use the SdFat library
#include "SoftwareSerial.h"
#include "DFPlayerMini_Fast.h"

#if SPI_DRIVER_SELECT != 2
#error edit SdFatConfig.h .  READ THE SKETCH INSTRUCTIONS
#endif

//  SD Card Setup

SoftSpiDriver<12, 11, 13> softSpi; //Bit-Bang on the Shield pins SDFat.h v2
SdFat SD;
#define SD_CS SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)

//  RFID Setup
/*  Mega Connections for RFID
 *   RST - 43,  *   MOSO - 51, *   MISO - 50, *   SCK - 52, *   SDA - 53
 */
 
#include <MFRC522.h>  //include library code for RFID
const int SS_PIN = 53;  //define RFID pins
const int RST_PIN = 43;
MFRC522 mfrc522(SS_PIN, RST_PIN);   //create MFRC522 instance.


//  TFT Setup

#include <Adafruit_GFX.h>    // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

#define NAMEMATCH ""         // "" matches any name
#define PALETTEDEPTH   8     // support 256-colour Palette

char namebuf[32] = "/";   //BMP files in root directory

File root;
int pathlen;

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


//  DF MiniPlayer setup
// Use pins 18 and 19 to communicate with DFPlayer Mini

static const uint8_t PIN_MP3_TX = 18; // Connects to module's RX
static const uint8_t PIN_MP3_RX = 19; // Connects to module's TX
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFPlayerMini_Fast player;

//  Array through structuring 'Card'

struct Card {
  const char * imageName;
  const char * fileName;
  byte    size;     // Number of bytes in the UID. 4, 7 or 10.
  byte    uidByte[10];
  int soundIndex;
};

Card knownCards[] = {
  { "Talyllyn", "Talyllyn_400x267.bmp", 4, {0x49, 0x0E, 0x4F, 0xA2}, 0001},
  { "Dolgoch",  "Dolgoch_400x267.bmp", 4, {0x61, 0x2C, 0x28, 0x27}, 0002},
  { "Sir Haydn", "Sir_Haydn_400x267.bmp", 4, {0x60, 0xAB, 0x66, 0x1B}, 0003},
  { "Sir Henry", "Sir_Henry_400x267.bmp", 4, {0x91, 0x6B, 0x0E, 0x26}, 0004},
  {  "Unknown", " ", 0, {" "}, },  // this is a catch all cards when unknown card is presented
};
constexpr size_t knownCardsCount = (sizeof knownCards / sizeof * knownCards) - 1; // -1 because the very last one is a catch all card

void hexDump(byte *buffer, size_t bufferSize) {
  for (size_t i = 0; i < bufferSize; i++) {
    Serial.write(buffer[i] < 0x10 ? '0' : ' ');
    Serial.print(buffer[i], HEX);
    Serial.write(' ');
  }
}

void setup()
{
    uint16_t ID;
    Serial.begin(115200);
    ID = tft.readID();
    if (ID == 0x0D3D3) ID = 0x9481;
    tft.begin(ID);
    tft.setRotation(1);
    tft.fillScreen(BLACK);
    tft.setTextSize(2);
    tft.setTextColor(GREEN);
    bool good = SD.begin(SD_CS);
    if (!good) 
    Serial.print(F("cannot start SD"));
    while (!Serial)
    delay(100);
    SPI.begin();          //initiate SPI bus
    mfrc522.PCD_Init();   //initiate MFRC522

//  Mini Player
    softwareSerial.begin(9600);// Start communication with DFPlayer Mini
    if (player.begin(softwareSerial, true, false)) //  true, false needed for mega, not uno
       
//  Set volume to maximum (0 to 30).
    player.volume(25);
{
  Serial.println("Put your RFID tag close to the reader...");
  Serial.println();
  }
    root = SD.open(namebuf);
    pathlen = strlen(namebuf);
  }
  
void loop()
  {
  if ( ! mfrc522.PICC_IsNewCardPresent()) return;
  if ( ! mfrc522.PICC_ReadCardSerial())   return;

  MFRC522::Uid currentCard = mfrc522.uid; // copy what we received

  mfrc522.PICC_HaltA();       // Halt PICC
  mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD

  size_t cardIndex = 0;  //  See notes
  for (; cardIndex < knownCardsCount; cardIndex++)
    if (knownCards[cardIndex].size == currentCard.size)
      if (memcmp(knownCards[cardIndex].uidByte, currentCard.uidByte, currentCard.size) == 0) break; // found (see https://cplusplus.com/reference/cstring/memcmp/)

  //Show UID and image name on serial monitor (if not found, cardIndex is equal to knownCardsCount which is the last "catch all" card
      Serial.print(F("Tag: "));
      hexDump(currentCard.uidByte, currentCard.size);
      Serial.print(F("-> "));
      Serial.println(knownCards[cardIndex].imageName);

      showBMP(knownCards[cardIndex].fileName, 40, 0);
      tft.setCursor(180, 285);
      tft.println(knownCards[cardIndex].imageName);
      player.play(knownCards[cardIndex].soundIndex);
   
      tft.fillScreen(BLACK);  //resets screen to black after BMP loaded
      Serial.println("Put your RFID tag close to the reader...");
}

#define BMPIMAGEOFFSET 54

#define BUFFPIXEL      20  //  must be a divisor of 240

uint16_t read16(File& f) {
    uint16_t result;         // read little-endian
    f.read(&result, sizeof(result));
    return result;
}

uint32_t read32(File& f) {
    uint32_t result;
    f.read(&result, sizeof(result));
    return result;
}

uint8_t showBMP(char *nm, int x, int y)
{
    File bmpFile;
    int bmpWidth, bmpHeight;    // W+H in pixels
    uint8_t bmpDepth;           // Bit depth (currently must be 24, 16, 8, 4, 1)
    uint32_t bmpImageoffset;    // Start of image data in file
    uint32_t rowSize;           // Not always = bmpWidth; may have padding
    uint8_t sdbuffer[3 * BUFFPIXEL];    // pixel in buffer (R+G+B per pixel)
    uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL;
    uint8_t bitmask, bitshift;
    boolean flip = true;        // BMP is stored bottom-to-top
    int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx;
    uint32_t pos;               // seek position
    boolean is565 = false;      //

    uint16_t bmpID;
    uint16_t n;                 // blocks read
    uint8_t ret;

    if ((x >= tft.width()) || (y >= tft.height()))
        return 1;               // off screen

    bmpFile = SD.open(nm);      // Parse BMP header
    bmpID = read16(bmpFile);    // BMP signature
    (void) read32(bmpFile);     // Read & ignore file size
    (void) read32(bmpFile);     // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile);       // Start of image data
    (void) read32(bmpFile);     // Read & ignore DIB header size
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    n = read16(bmpFile);        // # planes -- must be '1'
    bmpDepth = read16(bmpFile); // bits per pixel
    pos = read32(bmpFile);      // format
    if (bmpID != 0x4D42) ret = 2; // bad ID
    else if (n != 1) ret = 3;   // too many planes
    else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565
    else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette 
    else {
        bool first = true;
        is565 = (pos == 3);               // ?already in 16-bit format
        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
        if (bmpHeight < 0) {              // If negative, image is in top-down order.
            bmpHeight = -bmpHeight;
            flip = false;
        }

        w = bmpWidth;
        h = bmpHeight;
        if ((x + w) >= tft.width())       // Crop area to be loaded
            w = tft.width() - x;
        if ((y + h) >= tft.height())      //
            h = tft.height() - y;

        if (bmpDepth <= PALETTEDEPTH) {   // these modes have separate palette
            //bmpFile.seek(BMPIMAGEOFFSET); //palette is always @ 54
            bmpFile.seek(bmpImageoffset - (4<<bmpDepth)); //54 for regular, diff for colorsimportant
            bitmask = 0xFF;
            if (bmpDepth < 8)
                bitmask >>= bmpDepth;
            bitshift = 8 - bmpDepth;
            n = 1 << bmpDepth;
            lcdbufsiz -= n;
            palette = lcdbuffer + lcdbufsiz;
            for (col = 0; col < n; col++) {
                pos = read32(bmpFile);    //map palette to 5-6-5
                palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8);
            }
        }

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
        for (row = 0; row < h; row++) { // For each scanline...
            // Seek to start of scan line.  It might seem labor-
            // intensive to be doing this on every line, but this
            // method covers a lot of gritty details like cropping
            // and scanline padding.  Also, the seek only takes
            // place if the file position actually needs to change
            // (avoids a lot of cluster math in SD library).
            uint8_t r, g, b, *sdptr;
            int lcdidx, lcdleft;
            if (flip)   // Bitmap is stored bottom-to-top order (normal BMP)
                pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
            else        // Bitmap is stored top-to-bottom
                pos = bmpImageoffset + row * rowSize;
            if (bmpFile.position() != pos) { // Need seek?
                bmpFile.seek(pos);
                buffidx = sizeof(sdbuffer); // Force buffer reload
            }

            for (col = 0; col < w; ) {  //pixels in row
                lcdleft = w - col;
                if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
                for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
                    uint16_t color;
                    // Time to read more pixel data?
                    if (buffidx >= sizeof(sdbuffer)) { // Indeed
                        bmpFile.read(sdbuffer, sizeof(sdbuffer));
                        buffidx = 0; // Set index to beginning
                        r = 0;
                    }
                    switch (bmpDepth) {          // Convert pixel from BMP to TFT format
                        case 24:
                            b = sdbuffer[buffidx++];
                            g = sdbuffer[buffidx++];
                            r = sdbuffer[buffidx++];
                            color = tft.color565(r, g, b);
                            break;
                        case 16:
                            b = sdbuffer[buffidx++];
                            r = sdbuffer[buffidx++];
                            if (is565)
                                color = (r << 8) | (b);
                            else
                                color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
                            break;
                        case 1:
                        case 4:
                        case 8:
                            if (r == 0)
                                b = sdbuffer[buffidx++], r = 8;
                            color = palette[(b >> bitshift) & bitmask];
                            r -= bmpDepth;
                            b <<= bmpDepth;
                            break;
                    }
                    lcdbuffer[lcdidx] = color;

                }
                tft.pushColors(lcdbuffer, lcdidx, first);
                first = false;
                col += lcdidx;
            }           // end cols
        }               // end rows
        tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
        ret = 0;        // good render
    }
    bmpFile.close();
    return (ret);
   
}```