1 | /*
|
2 | * This program attempts to initialize an SD card and analyze its structure.
|
3 | */
|
4 | #include <SPI.h>
|
5 | #include <SdFat.h>
|
6 | /*
|
7 | * SD chip select pin. Common values are:
|
8 | *
|
9 | * Arduino Ethernet shield, pin 4.
|
10 | * SparkFun SD shield, pin 8.
|
11 | * Adafruit SD shields and modules, pin 10.
|
12 | * Default SD chip select is the SPI SS pin.
|
13 | */
|
14 | const uint8_t SD_CHIP_SELECT = 5;
|
15 | /*
|
16 | * Set DISABLE_CHIP_SELECT to disable a second SPI device.
|
17 | * For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
|
18 | * to 10 to disable the Ethernet controller.
|
19 | */
|
20 | const int8_t DISABLE_CHIP_SELECT = -1;
|
21 | SdFat sd;
|
22 |
|
23 | // serial output steam
|
24 | ArduinoOutStream cout(Serial);
|
25 |
|
26 | // global for card size
|
27 | uint32_t cardSize;
|
28 |
|
29 | // global for card erase size
|
30 | uint32_t eraseSize;
|
31 | //------------------------------------------------------------------------------
|
32 | // store error strings in flash
|
33 | #define sdErrorMsg(msg) sdErrorMsg_F(F(msg));
|
34 | void sdErrorMsg_F(const __FlashStringHelper* str) {
|
35 | cout << str << endl;
|
36 | if (sd.card()->errorCode()) {
|
37 | cout << F("SD errorCode: ");
|
38 | cout << hex << int(sd.card()->errorCode()) << endl;
|
39 | cout << F("SD errorData: ");
|
40 | cout << int(sd.card()->errorData()) << dec << endl;
|
41 | }
|
42 | }
|
43 | //------------------------------------------------------------------------------
|
44 | uint8_t cidDmp() {
|
45 | cid_t cid;
|
46 | if (!sd.card()->readCID(&cid)) {
|
47 | sdErrorMsg("readCID failed");
|
48 | return false;
|
49 | }
|
50 | cout << F("\nManufacturer ID: ");
|
51 | cout << hex << int(cid.mid) << dec << endl;
|
52 | cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
|
53 | cout << F("Product: ");
|
54 | for (uint8_t i = 0; i < 5; i++) {
|
55 | cout << cid.pnm[i];
|
56 | }
|
57 | cout << F("\nVersion: ");
|
58 | cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
|
59 | cout << F("Serial number: ") << hex << cid.psn << dec << endl;
|
60 | cout << F("Manufacturing date: ");
|
61 | cout << int(cid.mdt_month) << '/';
|
62 | cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
|
63 | cout << endl;
|
64 | return true;
|
65 | }
|
66 | //------------------------------------------------------------------------------
|
67 | uint8_t csdDmp() {
|
68 | csd_t csd;
|
69 | uint8_t eraseSingleBlock;
|
70 | if (!sd.card()->readCSD(&csd)) {
|
71 | sdErrorMsg("readCSD failed");
|
72 | return false;
|
73 | }
|
74 | if (csd.v1.csd_ver == 0) {
|
75 | eraseSingleBlock = csd.v1.erase_blk_en;
|
76 | eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
|
77 | } else if (csd.v2.csd_ver == 1) {
|
78 | eraseSingleBlock = csd.v2.erase_blk_en;
|
79 | eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
|
80 | } else {
|
81 | cout << F("csd version error\n");
|
82 | return false;
|
83 | }
|
84 | eraseSize++;
|
85 | cout << F("cardSize: ") << 0.000512*cardSize;
|
86 | cout << F(" MB (MB = 1,000,000 bytes)\n");
|
87 |
|
88 | cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
|
89 | cout << F("eraseSingleBlock: ");
|
90 | if (eraseSingleBlock) {
|
91 | cout << F("true\n");
|
92 | } else {
|
93 | cout << F("false\n");
|
94 | }
|
95 | return true;
|
96 | }
|
97 | //------------------------------------------------------------------------------
|
98 | // print partition table
|
99 | uint8_t partDmp() {
|
100 | cache_t *p = sd.vol()->cacheClear();
|
101 | if (!p) {
|
102 | sdErrorMsg("cacheClear failed");
|
103 | return false;
|
104 | }
|
105 | if (!sd.card()->readBlock(0, p->data)) {
|
106 | sdErrorMsg("read MBR failed");
|
107 | return false;
|
108 | }
|
109 | for (uint8_t ip = 1; ip < 5; ip++) {
|
110 | part_t *pt = &p->mbr.part[ip - 1];
|
111 | if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
|
112 | cout << F("\nNo MBR. Assuming Super Floppy format.\n");
|
113 | return true;
|
114 | }
|
115 | }
|
116 | cout << F("\nSD Partition Table\n");
|
117 | cout << F("part,boot,type,start,length\n");
|
118 | for (uint8_t ip = 1; ip < 5; ip++) {
|
119 | part_t *pt = &p->mbr.part[ip - 1];
|
120 | cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
|
121 | cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
|
122 | }
|
123 | return true;
|
124 | }
|
125 | //------------------------------------------------------------------------------
|
126 | void volDmp() {
|
127 | cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
|
128 | cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
|
129 | cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
|
130 | cout << F("freeClusters: ");
|
131 | uint32_t volFree = sd.vol()->freeClusterCount();
|
132 | cout << volFree << endl;
|
133 | float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
|
134 | cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
|
135 | cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
|
136 | cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
|
137 | cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
|
138 | cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
|
139 | cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
|
140 | if (sd.vol()->dataStartBlock() % eraseSize) {
|
141 | cout << F("Data area is not aligned on flash erase boundaries!\n");
|
142 | cout << F("Download and use formatter from www.sdsd.card()->org/consumer!\n");
|
143 | }
|
144 | }
|
145 | //------------------------------------------------------------------------------
|
146 | void setup() {
|
147 | Serial.begin(9600);
|
148 | while(!Serial) {} // wait for Leonardo
|
149 |
|
150 | // use uppercase in hex and use 0X base prefix
|
151 | cout << uppercase << showbase << endl;
|
152 |
|
153 | // pstr stores strings in flash to save RAM
|
154 | cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
|
155 | if (DISABLE_CHIP_SELECT < 0) {
|
156 | cout << F(
|
157 | "\nAssuming the SD is the only SPI device.\n"
|
158 | "Edit DISABLE_CHIP_SELECT to disable another device.\n");
|
159 | } else {
|
160 | cout << F("\nDisabling SPI device on pin ");
|
161 | cout << int(DISABLE_CHIP_SELECT) << endl;
|
162 | pinMode(DISABLE_CHIP_SELECT, OUTPUT);
|
163 | digitalWrite(DISABLE_CHIP_SELECT, HIGH);
|
164 | }
|
165 | cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
|
166 | cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
|
167 | }
|
168 | //------------------------------------------------------------------------------
|
169 | void loop() {
|
170 | // read any existing Serial data
|
171 | while (Serial.read() >= 0) {}
|
172 |
|
173 | // pstr stores strings in flash to save RAM
|
174 | cout << F("\ntype any character to start\n");
|
175 | while (Serial.read() <= 0) {}
|
176 | delay(400); // catch Due reset problem
|
177 |
|
178 | uint32_t t = millis();
|
179 | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
180 | // breadboards. use SPI_FULL_SPEED for better performance.
|
181 | if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
|
182 | sdErrorMsg("\ncardBegin failed");
|
183 | return;
|
184 | }
|
185 | t = millis() - t;
|
186 |
|
187 | cardSize = sd.card()->cardSize();
|
188 | if (cardSize == 0) {
|
189 | sdErrorMsg("cardSize failed");
|
190 | return;
|
191 | }
|
192 | cout << F("\ninit time: ") << t << " ms" << endl;
|
193 | cout << F("\nCard type: ");
|
194 | switch (sd.card()->type()) {
|
195 | case SD_CARD_TYPE_SD1:
|
196 | cout << F("SD1\n");
|
197 | break;
|
198 |
|
199 | case SD_CARD_TYPE_SD2:
|
200 | cout << F("SD2\n");
|
201 | break;
|
202 |
|
203 | case SD_CARD_TYPE_SDHC:
|
204 | if (cardSize < 70000000) {
|
205 | cout << F("SDHC\n");
|
206 | } else {
|
207 | cout << F("SDXC\n");
|
208 | }
|
209 | break;
|
210 |
|
211 | default:
|
212 | cout << F("Unknown\n");
|
213 | }
|
214 | if (!cidDmp()) {
|
215 | return;
|
216 | }
|
217 | if (!csdDmp()) {
|
218 | return;
|
219 | }
|
220 | uint32_t ocr;
|
221 | if (!sd.card()->readOCR(&ocr)) {
|
222 | sdErrorMsg("\nreadOCR failed");
|
223 | return;
|
224 | }
|
225 | cout << F("OCR: ") << hex << ocr << dec << endl;
|
226 | if (!partDmp()) {
|
227 | return;
|
228 | }
|
229 | if (!sd.fsBegin()) {
|
230 | sdErrorMsg("\nFile System initialization failed.\n");
|
231 | return;
|
232 | }
|
233 | volDmp();
|
234 | }
|