Browse Source

Enable simultaneous transfer with SDIO

Petteri Aimonen 3 năm trước cách đây
mục cha
commit
f4998750cd

+ 75 - 36
lib/AzulSCSI_platform_GD32F205/gd32_sdio_sdcard.c

@@ -151,6 +151,8 @@ static void dma_transfer_config(uint32_t *srcbuf, uint32_t bufsize);
 /* configure the DMA for SDIO receive request */
 static void dma_receive_config(uint32_t *dstbuf, uint32_t bufsize);
 
+unsigned long millis(void);
+
 /*!
     \brief      initialize the SD card and make it in standby state
     \param[in]  none
@@ -429,12 +431,11 @@ sd_error_enum sd_transfer_mode_config(uint32_t txmode)
     \param[in]  blocksize: the data block size
     \retval     sd_error_enum
 */
-sd_error_enum sd_block_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize)
+sd_error_enum sd_block_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize, sdio_callback_t callback)
 {
     /* initialize the variables */
     sd_error_enum status = SD_OK;
     uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = preadbuffer;
-    __IO uint32_t timeout = 0;
 
     if(NULL == preadbuffer) {
         status = SD_PARAMETER_INVALID;
@@ -540,12 +541,16 @@ sd_error_enum sd_block_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t b
         sdio_interrupt_enable(SDIO_INT_CCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_RXORE | SDIO_INT_DTEND | SDIO_INT_STBITE);
         sdio_dma_enable();
         dma_receive_config(preadbuffer, blocksize);
-        timeout = 100000;
-        while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)) {
-            timeout--;
-            if(0 == timeout) {
+        uint32_t start = millis();
+        while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF))) {
+            if((uint32_t)(millis() - start) > 1000) {
                 return SD_ERROR;
             }
+            if (callback)
+            {
+                uint32_t complete = (blocksize - DMA_CHCNT(DMA1, DMA_CH3) * 4);
+                callback(complete);
+            }
         }
     } else {
         status = SD_PARAMETER_INVALID;
@@ -561,13 +566,12 @@ sd_error_enum sd_block_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t b
     \param[in]  blocksnumber: number of blocks that will be read
     \retval     sd_error_enum
 */
-sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize, uint32_t blocksnumber)
+sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize, uint32_t blocksnumber, sdio_callback_t callback)
 {
     /* initialize the variables */
     sd_error_enum status = SD_OK;
     uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = preadbuffer;
-    __IO uint32_t timeout = 0;
-
+    
     if(NULL == preadbuffer) {
         status = SD_PARAMETER_INVALID;
         return status;
@@ -612,7 +616,7 @@ sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint
         return status;
     }
 
-    if(blocksnumber > 1) {
+    if(blocksnumber >= 1) {
         if(blocksnumber * blocksize > SD_MAX_DATA_LENGTH) {
             /* exceeds the maximum length */
             status = SD_PARAMETER_INVALID;
@@ -694,14 +698,22 @@ sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint
             sdio_dma_enable();
             dma_receive_config(preadbuffer, totalnumber_bytes);
 
-            timeout = 100000;
-            while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)) {
-                timeout--;
-                if(0 == timeout) {
+            uint32_t start = millis();
+            while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF))) {
+                if((uint32_t)(millis() - start) > 1000) {
                     return SD_ERROR;
                 }
+                if (callback)
+                {
+                    uint32_t complete = (totalnumber_bytes - DMA_CHCNT(DMA1, DMA_CH3) * 4);
+                    callback(complete);
+                }
             }
             while((0 == transend) && (SD_OK == transerror)) {
+                if (callback)
+                {
+                    callback(totalnumber_bytes);
+                }
             }
             if(SD_OK != transerror) {
                 return transerror;
@@ -721,15 +733,14 @@ sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint
     \param[out] none
     \retval     sd_error_enum
 */
-sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize)
+sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize, sdio_callback_t callback)
 {
     /* initialize the variables */
     sd_error_enum status = SD_OK;
     uint8_t cardstate = 0;
     uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = pwritebuffer;
     uint32_t transbytes = 0, restwords = 0, response = 0;
-    __IO uint32_t timeout = 0;
-
+    
     if(NULL == pwritebuffer) {
         status = SD_PARAMETER_INVALID;
         return status;
@@ -785,11 +796,19 @@ sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_
     }
 
     response = sdio_response_get(SDIO_RESPONSE0);
-    timeout = 100000;
-
-    while((0 == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0)) {
+    
+    uint32_t start = millis();
+    while((0 == (response & SD_R1_READY_FOR_DATA))) {
         /* continue to send CMD13 to polling the state of card until buffer empty or timeout */
-        --timeout;
+        if((uint32_t)(millis() - start) > 1000) {
+            return SD_ERROR;
+        }
+
+        if (callback)
+        {
+            callback(0);
+        }
+
         /* send CMD13(SEND_STATUS), addressed card sends its status registers */
         sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
         sdio_wait_type_set(SDIO_WAITTYPE_NO);
@@ -801,9 +820,6 @@ sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_
         }
         response = sdio_response_get(SDIO_RESPONSE0);
     }
-    if(0 == timeout) {
-        return SD_ERROR;
-    }
 
     /* send CMD24(WRITE_BLOCK) to write a block */
     sdio_command_response_config(SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT);
@@ -871,14 +887,22 @@ sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_
         dma_transfer_config(pwritebuffer, blocksize);
         sdio_dma_enable();
 
-        timeout = 100000;
-        while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)) {
-            timeout--;
-            if(0 == timeout) {
+        uint32_t start = millis();
+        while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF))) {
+            if((uint32_t)(millis() - start) > 1000) {
                 return SD_ERROR;
             }
+            if (callback)
+            {
+                uint32_t complete = (blocksize - DMA_CHCNT(DMA1, DMA_CH3) * 4);
+                callback(complete);
+            }
         }
         while((0 == transend) && (SD_OK == transerror)) {
+            if (callback)
+            {
+                callback(blocksize);
+            }
         }
 
         if(SD_OK != transerror) {
@@ -894,6 +918,10 @@ sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_
     /* get the card state and wait the card is out of programming and receiving state */
     status = sd_card_state_get(&cardstate);
     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))) {
+        if (callback)
+        {
+            callback(blocksize);
+        }
         status = sd_card_state_get(&cardstate);
     }
     return status;
