Use DMA for SCSI and SD card transfers for a massive performance boost.
[SCSI2SD-V6.git] / software / SCSI2SD / src / sd.c
index f11d2e02eeb5d65d29845221a58058b53ba1d8b5..19e02fde944da55ec9e5f42e8b5c477a4d59ce6b 100755 (executable)
 // Global\r
 SdDevice sdDev;\r
 \r
+// Private DMA variables.\r
+static int dmaInProgress = 0;\r
+static uint8 sdDMARxChan = CY_DMA_INVALID_CHANNEL;\r
+static uint8 sdDMATxChan = CY_DMA_INVALID_CHANNEL;\r
+\r
+// DMA descriptors\r
+static uint8 sdDMARxTd[1] = { CY_DMA_INVALID_TD };\r
+static uint8 sdDMATxTd[1] = { CY_DMA_INVALID_TD };\r
+\r
+// Dummy location for DMA to send unchecked CRC bytes to\r
+static uint8 discardBuffer;\r
+\r
+// Source of dummy SPI bytes for DMA\r
+static uint8 dummyBuffer = 0xFF;\r
+\r
+volatile static uint8 rxDMAComplete;\r
+volatile static uint8 txDMAComplete;\r
+\r
+CY_ISR_PROTO(sdRxISR);\r
+CY_ISR(sdRxISR)\r
+{\r
+       rxDMAComplete = 1;\r
+}\r
+CY_ISR_PROTO(sdTxISR);\r
+CY_ISR(sdTxISR)\r
+{\r
+       txDMAComplete = 1;\r
+}\r
+\r
 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
 {\r
        uint8 a;\r
@@ -126,12 +155,13 @@ static void sdClearStatus()
 }\r
 \r
 \r
-void sdPrepareRead()\r
+void\r
+sdReadMultiSectorPrep()\r
 {\r
        uint8 v;\r
        uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
        uint32 sdLBA = SCSISector2SD(scsiLBA);\r
-       \r
+\r
        if (!sdDev.ccs)\r
        {\r
                sdLBA = sdLBA * SD_SECTOR_SIZE;\r
@@ -153,10 +183,9 @@ void sdPrepareRead()
        }\r
 }\r
 \r
-static void doReadSector(uint32_t numBytes)\r
+static void\r
+dmaReadSector(uint8_t* outputBuffer)\r
 {\r
-       int prep, i, guard;\r
-\r
        // Wait for a start-block token.\r
        // Don't wait more than 100ms, which is the timeout recommended\r
        // in the standard.\r
@@ -183,93 +212,60 @@ static void doReadSector(uint32_t numBytes)
                return;\r
        }\r
 \r
