From: Michael McMaster Date: Fri, 20 Dec 2013 11:54:41 +0000 (+1000) Subject: Read performance improvements X-Git-Tag: 3.1~4 X-Git-Url: http://git.codesrc.com/gitweb.cgi?a=commitdiff_plain;h=c8389e5ff70b709d3aa0f685541bd94da830c446;p=SCSI2SD.git Read performance improvements - More than 2x improvement in read performance, to 930KB/sec - Added compatibility for the Keil ARM compiler. Provides an additional 1.5% performance improvement. --- diff --git a/STATUS b/STATUS index 6e099b1..7074591 100644 --- a/STATUS +++ b/STATUS @@ -1,4 +1,2 @@ -- DMA is not used for SPI transfers - - Potential for large performance improvement. - Parity checking not implemented for the PSoC Datapath implementation diff --git a/readme.txt b/readme.txt index f2e9811..8236382 100644 --- a/readme.txt +++ b/readme.txt @@ -43,7 +43,7 @@ Performance As currently implemented: -Sequential read: 424kb/sec Sequential write: 414kb/sec +Sequential read: 930kb/sec Sequential write: 414kb/sec Tested with a 16GB class 10 SD card, via the commands: @@ -53,9 +53,6 @@ Tested with a 16GB class 10 SD card, via the commands: # READ TEST sudo dd bs=8192 count=100 if=/dev/sdX of=/dev/null -I am working on updating the SD card communication to use DMA, to allow simultaneous use of the SD and SCSI interfaces. I expect the performance to reach 1Mb/sec. - - Compatibility Tested with Linux (current), Apple Macintosh System 7.5.3 on LC-III, and LC-475 diff --git a/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyfit b/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyfit index 2ffb942..c6d5f47 100755 Binary files a/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyfit and b/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyfit differ diff --git a/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyprj b/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyprj index d2665e2..9bcf221 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyprj +++ b/software/SCSI2SD/SCSI2SD.cydsn/SCSI2SD.cyprj @@ -26,13 +26,6 @@ - - - - - - - @@ -204,13 +197,6 @@ - - - - - - - @@ -2584,6 +2570,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2591,7 +2909,7 @@ - + diff --git a/software/SCSI2SD/SCSI2SD.cydsn/bits.h b/software/SCSI2SD/SCSI2SD.cydsn/bits.h index 7369ce6..45adfcb 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/bits.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/bits.h @@ -24,4 +24,4 @@ extern const uint8 Lookup_OddParity[256]; uint8 countBits(uint8 value); -#endif \ No newline at end of file +#endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/blinky.c b/software/SCSI2SD/SCSI2SD.cydsn/blinky.c index 676ec5d..4d9d7ae 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/blinky.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/blinky.c @@ -28,4 +28,4 @@ void scsi2sd_test_blink(void) LED1_Write(1); CyDelay(250); // ms } -} \ No newline at end of file +} diff --git a/software/SCSI2SD/SCSI2SD.cydsn/config.c b/software/SCSI2SD/SCSI2SD.cydsn/config.c index fc1809d..674d752 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/config.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/config.c @@ -92,6 +92,9 @@ static void saveConfig() void configInit() { + int shadowRows, shadowBytes; + uint8* eeprom = (uint8*)CYDEV_EE_BASE; + // We could map cfgPtr directly into the EEPROM memory, // but that would waste power. Copy it to RAM then turn off // the EEPROM. @@ -99,9 +102,9 @@ void configInit() CyDelayUs(5); // 5us to start per datasheet. // Check magic - int shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1; - int shadowBytes = CYDEV_EEPROM_ROW_SIZE * shadowRows; - uint8* eeprom = (uint8*)CYDEV_EE_BASE; + shadowRows = (sizeof(shadow) / CYDEV_EEPROM_ROW_SIZE) + 1; + shadowBytes = CYDEV_EEPROM_ROW_SIZE * shadowRows; + if (memcmp(eeprom + shadowBytes, magic, sizeof(magic))) { saveConfig(); @@ -143,9 +146,12 @@ void configPoll() if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL) { - ledOn(); + int byteCount; + + ledOn(); + // The host sent us some data! - int byteCount = USBFS_GetEPCount(USB_EP_OUT); + byteCount = USBFS_GetEPCount(USB_EP_OUT); // Assume that byteCount <= sizeof(shadow). // shadow should be padded out to 64bytes, which is the largest diff --git a/software/SCSI2SD/SCSI2SD.cydsn/config.h b/software/SCSI2SD/SCSI2SD.cydsn/config.h index 4cb26ef..6b048bd 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/config.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/config.h @@ -36,7 +36,7 @@ typedef struct extern Config* config; -void configInit(); -void configPoll(); +void configInit(void); +void configPoll(void); #endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.c b/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.c index 3f27b83..f6899cd 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.c @@ -122,11 +122,13 @@ void scsiReceiveDiagnostic() scsiDev.dataLen = allocLength; } - uint8 lun = scsiDev.cdb[1] >> 5; - // Set the first byte to indicate LUN presence. - if (lun) // We only support lun 0 { - scsiDev.data[0] = 0x7F; + uint8 lun = scsiDev.cdb[1] >> 5; + // Set the first byte to indicate LUN presence. + if (lun) // We only support lun 0 + { + scsiDev.data[0] = 0x7F; + } } } diff --git a/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.h b/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.h index cec3f42..e3f09be 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/diagnostic.h @@ -17,7 +17,7 @@ #ifndef DIAGNOSTIC_H #define DIAGNOSTIC_H -void scsiSendDiagnostic(); -void scsiReceiveDiagnostic(); +void scsiSendDiagnostic(void); +void scsiReceiveDiagnostic(void); -#endif \ No newline at end of file +#endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/disk.c b/software/SCSI2SD/SCSI2SD.cydsn/disk.c index b5b3fd8..427112c 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/disk.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/disk.c @@ -33,7 +33,7 @@ static int doSdInit() if (result) { blockDev.state = blockDev.state | DISK_INITIALISED; - + // artificially limit this value according to EEPROM config. blockDev.capacity = (config->maxBlocks && (sdDev.capacity > config->maxBlocks)) @@ -420,10 +420,10 @@ void scsiDiskInit() if (SD_CD_Read() == 1) { + int retry; blockDev.state = blockDev.state | DISK_PRESENT; // Wait up to 5 seconds for the SD card to wake up. - int retry; for (retry = 0; retry < 5; ++retry) { if (doSdInit()) diff --git a/software/SCSI2SD/SCSI2SD.cydsn/disk.h b/software/SCSI2SD/SCSI2SD.cydsn/disk.h index 5d2d04d..2133279 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/disk.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/disk.h @@ -51,9 +51,9 @@ typedef struct extern BlockDevice blockDev; extern Transfer transfer; -void scsiDiskInit(); -void scsiDiskReset(); -void scsiDiskPoll(); -int scsiDiskCommand(); +void scsiDiskInit(void); +void scsiDiskReset(void); +void scsiDiskPoll(void); +int scsiDiskCommand(void); #endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/geometry.c b/software/SCSI2SD/SCSI2SD.cydsn/geometry.c index 5665ae5..f42152b 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/geometry.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/geometry.c @@ -91,7 +91,7 @@ uint64 scsiByteAddress(int format, const uint8* addr) } break; default: - result = -1; + result = (uint64) -1; } return result; @@ -123,10 +123,11 @@ void scsiSaveByteAddress(int format, uint64 byteAddr, uint8* buf) uint32 cyl; uint8 head; uint32 sector; + uint32 bytes; LBA2CHS(lba, &cyl, &head, §or); - uint32 bytes = sector * SCSI_SECTOR_SIZE + byteOffset; + bytes = sector * SCSI_SECTOR_SIZE + byteOffset; buf[0] = cyl >> 16; buf[1] = cyl >> 8; diff --git a/software/SCSI2SD/SCSI2SD.cydsn/inquiry.c b/software/SCSI2SD/SCSI2SD.cydsn/inquiry.c index bd7f7cd..9cc0f23 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/inquiry.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/inquiry.c @@ -98,8 +98,9 @@ void scsiInquiry() } else { + uint8* out; memcpy(scsiDev.data, StandardResponse, sizeof(StandardResponse)); - uint8* out = scsiDev.data + sizeof(StandardResponse); + out = scsiDev.data + sizeof(StandardResponse); memcpy(out, config->vendor, sizeof(config->vendor)); out += sizeof(config->vendor); memcpy(out, config->prodId, sizeof(config->prodId)); diff --git a/software/SCSI2SD/SCSI2SD.cydsn/inquiry.h b/software/SCSI2SD/SCSI2SD.cydsn/inquiry.h index d068796..c707b27 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/inquiry.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/inquiry.h @@ -17,6 +17,6 @@ #ifndef INQUIRY_H #define INQUIRY_H -void scsiInquiry(); +void scsiInquiry(void); #endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/led.h b/software/SCSI2SD/SCSI2SD.cydsn/led.h index 48e1b83..e021891 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/led.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/led.h @@ -22,4 +22,4 @@ #define ledOn() LED1_Write(0) #define ledOff() LED1_Write(1) -#endif \ No newline at end of file +#endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/loopback.c b/software/SCSI2SD/SCSI2SD.cydsn/loopback.c index ecddd64..b64405a 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/loopback.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/loopback.c @@ -72,11 +72,12 @@ static int test_data_10MHz(void) int i; for (i = 0; i < 100; ++i) { + uint8 dbx; // We write using Active High SCSI_Out_DBx_Write(0xFF); CyDelayCycles(3); // And expect an Active Low response. - uint8 dbx = SCSI_In_DBx_Read(); + dbx = SCSI_In_DBx_Read(); result = result && (dbx == 0); // We write using Active High @@ -145,4 +146,4 @@ void scsi2sd_test_loopback(void) { test_success(); } -} \ No newline at end of file +} diff --git a/software/SCSI2SD/SCSI2SD.cydsn/main.c b/software/SCSI2SD/SCSI2SD.cydsn/main.c index bb0deb6..4ae3d96 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/main.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/main.c @@ -17,7 +17,6 @@ #include "device.h" #include "blinky.h" -#include "loopback.h" #include "scsi.h" #include "scsiPhy.h" #include "config.h" @@ -38,10 +37,6 @@ int main() // Set interrupt handlers. scsiPhyInit(); - // Loopback test requires the interrupt handers. - // Will not return if uncommented. - // scsi2sd_test_loopback(); - configInit(); scsiInit(); diff --git a/software/SCSI2SD/SCSI2SD.cydsn/mode.c b/software/SCSI2SD/SCSI2SD.cydsn/mode.c index cb6d7f4..99e89b1 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/mode.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/mode.c @@ -133,6 +133,8 @@ static void doModeSense( } else { + int pageFound = 1; + ////////////// Mode Parameter Header //////////////////////////////////// @@ -195,8 +197,6 @@ static void doModeSense( scsiDev.data[idx++] = SCSI_BLOCK_SIZE & 0xFF; } - int pageFound = 1; - switch (pageCode) { case 0x3F: diff --git a/software/SCSI2SD/SCSI2SD.cydsn/mode.h b/software/SCSI2SD/SCSI2SD.cydsn/mode.h index c097807..819b1f5 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/mode.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/mode.h @@ -17,6 +17,6 @@ #ifndef MODE_H #define MODE_H -int scsiModeCommand(); +int scsiModeCommand(void); #endif diff --git a/software/SCSI2SD/SCSI2SD.cydsn/scsi.c b/software/SCSI2SD/SCSI2SD.cydsn/scsi.c index 8b69da0..245bf1d 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/scsi.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/scsi.c @@ -32,19 +32,19 @@ // Global SCSI device state. ScsiDevice scsiDev; -static void enter_SelectionPhase(); -static void process_SelectionPhase(); -static void enter_BusFree(); +static void enter_SelectionPhase(void); +static void process_SelectionPhase(void); +static void enter_BusFree(void); static void enter_MessageIn(uint8 message); -static void process_MessageIn(); +static void process_MessageIn(void); static void enter_Status(uint8 status); -static void process_Status(); +static void process_Status(void); static void enter_DataIn(int len); -static void process_DataIn(); -static void process_DataOut(); -static void process_Command(); +static void process_DataIn(void); +static void process_DataOut(void); +static void process_Command(void); -static void doReserveRelease(); +static void doReserveRelease(void); static void enter_BusFree() { @@ -109,17 +109,20 @@ static void enter_DataIn(int len) static void process_DataIn() { + uint32 len; + if (scsiDev.dataLen > sizeof(scsiDev.data)) { scsiDev.dataLen = sizeof(scsiDev.data); } - scsiEnterPhase(DATA_IN); - - uint32 len = scsiDev.dataLen - scsiDev.dataPtr; - scsiWrite(scsiDev.data + scsiDev.dataPtr, len); - scsiDev.dataPtr += len; - + len = scsiDev.dataLen - scsiDev.dataPtr; + if (len > 0) + { + scsiEnterPhase(DATA_IN); + scsiWrite(scsiDev.data + scsiDev.dataPtr, len); + scsiDev.dataPtr += len; + } if ((scsiDev.dataPtr >= scsiDev.dataLen) && (transfer.currentBlock == transfer.blocks)) @@ -130,24 +133,29 @@ static void process_DataIn() static void process_DataOut() { + uint32 len; + if (scsiDev.dataLen > sizeof(scsiDev.data)) { scsiDev.dataLen = sizeof(scsiDev.data); } - scsiEnterPhase(DATA_OUT); - scsiDev.parityError = 0; - uint32 len = scsiDev.dataLen - scsiDev.dataPtr; - scsiRead(scsiDev.data + scsiDev.dataPtr, len); - scsiDev.dataPtr += len; - - // TODO re-implement parity checking - if (0 && scsiDev.parityError && config->enableParity) + len = scsiDev.dataLen - scsiDev.dataPtr; + if (len > 0) { - scsiDev.sense.code = ABORTED_COMMAND; - scsiDev.sense.asc = SCSI_PARITY_ERROR; - enter_Status(CHECK_CONDITION); + scsiEnterPhase(DATA_OUT); + + scsiRead(scsiDev.data + scsiDev.dataPtr, len); + scsiDev.dataPtr += len; + + // TODO re-implement parity checking + if (0 && scsiDev.parityError && config->enableParity) + { + scsiDev.sense.code = ABORTED_COMMAND; + scsiDev.sense.asc = SCSI_PARITY_ERROR; + enter_Status(CHECK_CONDITION); + } } if ((scsiDev.dataPtr >= scsiDev.dataLen) && @@ -160,18 +168,23 @@ static void process_DataOut() static const uint8 CmdGroupBytes[8] = {6, 10, 10, 6, 6, 12, 6, 6}; static void process_Command() { + int group; + int cmdSize; + uint8 command; + uint8 lun; + scsiEnterPhase(COMMAND); scsiDev.parityError = 0; memset(scsiDev.cdb, 0, sizeof(scsiDev.cdb)); scsiDev.cdb[0] = scsiReadByte(); - int group = scsiDev.cdb[0] >> 5; - int cmdSize = CmdGroupBytes[group]; + group = scsiDev.cdb[0] >> 5; + cmdSize = CmdGroupBytes[group]; scsiRead(scsiDev.cdb + 1, cmdSize - 1); - uint8 command = scsiDev.cdb[0]; - uint8 lun = scsiDev.cdb[1] >> 5; + command = scsiDev.cdb[0]; + lun = scsiDev.cdb[1] >> 5; if (scsiDev.parityError) { @@ -395,15 +408,17 @@ static void process_SelectionPhase() // Save our initiator now that we're no longer in a time-critical // section. - uint8 initiatorMask = mask ^ scsiDev.scsiIdMask; - scsiDev.initiatorId = 0; - int i; - for (i = 0; i < 8; ++i) { - if (initiatorMask & (1 << i)) + int i; + uint8 initiatorMask = mask ^ scsiDev.scsiIdMask; + scsiDev.initiatorId = 0; + for (i = 0; i < 8; ++i) { - scsiDev.initiatorId = i; - break; + if (initiatorMask & (1 << i)) + { + scsiDev.initiatorId = i; + break; + } } } @@ -515,10 +530,11 @@ static void process_MessageOut() } else if (scsiDev.msgOut == 0x01) { + int i; + // Extended message. int msgLen = scsiReadByte(); if (msgLen == 0) msgLen = 256; - int i; for (i = 0; i < msgLen && !scsiDev.resetFlag; ++i) { // Discard bytes. diff --git a/software/SCSI2SD/SCSI2SD.cydsn/scsi.h b/software/SCSI2SD/SCSI2SD.cydsn/scsi.h index 91c0fa6..68ec8bd 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/scsi.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/scsi.h @@ -89,8 +89,8 @@ typedef struct // Only let the reserved initiator talk to us. // A 3rd party may be sending the RESERVE/RELEASE commands int initiatorId; // 0 -> 7. Set during the selection phase. - int reservedId;; // 0 -> 7 if reserved. -1 if not reserved. - int reserverId;; // 0 -> 7 if reserved. -1 if not reserved. + int reservedId; // 0 -> 7 if reserved. -1 if not reserved. + int reserverId; // 0 -> 7 if reserved. -1 if not reserved. // SCSI_STATUS value. // Change to SCSI_STATUS_CHECK_CONDITION when setting a SENSE value @@ -106,7 +106,7 @@ typedef struct extern ScsiDevice scsiDev; -void scsiInit(); +void scsiInit(void); void scsiPoll(void); diff --git a/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.c b/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.c index 4819615..d6d1a91 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.c @@ -52,8 +52,7 @@ uint8 scsiReadByte(void) while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 1)) {} CY_SET_REG8(scsiTarget_datapath__F0_REG, 0); while (!(CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG) & 2)) {} - uint8 value = CY_GET_REG8(scsiTarget_datapath__F1_REG); - return value; + return CY_GET_REG8(scsiTarget_datapath__F1_REG); } void scsiRead(uint8* data, uint32 count) diff --git a/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.h b/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.h index 8a37e67..658c1df 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/scsiPhy.h @@ -30,13 +30,13 @@ // Contains the odd-parity flag for a given 8-bit value. extern const uint8 Lookup_OddParity[256]; -void scsiPhyInit(); +void scsiPhyInit(void); uint8 scsiReadByte(void); void scsiRead(uint8* data, uint32 count); void scsiWriteByte(uint8 value); void scsiWrite(uint8* data, uint32 count); -uint8 scsiReadDBxPins(); +uint8 scsiReadDBxPins(void); void scsiEnterPhase(int phase); diff --git a/software/SCSI2SD/SCSI2SD.cydsn/sd.c b/software/SCSI2SD/SCSI2SD.cydsn/sd.c index 2d31294..21a8ecc 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/sd.c +++ b/software/SCSI2SD/SCSI2SD.cydsn/sd.c @@ -22,6 +22,8 @@ #include "sd.h" #include "led.h" +#include "scsiPhy.h" + #include // Global @@ -126,12 +128,13 @@ static void sdClearStatus() void sdPrepareRead() { + uint8 v; uint32 len = (transfer.lba + transfer.currentBlock); if (!sdDev.ccs) { len = len * SCSI_BLOCK_SIZE; } - uint8 v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, len); + v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, len); if (v) { scsiDiskReset(); @@ -146,13 +149,16 @@ void sdPrepareRead() void sdReadSector() { + int prep, i, guard; + // Wait for a start-block token. - // Don't wait more than 200ms. - int maxWait = 200000; + // Don't wait more than 100ms, which is the timeout recommended + // in the standard. + //100ms @ 64Hz = 6400000 + int maxWait = 6400000; uint8 token = sdSpiByte(0xFF); while (token != 0xFE && (maxWait-- > 0)) { - CyDelayUs(1); token = sdSpiByte(0xFF); } if (token != 0xFE) @@ -168,28 +174,65 @@ void sdReadSector() return; } - int prep = 0; - int i = 0; + // Don't do a bus settle delay if we're already in the correct phase. + if (transfer.currentBlock == 0) + { + scsiEnterPhase(DATA_IN); + } + + // Quickly seed the FIFO + prep = 4; + CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO + CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO + CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO + CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO + + i = 0; + guard = 0; + + // This loop is critically important for performance. + // We stream data straight from the SDCard fifos into the SCSI component + // FIFO's. If the loop isn't fast enough, the transmit FIFO's will empty, + // and performance will suffer. Every clock cycle counts. while (i < SCSI_BLOCK_SIZE) { - if (prep < SCSI_BLOCK_SIZE && (SDCard_ReadTxStatus() & SDCard_STS_TX_FIFO_NOT_FULL)) + uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR); + uint8_t scsiStatus = CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG); + + // Read from the SPIM fifo if there is room to stream the byte to the + // SCSI fifos + if((sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY) && + (scsiStatus & 1) // SCSI TX FIFO NOT FULL + ) { - SDCard_WriteTxData(0xFF); - prep++; + uint8_t val = CY_GET_REG8(SDCard_RXDATA_PTR); + CY_SET_REG8(scsiTarget_datapath__F0_REG, val); + guard++; } - if(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY) + // Byte has been sent out the SCSI interface. + if (scsiStatus & 2) // SCSI RX FIFO NOT EMPTY { - scsiDev.data[i] = SDCard_ReadRxData(); - i++; + CY_GET_REG8(scsiTarget_datapath__F1_REG); + ++i; } - } + // How many bytes are in a 4-byte FIFO ? 5. 4 FIFO bytes PLUS one byte + // being processed bit-by-bit. Artifically limit the number of bytes in the + // "combined" SPIM TX and RX FIFOS to the individual FIFO size. + // Unlike the SCSI component, SPIM doesn't check if there's room in + // the output FIFO before starting to transmit. + if ((prep - guard < 4) && (prep < SCSI_BLOCK_SIZE)) + { + CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO + prep++; + } + } sdSpiByte(0xFF); // CRC sdSpiByte(0xFF); // CRC scsiDev.dataLen = SCSI_BLOCK_SIZE; - scsiDev.dataPtr = 0; + scsiDev.dataPtr = SCSI_BLOCK_SIZE; } void sdCompleteRead() @@ -200,8 +243,9 @@ void sdCompleteRead() // an error condition as we're trying to read past-the-end of the storage // device. // ie. do not use sdCommandAndResponse here. + uint8 r1b; sdSendCommand(SD_STOP_TRANSMISSION, 0); - uint8 r1b = sdReadResp(); + r1b = sdReadResp(); if (r1b) { @@ -212,7 +256,7 @@ void sdCompleteRead() r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0); retries--; } - + scsiDev.status = CHECK_CONDITION; scsiDev.sense.code = HARDWARE_ERROR; scsiDev.sense.asc = UNRECOVERED_READ_ERROR; @@ -220,11 +264,13 @@ void sdCompleteRead() } // R1b has an optional trailing "busy" signal. - uint8 busy; - do { - busy = sdSpiByte(0xFF); - } while (busy == 0); + uint8 busy; + do + { + busy = sdSpiByte(0xFF); + } while (busy == 0); + } } static void sdWaitWriteBusy() @@ -238,12 +284,13 @@ static void sdWaitWriteBusy() int sdWriteSector() { - int result; + int result, i, maxWait; + uint8 dataToken; + // Wait for a previously-written sector to complete. sdWaitWriteBusy(); sdSpiByte(0xFC); // MULTIPLE byte start token - int i; for (i = 0; i < SCSI_BLOCK_SIZE; i++) { while(!(SDCard_ReadTxStatus() & SDCard_STS_TX_FIFO_NOT_FULL)) @@ -252,30 +299,31 @@ int sdWriteSector() } while(!(SDCard_ReadTxStatus() & SDCard_STS_SPI_DONE)) {} SDCard_ClearFIFO(); - + sdSpiByte(0x00); // CRC sdSpiByte(0x00); // CRC - // Don't wait more than 1000ms. + // Don't wait more than 1s. // My 2g Kingston micro-sd card doesn't respond immediately. // My 16Gb card does. - int maxWait = 1000; - uint8 dataToken = sdSpiByte(0xFF); // Response + maxWait = 1000000; + dataToken = sdSpiByte(0xFF); // Response while (dataToken == 0xFF && maxWait-- > 0) { - CyDelay(1); // 1ms. + CyDelayUs(1); dataToken = sdSpiByte(0xFF); } if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted. { + uint8 r1b, busy; + sdWaitWriteBusy(); - uint8 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0); + r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0); (void) r1b; sdSpiByte(0xFF); // R1b has an optional trailing "busy" signal. - uint8 busy; do { busy = sdSpiByte(0xFF); @@ -305,6 +353,8 @@ int sdWriteSector() void sdCompleteWrite() { + uint8 r1, r2; + // Wait for a previously-written sector to complete. sdWaitWriteBusy(); @@ -312,8 +362,8 @@ void sdCompleteWrite() // Wait for the card to come out of busy. sdWaitWriteBusy(); - uint8 r1 = sdCommandAndResponse(13, 0); // send status - uint8 r2 = sdSpiByte(0xFF); + r1 = sdCommandAndResponse(13, 0); // send status + r2 = sdSpiByte(0xFF); if (r1 || r2) { sdClearStatus(); @@ -381,11 +431,12 @@ static int sdOpCond() static int sdReadOCR() { + uint8 buf[4]; + int i; + uint8 status = sdCRCCommandAndResponse(SD_READ_OCR, 0); if(status){goto bad;} - uint8 buf[4]; - int i; for (i = 0; i < 4; ++i) { buf[i] = sdSpiByte(0xFF); @@ -400,19 +451,20 @@ bad: static int sdReadCSD() { + uint8 startToken; + int maxWait, i; + uint8 buf[16]; + uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0); if(status){goto bad;} - - uint8 startToken; - int maxWait = 1023; + + maxWait = 1023; do { startToken = sdSpiByte(0xFF); } while(maxWait-- && (startToken != 0xFE)); if (startToken != 0xFE) { goto bad; } - uint8 buf[16]; - int i; for (i = 0; i < 16; ++i) { buf[i] = sdSpiByte(0xFF); @@ -452,18 +504,20 @@ bad: int sdInit() { + int result = 0; + int i; + uint8 v; + sdDev.version = 0; sdDev.ccs = 0; sdDev.capacity = 0; - int result = 0; SD_CS_Write(1); // Set CS inactive (active low) SD_Init_Clk_Start(); // Turn on the slow 400KHz clock SD_Clk_Ctl_Write(0); // Select the 400KHz clock source. SDCard_Start(); // Enable SPI hardware // Power on sequence. 74 clock cycles of a "1" while CS unasserted. - int i; for (i = 0; i < 10; ++i) { sdSpiByte(0xFF); @@ -472,7 +526,7 @@ int sdInit() SD_CS_Write(0); // Set CS active (active low) CyDelayUs(1); - uint8 v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0); + v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0); if(v != 1){goto bad;} ledOn(); @@ -525,6 +579,9 @@ out: void sdPrepareWrite() { + uint32 len; + uint8 v; + // Set the number of blocks to pre-erase by the multiple block write command // We don't care about the response - if the command is not accepted, writes // will just be a bit slower. @@ -533,12 +590,12 @@ void sdPrepareWrite() sdCommandAndResponse(SD_APP_CMD, 0); sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks); - uint32 len = (transfer.lba + transfer.currentBlock); + len = (transfer.lba + transfer.currentBlock); if (!sdDev.ccs) { len = len * SCSI_BLOCK_SIZE; } - uint8 v = sdCommandAndResponse(25, len); + v = sdCommandAndResponse(25, len); if (v) { scsiDiskReset(); diff --git a/software/SCSI2SD/SCSI2SD.cydsn/sd.h b/software/SCSI2SD/SCSI2SD.cydsn/sd.h index b8e3c31..7cdca9a 100755 --- a/software/SCSI2SD/SCSI2SD.cydsn/sd.h +++ b/software/SCSI2SD/SCSI2SD.cydsn/sd.h @@ -54,13 +54,13 @@ typedef struct extern SdDevice sdDev; -int sdInit(); -void sdPrepareWrite(); -int sdWriteSector(); -void sdCompleteWrite(); +int sdInit(void); +void sdPrepareWrite(void); +int sdWriteSector(void); +void sdCompleteWrite(void); -void sdPrepareRead(); -void sdReadSector(); -void sdCompleteRead(); +void sdPrepareRead(void); +void sdReadSector(void); +void sdCompleteRead(void); #endif