@@ -908,15 +936,14 @@ sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_
     \param[out] none
     \retval     sd_error_enum
 */
-sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize, uint32_t blocksnumber)
+sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize, uint32_t blocksnumber, sdio_callback_t callback)
 {
     /* initialize the variables */
     sd_error_enum status = SD_OK;
     uint8_t cardstate = 0;
     uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = pwritebuffer;
     uint32_t transbytes = 0, restwords = 0;
-    __IO uint32_t timeout = 0;
-
+    
     if(NULL == pwritebuffer) {
         status = SD_PARAMETER_INVALID;
         return status;
@@ -971,7 +998,7 @@ sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, u
         return status;
     }
 
-    if(blocksnumber > 1) {
+    if(blocksnumber >= 1) {
         if(blocksnumber * blocksize > SD_MAX_DATA_LENGTH) {
             status = SD_PARAMETER_INVALID;
             return status;
@@ -1081,14 +1108,22 @@ sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, u
             sdio_dma_enable();
             dma_transfer_config(pwritebuffer, totalnumber_bytes);
 
-            timeout = 100000;
-            while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF) && (timeout > 0))) {
-                timeout--;
-                if(0 == timeout) {
+            uint32_t start = millis();
+            while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF))) {
+                if((uint32_t)(millis() - start) > 1000) {
                     return SD_ERROR;
                 }
+                if (callback)
+                {
+                    uint32_t complete = (totalnumber_bytes - DMA_CHCNT(DMA1, DMA_CH3) * 4);
+                    callback(complete);
+                }
             }
             while((0 == transend) && (SD_OK == transerror)) {
+                if (callback)
+                {
+                    callback(totalnumber_bytes);
+                }
             }
             if(SD_OK != transerror) {
                 return transerror;
@@ -1104,6 +1139,10 @@ sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, u
     /* get the card state and wait the card is out of programming and receiving state */
     status = sd_card_state_get(&cardstate);
     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))) {
+        if (callback)
+        {
+            callback(totalnumber_bytes);
+        }
         status = sd_card_state_get(&cardstate);
     }
     return status;

+ 5 - 4
lib/AzulSCSI_platform_GD32F205/gd32_sdio_sdcard.h

@@ -227,14 +227,15 @@ sd_error_enum sd_bus_mode_config(uint32_t busmode);
 /* configure the mode of transmission */
 sd_error_enum sd_transfer_mode_config(uint32_t txmode);
 
+typedef void (*sdio_callback_t)(uint32_t bytes_done);
 /* read a block data into a buffer from the specified address of a card */
-sd_error_enum sd_block_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize);
+sd_error_enum sd_block_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize, sdio_callback_t callback);
 /* read multiple blocks data into a buffer from the specified address of a card */
-sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize, uint32_t blocksnumber);
+sd_error_enum sd_multiblocks_read(uint32_t *preadbuffer, uint64_t readaddr, uint16_t blocksize, uint32_t blocksnumber, sdio_callback_t callback);
 /* write a block data to the specified address of a card */
-sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize);
+sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize, sdio_callback_t callback);
 /* write multiple blocks data to the specified address of a card */
-sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize, uint32_t blocksnumber);
+sd_error_enum sd_multiblocks_write(uint32_t *pwritebuffer, uint64_t writeaddr, uint16_t blocksize, uint32_t blocksnumber, sdio_callback_t callback);
 /* erase a continuous area of a card */
 sd_error_enum sd_erase(uint64_t startaddr, uint64_t endaddr);
 /* process all the interrupts which the corresponding flags are set */