-       scsiEnterPhase(DATA_IN);\r
+       CyDmaTdSetConfiguration(sdDMARxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, TD_INC_DST_ADR | SD_RX_DMA__TD_TERMOUT_EN);\r
+       CyDmaTdSetAddress(sdDMARxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)outputBuffer));\r
+       CyDmaTdSetConfiguration(sdDMATxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
+       CyDmaTdSetAddress(sdDMATxTd[0], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
 \r
-       // Quickly seed the FIFO\r
-       prep = 4;\r
-       CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
-       CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
-       CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
-       CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
-       \r
-       i = 0;\r
-       guard = 0;\r
-       \r
-       // This loop is critically important for performance.\r
-       // We stream data straight from the SDCard fifos into the SCSI component\r
-       // FIFO's. If the loop isn't fast enough, the transmit FIFO's will empty,\r
-       // and performance will suffer. Every clock cycle counts.\r
-       while (i < numBytes && !scsiDev.resetFlag)\r
-       {\r
-               uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
-               uint8_t scsiStatus = CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG);\r
-\r
-               // Read from the SPIM fifo if there is room to stream the byte to the\r
-               // SCSI fifos\r
-               if((sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY) &&\r
-                       (scsiStatus & 1) // SCSI TX FIFO NOT FULL\r
-                       )\r
-               {\r
-                       uint8_t val = CY_GET_REG8(SDCard_RXDATA_PTR);\r
-                       CY_SET_REG8(scsiTarget_datapath__F0_REG, val);\r
-                       guard++;\r
+       dmaInProgress = 1;\r
+       // The DMA controller is a bit trigger-happy. It will retain\r
+       // a drq request that was triggered while the channel was\r
+       // disabled.\r
+       CyDmaClearPendingDrq(sdDMATxChan);\r
+       CyDmaClearPendingDrq(sdDMARxChan);\r
 \r
-                       // How many bytes are in a 4-byte FIFO ? 5.  4 FIFO bytes PLUS one byte\r
-                       // being processed bit-by-bit. Artifically limit the number of bytes in the \r
-                       // "combined" SPIM TX and RX FIFOS to the individual FIFO size.\r
-                       // Unlike the SCSI component, SPIM doesn't check if there's room in\r
-                       // the output FIFO before starting to transmit.\r
+       txDMAComplete = 0;\r
+       rxDMAComplete = 0;\r
 \r
-                       if (prep < numBytes)\r
-                       {\r
-                               CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
-                               prep++;\r
-                       }\r
+       // Re-loading the initial TD's here is very important, or else\r
+       // we'll be re-using the last-used TD, which would be the last\r
+       // in the chain (ie. CRC TD)\r
+       CyDmaChSetInitialTd(sdDMARxChan, sdDMARxTd[0]);\r
+       CyDmaChSetInitialTd(sdDMATxChan, sdDMATxTd[0]);\r
 \r
-               }\r
-                                       \r
-               // Byte has been sent out the SCSI interface.\r
-               if (scsiStatus & 2) // SCSI RX FIFO NOT EMPTY\r
-               {\r
-                       CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
-                       ++i;\r
-               }\r
-       }\r
+       // There is no flow control, so we must ensure we can read the bytes\r
+       // before we start transmitting\r
+       CyDmaChEnable(sdDMARxChan, 1);\r
+       CyDmaChEnable(sdDMATxChan, 1);\r
+}\r
 \r
-       // Read and discard remaining bytes. This applis for non-512 byte sectors,\r
-       // or if a SCSI reset was triggered.\r
-       while (guard < SD_SECTOR_SIZE)\r
+int\r
+sdReadSectorDMAPoll()\r
+{\r
+       if (rxDMAComplete && txDMAComplete)\r
        {\r
-               uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
-               if(sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY)\r
-               {\r
-                       CY_GET_REG8(SDCard_RXDATA_PTR);\r
-                       guard++;\r
-               }\r
+               // DMA transfer is complete\r
+               dmaInProgress = 0;\r
 \r
-               if ((prep - guard < 4) && (prep < SD_SECTOR_SIZE))\r
-               {\r
-                       CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
-                       prep++;\r
-               }\r
-       }\r
+               sdSpiByte(0xFF); // CRC\r
+               sdSpiByte(0xFF); // CRC\r
 \r
-       sdSpiByte(0xFF); // CRC\r
-       sdSpiByte(0xFF); // CRC\r
-       scsiDev.dataLen = numBytes;\r
-       scsiDev.dataPtr = numBytes;\r
-       \r
-       while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
+               return 1;\r
+       }\r
+       else\r
+       {\r
+               return 0;\r
+       }\r
 }\r
 \r
-static void doReadSectorSingle(uint32 sdBlock, int sdBytes)\r
+void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer)\r
 {\r
        uint8 v;\r
        if (!sdDev.ccs)\r
        {\r
-               sdBlock = sdBlock * SD_SECTOR_SIZE;\r
-       }       \r
-       v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, sdBlock);\r
+               lba = lba * SD_SECTOR_SIZE;\r
+       }\r
+       v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, lba);\r
        if (v)\r
        {\r
                scsiDiskReset();\r
@@ -282,52 +278,28 @@ static void doReadSectorSingle(uint32 sdBlock, int sdBytes)
        }\r
        else\r
        {\r
-               doReadSector(sdBytes);\r
+               dmaReadSector(outputBuffer);\r
        }\r
 }\r
 \r
