2014-07-12 13:45:56 +00:00
/*
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 <math.h>
# include <avr/io.h>
# include <avr/pgmspace.h>
# include <avr/interrupt.h>
# include <util/delay.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# 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 ; i < writeBlockPow ; i + + )
{
writeBlock * = 2 ;
}
uint32_t sectorSize = writeBlock * sectorSizeCnt ;
sectorSize / = 1024 ;
snprintf ( textBuf , TEXTBUF_SIZE , " BLK %luB ERASE %luK " , writeBlock , sectorSize ) ;
LcdGoto ( 0 , 1 ) ;
LcdTinyString ( textBuf , TEXT_NORMAL ) ;
LcdGoto ( 0 , 2 ) ;
SdBaseFile f ;
if ( ! f . open ( " TESTFILE.DAT " , O_RDWR ) )
{
LcdTinyStringP ( PSTR ( " TESTFILE.DAT missing " ) , TEXT_NORMAL ) ;
while ( 1 ) ;
}
// get address of file on SD
uint32_t imageFirstBlock , imageLastBlock ;
if ( ! f . contiguousRange ( & imageFirstBlock , & imageLastBlock ) )
{
LcdTinyStringP ( PSTR ( " file not contiguous " ) , TEXT_NORMAL ) ;
while ( 1 ) ;
}
if ( f . fileSize ( ) < ( unsigned long ) 1024 * 1024 )
{
LcdTinyStringP ( PSTR ( " file too small " ) , TEXT_NORMAL ) ;
while ( 1 ) ;
}
f . close ( ) ;
LcdTinyStringP ( PSTR ( " Testing... " ) , TEXT_NORMAL ) ;
uint32_t writeCount = 0 ;
uint32_t writeTotalTime = 0 ;
uint32_t worstTime = 0 ;
uint32_t above20Count = 0 ;
for ( int trial = 0 ; trial < 3 ; trial + + )
{
uint32_t b = 0 ;
for ( uint32_t cnt = 0 ; cnt < 1600 & & b < 1600 ; cnt + + )
{
if ( ! sd . card ( ) - > readBlock ( 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 < < STATUS_LED_PIN ) ;
uint32_t t0 ;
_delay_ms ( 3 ) ;
// write it
t0 = millis ( ) ;
if ( ! sd . card ( ) - > 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 ) ;
}