Files
n_signer/firmware/teensy41/sd_test/sd_test.ino
T

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);
}