-\r
-void sdReadSectorSingle()\r
+void\r
+sdReadMultiSectorDMA(uint8_t* outputBuffer)\r
 {\r
-       uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
-       uint32 sdLBA = SCSISector2SD(scsiLBA);\r
-       \r
-       int sdSectors = SDSectorsPerSCSISector();\r
-       int i;\r
-       for (i = 0; (i < sdSectors - 1) && (scsiDev.status != CHECK_CONDITION); ++i)\r
-       {\r
-               doReadSectorSingle(sdLBA + i, SD_SECTOR_SIZE);\r
-       }\r
-\r
-       if (scsiDev.status != CHECK_CONDITION)\r
-       {\r
-               int remaining = config->bytesPerSector % SD_SECTOR_SIZE;\r
-               if (remaining == 0) remaining = SD_SECTOR_SIZE; // Full sector needed.\r
-               doReadSectorSingle(sdLBA + i, remaining);\r
-       }\r
+       // Pre: sdReadMultiSectorPrep called.\r
+       dmaReadSector(outputBuffer);\r
 }\r
 \r
-void sdReadSectorMulti()\r
-{\r
-       // Pre: sdPrepareRead called.\r
-       int sdSectors = SDSectorsPerSCSISector();\r
-       int i;\r
-       for (i = 0; (i < sdSectors - 1) && (scsiDev.status != CHECK_CONDITION); ++i)\r
-       {\r
-               doReadSector(SD_SECTOR_SIZE);\r
-       }\r
 \r
-       if (scsiDev.status != CHECK_CONDITION)\r
+void sdCompleteRead()\r
+{\r
+       if (dmaInProgress)\r
        {\r
-               int remaining = config->bytesPerSector % SD_SECTOR_SIZE;\r
-               if (remaining == 0) remaining = SD_SECTOR_SIZE; // Full sector needed.\r
-               doReadSector(remaining);\r
+               // Not much choice but to wait until we've completed the transfer.\r
+               // Cancelling the transfer can't be done as we have no way to reset\r
+               // the SD card.\r
+               while (!sdReadSectorDMAPoll()) { /* spin */ }\r
        }\r
-}\r
 \r
-\r
-void sdCompleteRead()\r
-{\r
        transfer.inProgress = 0;\r
 \r
        // We cannot send even a single "padding" byte, as we normally would when\r
@@ -375,152 +347,110 @@ static void sdWaitWriteBusy()
        } while (val != 0xFF);\r
 }\r
 \r
