This sketch was completed with the assistance from this forum and has run succesfully for quite a while. I needed the mega for another sketch and when I have tried reloading the original Mega it fails to verify, generally around the SD Card setup with the 'SoftSpiDriver<12, 11, 13>softSpi;' line. I have tried to reload all the libraries associated with the sketch and tried earlier versions of the SdFat library to no avail.
Link to earlier queries when I was building the sketch - Sketch fails after running successfully first time - #36 by BJM1309
Any ideas or assistance greatfully received.
Regards,
Brian
#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" //Use 'Fast' version, other versions cause problems
// #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);
}