sd card: what the card says it is, from its CID register

Type, size, and the identity register read by our SD driver (CMD10):
manufacturer, OEM, product name, revision, serial and date, decoded by a
host-tested parser. Needed for the upstream report of #21: nothing else
here could read the card's identity. This one is a Samsung 8 GB SDHC
from June 2013.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-05 23:15:29 +02:00
co-authored by Claude Opus 5.5
parent 3f2650c56e
commit 370f067fbf
7 changed files with 173 additions and 1 deletions
+20
View File
@@ -920,6 +920,26 @@ uint32_t sdcard_sector_size(uint8_t pdrv) {
return 512;
}
// roro: the card's CID. CMD10 in SPI mode (the enum's SEND_CID, 2, is the SD-mode command).
namespace roro {
bool sdReadCid(uint8_t cid[16]) {
for (uint8_t pdrv = 0; pdrv < FF_VOLUMES; ++pdrv) {
ardu_sdcard_t *card = s_cards[pdrv];
if (!card) {
continue;
}
AcquireSPI lock(card);
if (!sdSelectCard(pdrv)) {
return false;
}
bool ok = !sdCommand(pdrv, 10, 0, NULL) && sdReadBytes(pdrv, (char *)cid, 16);
sdDeselectCard(pdrv);
return ok;
}
return false;
}
} // namespace roro
sdcard_type_t sdcard_type(uint8_t pdrv) {
ardu_sdcard_t *card = s_cards[pdrv];
if (pdrv >= FF_VOLUMES || card == NULL) {
+4
View File
@@ -26,4 +26,8 @@ struct SdFault {
SdFault sdLastFault();
// The mounted card's identity register (CID, CMD10): who made it, its name, serial and date.
// Call it where card access is allowed (the storage task).
bool sdReadCid(uint8_t cid[16]);
} // namespace roro
+53
View File
@@ -0,0 +1,53 @@
#include "sd_card_id.h"
#include <cstdio>
namespace roro {
namespace {
char printable(uint8_t b) { return b >= 0x20 && b < 0x7F ? static_cast<char>(b) : '?'; }
} // namespace
SdCardId parseSdCid(const uint8_t cid[16]) {
SdCardId id;
id.manufacturer = cid[0];
for (int i = 0; i < 2; ++i) id.oem[i] = printable(cid[1 + i]);
for (int i = 0; i < 5; ++i) id.product[i] = printable(cid[3 + i]);
id.revisionMajor = cid[8] >> 4;
id.revisionMinor = cid[8] & 0x0F;
id.serial = static_cast<uint32_t>(cid[9]) << 24 | cid[10] << 16 | cid[11] << 8 | cid[12];
// 4 reserved bits, 8 bits of year since 2000, 4 bits of month.
id.year = 2000 + (((cid[13] & 0x0F) << 4) | (cid[14] >> 4));
id.month = cid[14] & 0x0F;
return id;
}
const char* sdManufacturerName(uint8_t id) {
switch (id) {
case 0x01: return "Panasonic";
case 0x02: return "Toshiba/Kioxia";
case 0x03: return "SanDisk";
case 0x1B: return "Samsung";
case 0x1D: return "ADATA";
case 0x27: return "Phison";
case 0x28: return "Lexar";
case 0x31: return "Silicon Power";
case 0x41: return "Kingston";
case 0x74: return "Transcend";
case 0x76: return "Patriot";
case 0x82: return "Sony";
case 0x9C: return "Angelbird/Hoodman";
case 0xAD: return "Longsys/Lexar";
default: return "unknown";
}
}
std::string sdCardSummary(const SdCardId& id) {
char s[112];
std::snprintf(s, sizeof s, "%s (0x%02X) \"%s\" \"%s\" rev %u.%u, serial %08x, made %04d-%02d",
sdManufacturerName(id.manufacturer), id.manufacturer, id.oem, id.product, id.revisionMajor,
id.revisionMinor, static_cast<unsigned>(id.serial), id.year, id.month);
return s;
}
} // namespace roro
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
#include <string>
namespace roro {
// What an SD card says it is: its CID register, 16 bytes (SD Physical Layer spec, 5.2).
struct SdCardId {
uint8_t manufacturer = 0; // assigned by the SD Association; see sdManufacturerName()
char oem[3] = {}; // two characters
char product[6] = {}; // five characters
uint8_t revisionMajor = 0, revisionMinor = 0;
uint32_t serial = 0;
int year = 0, month = 0; // manufactured
};
SdCardId parseSdCid(const uint8_t cid[16]);
// The usual holder of a manufacturer ID. The SD Association doesn't publish its list: these are
// the commonly reported ones, and resold or counterfeit cards carry whatever their maker chose.
const char* sdManufacturerName(uint8_t id);
// "SanDisk (0x03) "SD" "SU08G" rev 8.0, serial 1234abcd, made 2014-03".
std::string sdCardSummary(const SdCardId& id);
} // namespace roro