-static int doWriteSector(uint32_t numBytes)\r
+void\r
+sdWriteMultiSectorDMA(uint8_t* outputBuffer)\r
 {\r
-       int prep, i, guard;\r
-       int result, maxWait;\r
-       uint8 dataToken;\r
-\r
-       scsiEnterPhase(DATA_OUT);\r
-       \r
        sdSpiByte(0xFC); // MULTIPLE byte start token\r
-       \r
-       prep = 0;\r
-       i = 0;\r
-       guard = 0;\r
-\r
-       // This loop is critically important for performance.\r
-       // We stream data straight from the SCSI fifos into the SPIM component\r
-       // FIFO's. If the loop isn't fast enough, the transmit FIFO's will empty,\r
-       // and performance will suffer. Every clock cycle counts.       \r
-       while (i < numBytes && !scsiDev.resetFlag)\r
-       {\r
-               uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
-               uint8_t scsiStatus = CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG);\r
-\r
-               // Read from the SCSI fifo if there is room to stream the byte to the\r
-               // SPIM fifos\r
-               // See sdReadSector for comment on guard (FIFO size is really 5)\r
-               if((guard - i < 4) &&\r
-                       (scsiDev.resetFlag || (scsiStatus & 2))\r
-                       ) // SCSI RX FIFO NOT EMPTY\r
-               {\r
-                       uint8_t val = CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
-                       CY_SET_REG8(SDCard_TXDATA_PTR, val);\r
-                       guard++;\r
-               }\r
-\r
-               // Byte has been sent out the SPIM interface.\r
-               if (sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY)\r
-               {\r
-                        CY_GET_REG8(SDCard_RXDATA_PTR);\r
-                       ++i;\r
-               }\r
 \r
-               if (prep < numBytes &&\r
-                       (scsiDev.resetFlag || (scsiStatus & 1)) // SCSI TX FIFO NOT FULL\r
-                       )\r
-               {\r
-                       // Trigger the SCSI component to read a byte\r
-                       CY_SET_REG8(scsiTarget_datapath__F0_REG, 0xFF);\r
-                       prep++;\r
-               }\r
-       }\r
+       CyDmaTdSetConfiguration(sdDMATxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, TD_INC_SRC_ADR | SD_TX_DMA__TD_TERMOUT_EN);\r
+       CyDmaTdSetAddress(sdDMATxTd[0], LO16((uint32)outputBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
+       CyDmaTdSetConfiguration(sdDMARxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
+       CyDmaTdSetAddress(sdDMARxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
        \r
-       // Write remaining bytes as 0x00\r
-       while (i < SD_SECTOR_SIZE)\r
+       dmaInProgress = 1;\r
+       // The DMA controller is a bit trigger-happy. It will retain\r
+       // a drq request that was triggered while the channel was\r
+       // disabled.\r
+       CyDmaClearPendingDrq(sdDMATxChan);\r
+       CyDmaClearPendingDrq(sdDMARxChan);\r
+\r
+       txDMAComplete = 0;\r
+       rxDMAComplete = 0;\r
+\r
+       // Re-loading the initial TD's here is very important, or else\r
+       // we'll be re-using the last-used TD, which would be the last\r
+       // in the chain (ie. CRC TD)\r
+       CyDmaChSetInitialTd(sdDMARxChan, sdDMARxTd[0]);\r
+       CyDmaChSetInitialTd(sdDMATxChan, sdDMATxTd[0]);\r
+\r
+       // There is no flow control, so we must ensure we can read the bytes\r
+       // before we start transmitting\r
+       CyDmaChEnable(sdDMARxChan, 1);\r
+       CyDmaChEnable(sdDMATxChan, 1);\r
+}\r
+\r
+int\r
+sdWriteSectorDMAPoll()\r
+{\r
+       if (rxDMAComplete && txDMAComplete)\r
        {\r
-               uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
+               // DMA transfer is complete\r
+               dmaInProgress = 0;\r
 \r
-               if((guard - i < 4) && (guard < SD_SECTOR_SIZE))\r
-               {\r
-                       CY_SET_REG8(SDCard_TXDATA_PTR, 0x00);\r
-                       guard++;\r
-               }\r
+               sdSpiByte(0x00); // CRC\r
+               sdSpiByte(0x00); // CRC\r
 \r
-               // Byte has been sent out the SPIM interface.\r
-               if (sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY)\r
+               // Don't wait more than 1s.\r
+               // My 2g Kingston micro-sd card doesn't respond immediately.\r
+               // My 16Gb card does.\r
+               int maxWait = 1000000;\r
+               uint8_t dataToken = sdSpiByte(0xFF); // Response\r
+               while (dataToken == 0xFF && maxWait-- > 0)\r
                {\r
-                        CY_GET_REG8(SDCard_RXDATA_PTR);\r
-                       ++i;\r
+                       CyDelayUs(1);\r
+                       dataToken = sdSpiByte(0xFF);\r
                }\r
-       }\r
-       \r
-       sdSpiByte(0x00); // CRC\r
-       sdSpiByte(0x00); // CRC\r
-\r
-       // Don't wait more than 1s.\r
-       // My 2g Kingston micro-sd card doesn't respond immediately.\r
-       // My 16Gb card does.\r
-       maxWait = 1000000;\r
-       dataToken = sdSpiByte(0xFF); // Response\r
-       while (dataToken == 0xFF && maxWait-- > 0)\r
-       {\r
-               CyDelayUs(1);\r
-               dataToken = sdSpiByte(0xFF);\r
-       }\r
-       if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
-       {\r
-               uint8 r1b, busy;\r
+               if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
+               {\r
+                       uint8 r1b, busy;\r
                \r
-               sdWaitWriteBusy();\r
+                       sdWaitWriteBusy();\r
 \r
-               r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
-               (void) r1b;\r
-               sdSpiByte(0xFF);\r
+                       r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
+                       (void) r1b;\r
+                       sdSpiByte(0xFF);\r
 \r
-               // R1b has an optional trailing "busy" signal.\r
-               do\r
-               {\r
-                       busy = sdSpiByte(0xFF);\r
-               } while (busy == 0);\r
+                       // R1b has an optional trailing "busy" signal.\r
+                       do\r
+                       {\r
+                               busy = sdSpiByte(0xFF);\r
+                       } while (busy == 0);\r
 \r
-               // Wait for the card to come out of busy.\r
-               sdWaitWriteBusy();\r
+                       // Wait for the card to come out of busy.\r
+                       sdWaitWriteBusy();\r
 \r
-               transfer.inProgress = 0;\r
-               scsiDiskReset();\r
-               sdClearStatus();\r
+                       transfer.inProgress = 0;\r
+                       scsiDiskReset();\r
+                       sdClearStatus();\r
 \r
-               scsiDev.status = CHECK_CONDITION;\r
-               scsiDev.sense.code = HARDWARE_ERROR;\r
-               scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
-               scsiDev.phase = STATUS;\r
-               result = 0;\r
+                       scsiDev.status = CHECK_CONDITION;\r
+                       scsiDev.sense.code = HARDWARE_ERROR;\r
+                       scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
+                       scsiDev.phase = STATUS;\r
+               }\r
+               else\r
+               {\r
+                       sdWaitWriteBusy();\r
+               }               \r
+\r
+               return 1;\r
        }\r
        else\r
        {\r
-               sdWaitWriteBusy();\r
-               result = 1;\r
+               return 0;\r
        }\r
-\r
-       while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
-\r
-       return result;\r
 }\r
 \r
-int sdWriteSector()\r
+void sdCompleteWrite()\r
 {\r
-       int result = 1;\r
-       // Pre: sdPrepareWrite called.\r
-       int sdSectors = SDSectorsPerSCSISector();\r
-       int i;\r
-       for (i = 0; result && (i < sdSectors - 1) && (scsiDev.status != CHECK_CONDITION); ++i)\r
-       {\r
-               result = doWriteSector(SD_SECTOR_SIZE);\r
-       }\r
-\r
-       if (result && scsiDev.status != CHECK_CONDITION)\r
+       if (dmaInProgress)\r
        {\r
-               int remaining = config->bytesPerSector % SD_SECTOR_SIZE;\r
-               if (remaining == 0) remaining = SD_SECTOR_SIZE; // Full sector needed.\r
-               result = doWriteSector(remaining);\r
+               // Not much choice but to wait until we've completed the transfer.\r
+               // Cancelling the transfer can't be done as we have no way to reset\r
+               // the SD card.\r
+               while (!sdWriteSectorDMAPoll()) { /* spin */ }\r
        }\r
-       return result;\r
-}\r
-\r
-void sdCompleteWrite()\r
-{\r
+       \r
        transfer.inProgress = 0;\r
 \r
        uint8 r1, r2;\r
@@ -669,6 +599,38 @@ bad:
        return 0;\r
 }\r
 \r
+static void sdInitDMA()\r
+{\r
+       // One-time init only.\r
+       if (sdDMATxChan == CY_DMA_INVALID_CHANNEL)\r
+       {\r
+               sdDMATxChan =\r
+                       SD_TX_DMA_DmaInitialize(\r
+                               1, // Bytes per burst\r
+                               1, // request per burst\r
+                               HI16(CYDEV_SRAM_BASE),\r
+                               HI16(CYDEV_PERIPH_BASE)\r
+                               );\r
+\r
+               sdDMARxChan =\r
+                       SD_RX_DMA_DmaInitialize(\r
+                               1, // Bytes per burst\r
+                               1, // request per burst\r
+                               HI16(CYDEV_PERIPH_BASE),\r
+                               HI16(CYDEV_SRAM_BASE)\r
+                               );\r
+\r
+               CyDmaChDisable(sdDMATxChan);\r
+               CyDmaChDisable(sdDMARxChan);\r
+\r
+               sdDMARxTd[0] = CyDmaTdAllocate();\r
+               sdDMATxTd[0] = CyDmaTdAllocate();\r
+\r
+               SD_RX_DMA_COMPLETE_StartEx(sdRxISR);\r
+               SD_TX_DMA_COMPLETE_StartEx(sdTxISR);\r
+       }\r
+}\r
+\r
 int sdInit()\r
 {\r
        int result = 0;\r
@@ -679,9 +641,17 @@ int sdInit()
        sdDev.ccs = 0;\r
        sdDev.capacity = 0;\r
 \r
+       sdInitDMA();\r
+\r
        SD_CS_Write(1); // Set CS inactive (active low)\r
-       SD_Init_Clk_Start(); // Turn on the slow 400KHz clock\r
-       SD_Clk_Ctl_Write(0); // Select the 400KHz clock source.\r
+\r
+       // Set the SPI clock for 400kHz transfers\r
+       // 25MHz / 400kHz approx factor of 63.\r
+       uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();\r
+       SD_Data_Clk_SetDivider(clkDiv25MHz * 63);\r
+       // Wait for the clock to settle.\r
+       CyDelayUs(1);\r
+\r
        SDCard_Start(); // Enable SPI hardware\r
 \r
        // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
@@ -708,24 +678,16 @@ int sdInit()
        v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
        if(v){goto bad;}\r
 \r
-       // now set the sd card up for full speed\r
+       // now set the sd card back to full speed.\r
        // The SD Card spec says we can run SPI @ 25MHz\r
-       // But the PSoC 5LP SPIM datasheet says the most we can do is 18MHz.\r
-       // I've confirmed that no data is ever put into the RX FIFO when run at\r
-       // 20MHz or 25MHz.\r
-       // ... and then we get timing analysis failures if the BUS_CLK is over 62MHz.\r
-       // So we run the MASTER_CLK and BUS_CLK at 60MHz, and run the SPI clock at 30MHz\r
-       // (15MHz SPI transfer clock).\r
        SDCard_Stop();\r
-       \r
+\r
        // We can't run at full-speed with the pullup resistors enabled.\r
        SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
        SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
        SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
-       \r
-       SD_Data_Clk_Start(); // Turn on the fast clock\r
-       SD_Clk_Ctl_Write(1); // Select the fast clock source.\r
-       SD_Init_Clk_Stop(); // Stop the slow clock.\r
+\r
+       SD_Data_Clk_SetDivider(clkDiv25MHz);\r
        CyDelayUs(1);\r
        SDCard_Start();\r
 \r
@@ -750,7 +712,7 @@ out:
 \r
 }\r
 \r
-void sdPrepareWrite()\r
+void sdWriteMultiSectorPrep()\r
 {\r
        uint8 v;\r
        \r