164 lines
5.6 KiB
Arduino
164 lines
5.6 KiB
Arduino
// 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 <SD.h>
|
|
|
|
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);
|
|
}
|