// Teensy 4.1 bring-up: detect, list, and read the SD card in the built-in slot. // // Uses the Teensy built-in SD library (4-bit SDMMC on the onboard slot — not the // SPI SD slot on the display module). Prints card info, the root directory // listing, and the first 512 bytes of the first file it finds, all over USB CDC // so we can inspect a card that may already be formatted with files on it. // // Build / upload: // arduino-cli compile --fqbn teensy:avr:teensy41 firmware/teensy41/sd_test // arduino-cli upload -p /dev/ttyACM0 --fqbn teensy:avr:teensy41 firmware/teensy41/sd_test // // Monitor: // stty -F /dev/ttyACM0 115200 raw -echo && cat /dev/ttyACM0 // // Exit criterion: card is detected, its size + format are reported, the root // directory lists, and a sample file read round-trips. #include static void report() { Serial.println(); Serial.println("=== Teensy 4.1 SD card test ==="); Serial.println(); // BUILTIN_SDCARD selects the Teensy 4.1's onboard 4-bit SDMMC slot. if (!SD.begin(BUILTIN_SDCARD)) { Serial.println("ERROR: SD.begin(BUILTIN_SDCARD) failed — no card, bad card, or wiring issue."); Serial.println("Check that a card is seated in the Teensy's built-in slot."); return; } Serial.println("SD card mounted OK via 4-bit SDMMC (BUILTIN_SDCARD)."); // Card type via the Sd2Card helper (wraps SD.sdfs.card()->type()). Sd2Card card; uint8_t ct = card.type(); Serial.print("Card type: "); switch (ct) { case SD_CARD_TYPE_SD1: Serial.println("SD1 (standard)"); break; case SD_CARD_TYPE_SD2: Serial.println("SD2 (standard)"); break; case SD_CARD_TYPE_SDHC: Serial.println("SDHC/SDXC"); break; default: Serial.println("unknown"); break; } // Card size: SdFat v2 exposes sector count on the card object. uint64_t sectors = 0; if (SD.sdfs.card()) sectors = SD.sdfs.card()->sectorCount(); uint64_t sz = sectors * 512ULL; Serial.print("Sectors (512 B): "); Serial.println((uint64_t)sectors); Serial.print("Card size (bytes): "); Serial.println((uint64_t)sz); Serial.print("Card size (GB): "); Serial.println((uint64_t)sz / (1000ULL * 1000ULL * 1000ULL)); Serial.print("Card size (GiB): "); Serial.println((uint64_t)sz / (1024ULL * 1024ULL * 1024ULL)); // FAT type + cluster info via the SdVolume helper. SdVolume vol; vol.init(card); Serial.print("Volume FAT type: "); switch (vol.fatType()) { case 0: Serial.println("(none / not FAT — likely exFAT)"); break; case 12: Serial.println("FAT12"); break; case 16: Serial.println("FAT16"); break; case 32: Serial.println("FAT32"); break; default: Serial.print(vol.fatType()); Serial.println(" (unknown)"); break; } Serial.print("Cluster count: "); Serial.println(vol.clusterCount()); Serial.print("Blocks per cluster: "); Serial.println(vol.blocksPerCluster()); Serial.print("sdfs.vol() fatType: "); if (SD.sdfs.vol()) Serial.println(SD.sdfs.vol()->fatType()); else Serial.println("(no FAT volume — likely exFAT-only)"); Serial.println(); Serial.println("=== Root directory listing ==="); File root = SD.open("/"); printDirectory(root, 0); root.close(); Serial.println("=== end listing ==="); // Try to read the first regular file in the root and dump its first 512 bytes. Serial.println(); Serial.println("=== First-file read test ==="); root = SD.open("/"); File first; while (true) { first = root.openNextFile(); if (!first) break; if (!first.isDirectory()) break; first.close(); } root.close(); if (first) { Serial.print("Reading: "); Serial.print(first.name()); Serial.print(" ("); Serial.print(first.size(), DEC); Serial.println(" bytes)"); Serial.println("--- first 512 bytes (hex + ASCII) ---"); uint8_t buf[512]; int n = first.read(buf, sizeof(buf)); for (int i = 0; i < n; i++) { if (buf[i] < 0x10) Serial.print('0'); Serial.print(buf[i], HEX); Serial.print(' '); if ((i & 15) == 15) { Serial.print(" | "); for (int j = i - 15; j <= i; j++) { char c = (char)buf[j]; Serial.print((c >= 32 && c < 127) ? c : '.'); } Serial.println(); } } Serial.println("--- end dump ---"); first.close(); } else { Serial.println("No regular files in root directory."); } Serial.println(); Serial.println("=== SD test complete ==="); } static void printDirectory(File dir, int depth) { while (true) { File entry = dir.openNextFile(); if (!entry) break; // no more files for (int i = 0; i < depth; i++) Serial.print(" "); if (entry.isDirectory()) { Serial.print(entry.name()); Serial.println("/"); printDirectory(entry, depth + 1); } else { Serial.print(entry.name()); Serial.print("\t"); Serial.print(entry.size(), DEC); Serial.println(" bytes"); } entry.close(); } } void setup() { Serial.begin(115200); while (!Serial && millis() < 4000) ; // wait up to 4s for USB CDC pinMode(LED_BUILTIN, OUTPUT); // Print the report once at boot (may be missed if the host isn't listening // yet — that's fine, send any byte to re-trigger). report(); } void loop() { // Re-run the report whenever any byte arrives over USB CDC, so the host can // request the report after the port has been opened. if (Serial.available()) { while (Serial.available()) Serial.read(); // drain report(); } // slow steady blink = idle, ready for a re-report request digitalWrite(LED_BUILTIN, HIGH); delay(500); digitalWrite(LED_BUILTIN, LOW); delay(500); }