+ 67 - 21
lib/AzulSCSI_platform_GD32F205/sd_card_sdio.cpp

@@ -99,16 +99,6 @@ bool SdioCard::readData(uint8_t* dst)
     return false;
 }
 
-bool SdioCard::readSector(uint32_t sector, uint8_t* dst)
-{
-    return checkReturnOk(sd_block_read((uint32_t*)dst, sector * 512, 512));
-}
-
-bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n)
-{
-    return checkReturnOk(sd_multiblocks_read((uint32_t*)dst, sector * 512, 512, n));
-}
-
 bool SdioCard::readStart(uint32_t sector)
 {
     azlog("SdioCard::readStart() called but not implemented!");
@@ -187,16 +177,6 @@ bool SdioCard::writeData(const uint8_t* src)
     return false;
 }
 
-bool SdioCard::writeSector(uint32_t sector, const uint8_t* src)
-{
-    return checkReturnOk(sd_block_write((uint32_t*)src, sector * 512, 512));
-}
-
-bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t n)
-{
-    return checkReturnOk(sd_multiblocks_write((uint32_t*)src, sector * 512, 512, n));
-}
-
 bool SdioCard::writeStart(uint32_t sector)
 {
     azlog("SdioCard::writeStart() called but not implemented!");
@@ -214,13 +194,76 @@ bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector)
     return checkReturnOk(sd_erase(firstSector * 512, lastSector * 512));
 }
 
+/* Writing and reading, with progress callback */
 
-SdioConfig g_sd_sdio_config(DMA_SDIO);
+static sd_callback_t m_stream_callback;
+static const uint8_t *m_stream_buffer;
+static uint32_t m_stream_count;
+static uint32_t m_stream_count_start;
 
 void azplatform_set_sd_callback(sd_callback_t func, const uint8_t *buffer)
 {
+    m_stream_callback = func;
+    m_stream_buffer = buffer;
+    m_stream_count = 0;
+    m_stream_count_start = 0;
 }
 
+static void sdio_callback(uint32_t complete)
+{
+    if (m_stream_callback)
+    {
+        m_stream_callback(m_stream_count_start + complete);
+    }
+}
+
+static sdio_callback_t get_stream_callback(const uint8_t *buf, uint32_t count)
+{
+    m_stream_count_start = m_stream_count;
+
+    if (m_stream_callback)
+    {
+        if (buf == m_stream_buffer + m_stream_count)
+        {
+            m_stream_count += count;
+            return &sdio_callback;
+        }
+        else
+        {
+            azdbg("Stream buffer mismatch: ", (uint32_t)buf, " vs. ", (uint32_t)(m_stream_buffer + m_stream_count));
+            return NULL;
+        }
+    }
+    
+    return NULL;
+}
+
+
+bool SdioCard::writeSector(uint32_t sector, const uint8_t* src)
+{
+    return checkReturnOk(sd_block_write((uint32_t*)src, (uint64_t)sector * 512, 512,
+        get_stream_callback(src, 512)));
+}
+
+bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t n)
+{
+    return checkReturnOk(sd_multiblocks_write((uint32_t*)src, (uint64_t)sector * 512, 512, n,
+        get_stream_callback(src, n * 512)));
+}
+
+bool SdioCard::readSector(uint32_t sector, uint8_t* dst)
+{
+    return checkReturnOk(sd_block_read((uint32_t*)dst, (uint64_t)sector * 512, 512,
+        get_stream_callback(dst, 512)));
+}
+
+bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n)
+{
+    return checkReturnOk(sd_multiblocks_read((uint32_t*)dst, (uint64_t)sector * 512, 512, n,
+        get_stream_callback(dst, n * 512)));
+}
+
+
 // These functions are not used for SDIO mode but are needed to avoid build error.
 void sdCsInit(SdCsPin_t pin) {}
 void sdCsWrite(SdCsPin_t pin, bool level) {}
@@ -231,4 +274,7 @@ extern "C" void SDIO_IRQHandler(void)
     sd_interrupts_process();
 }
 
+// SDIO configuration for main program
+SdioConfig g_sd_sdio_config(DMA_SDIO);
+
 #endif

+ 1 - 5
src/AzulSCSI_config.h

@@ -22,11 +22,7 @@
 #define HDIMG_LUN_POS 3                 // Position to embed LUN numbers
 #define HDIMG_BLK_POS 5                 // Position to embed block size numbers
 #define MAX_FILE_PATH 64                // Maximum file name length
-#define MAX_BLOCKSIZE 1024              // Maximum BLOCK size
-
-// Read buffer size
-// Should be at least MAX_BLOCKSIZE.
-#define READBUFFER_SIZE 4096
+#define MAX_BLOCKSIZE 8192              // Maximum BLOCK size
 
 // SCSI config
 #define NUM_SCSIID  7          // Maximum number of supported SCSI-IDs (The minimum is 0)