/* Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported license. (CC BY-NC 3.0) The terms of the license may be viewed at http://creativecommons.org/licenses/by-nc/3.0/ Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ Permissions beyond the scope of this license may be available at www.bigmessowires.com or from mailto:steve@bigmessowires.com. */ #include #include #include #include #include #include #include #include #include "portmacros.h" #include "noklcd.h" #include "millitimer.h" #include "SdFat.h" #include "SdBaseFile.h" #include "micro.h" #include "ports.h" #include "diskmenu.h" #include "cardtest.h" #ifdef PROGMEM_WORKAROUND // work-around for compiler bug #undef PROGMEM #define PROGMEM __attribute__(( section(".progmem.data") )) #undef PSTR #define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) #endif #define STATUS_LED_PORT B #define STATUS_LED_PIN 3 #define TEXTBUF_SIZE 22 extern char textBuf[]; extern uint8_t sectorBuf[512]; void CardTest() { LcdClear(); SdFat sd; if (!sd.init(SPI_HALF_SPEED)) { snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData()); LcdGoto(0,0); LcdTinyString(textBuf, TEXT_NORMAL); while(1); } cid_t cid; uint32_t cardSize = sd.card()->cardSize(); cardSize /= (2L*1024L); sd.card()->readCID(&cid); snprintf(textBuf, TEXTBUF_SIZE, "CID %d %c%c%c%c%c %lu MB", cid.mid, cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cardSize); LcdGoto(0,0); LcdTinyString(textBuf, TEXT_NORMAL); csd_t csd; sd.card()->readCSD(&csd); uint8_t writeBlockPow; // write block length, log2 uint8_t sectorSizeCnt; // minimum erasable size, in write blocks if (csd.v1.csd_ver == 1) { csd1_t* c = &csd.v1; writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low; sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low; } else { csd2_t* c = &csd.v2; writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low; sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low; } sectorSizeCnt += 1; // these all seem to be 2**n - 1? uint32_t writeBlock=1; for (uint8_t i=0; ireadBlock(imageFirstBlock + b, sectorBuf)) { LcdGoto(0,2); LcdTinyStringP(PSTR("SD read error"), TEXT_NORMAL); while(1); } // alter the data, to prevent any kind of compression/optimization on the card for (uint16_t i=0; i<512; i++) { sectorBuf[i] ^= sectorBuf[i+1]; } // blink the LED if ((writeCount & 0x7) == 0) PORT(STATUS_LED_PORT) ^= (1<writeBlock(imageFirstBlock + b, sectorBuf)) { LcdGoto(0,2); LcdTinyStringP(PSTR("SD write error"), TEXT_NORMAL); while(1); } uint32_t writeTime = millis() - t0; // update stats writeCount++; writeTotalTime += writeTime; if (writeTime > 20) above20Count++; if (writeTime > worstTime) worstTime = writeTime; // pseudo-interleave if ((cnt & 1) == 0) b += 6; else b -= 5; _delay_ms(3); } } uint32_t avg = (writeTotalTime + (writeCount >> 1))/ writeCount; LcdGoto(0,2); LcdTinyStringP(PSTR("AVG.ms/MAX.ms/LONG.%"), TEXT_NORMAL); snprintf(textBuf, TEXTBUF_SIZE, "512B RRWI %lu/%lu/%lu", avg, worstTime, above20Count*100/writeCount); LcdGoto(0,3); LcdTinyString(textBuf, TEXT_NORMAL); // Card: actual capacity, block size, erase size, best test result (random read-write interleaved) average/max/percent "long" over 20ms // ---------------------------------------------------------- // PNY class 10 8GB: 7708 MB, 512B block, 64K erase. 512B RRWI 10/189/1 (random read-write interleave) // SanDisk unrated Ultra II 2GB: 1938 MB, 1024B block, 32K erase. 512B RRWI 7/79/0 // Transcend unrated 2GB: 1875 MB, 1024B block, 128K erase. 512B RRWI 3/103/0 // SanDisk unrated 128MB: 120 MB, 512B block, 16K erase. 512B RRWI 5/94/1 // enabling the TACH stuff seems to cause some cards to get errors during this test. Coupling between traces? Why doesn't it happen during normal operation? // Transcend unrated 2GB: Finder consistently "goes to sleep" after copying first 19 tracks, but worked twice after 3 tries. Maybe it's too fast? while(1); }