W801 the SDIO Drive and FATFS optimize

Publish in 2022-04-22 18: 09: 10

one. Project overview

In using the default SDK the SDIO with FATFS In the process, discoveren SDK There are several problems as follows:
[1] Could not recognize the size is 2G Following card
[2] fatfs Cannot be mounted properly 2G Following card
[3] Change the main frequency to 240M after, There are problems with card reading and writing
So I was very upset about the original SDK the SDIO Drive sum Fatfs The transplant section has been modified, And solve these problems.

two. Dominant frequency problem

[1] Problem description, in SDK the wm_main. c The following functions exist, Is used to set CPU Bus frequency of, The highest is 240M. For better release performance, I adjusted it to 240M Later appeared SD The card reads and writes abnormally.

tls_sys_clk_set (CPU_CLK_240M) ; 

[2] The cause of the problem: SDIO in mmc In. . . mode, And use SD If the card is configured for the default speed, The highest output frequency can only be 20M. W801 the SDIO Mount to CPU The clock bus, Obtained by frequency division, original SDK The default frequency is 1/6, When the main frequency is changed, SDIO The bus frequency becomes 40M, If the number exceeds the upper limit, I cannot read or write normally.
[3] solution: There are two solutions, One is to change the value of the frequency division register, One is modification SD The speed configuration of the card, I chose the former here. SDIO The corresponding table of frequency division values is shown in the figure below;
9. png
So when cpu Main frequency set to 240M when, We need to say frequency division instead 1/12 Can not exceed 20M The upper limit of, The location of the change is changed in the following initial configuration function:

int wm_sdh_config (void) 
{
    tls_sys_clk sysclk;     

    tls_sys_clk_get (&sysclk) ; 
    SDIO_HOST-" MMC_CARDSEL = 0xC0 |  (sysclk. cpuclk / 2 - 1) ; //0xd3;  //enable module,  enable mmcclk
    SDIO_HOST-" MMC_CTL = 0xEB;   //original SDK Nakao D3,  Here to achieve frequency division 1/12,  Need to be modified as EB,  When the main frequency changes,  There is also a need to ensure that the corresponding changes are not exceeded 20M
    SDIO_HOST-" MMC_INT_MASK = 0x100;  //unmask sdio data interrupt. 
    SDIO_HOST-" MMC_CRCCTL = 0xC0;  //
    SDIO_HOST-" MMC_TIMEOUTCNT = 0xff; 
    return 0; 
}

[Modified test results]
10. png

three. SDIO Drive and Fatfs edit

1. SD Card related concepts

[1] SD Classification of cards:
SD Kayu mmc Cards developed, According to protocol version, Capacity sizes can be divided into several types, because W801 Maximum support sd2. 0 agreement, So here's what we're faced with 4 Class card:
1. mmc card
2. SD card: The protocol version is SD1. 0, Capacity size 0-2G
3. SDSC card: The protocol version is SD2. 0, Capacity size 0-2G
4. SDHC card: The protocol version is SD2. 0, Capacity size 2-32G
7. jpg

[2] imparity SD Card read-write difference
2G inner SD The card is byte addressed, while 2G The above cards can only be addressed for blocks. Give an example, When the address is 0x01 when, 2G The card will determine that it is a byte address 0x01 Start reading and writing, while 2G Other cards will be determined to read and write from the first block.

[3] SD Initialization and identification of cards
On the basis of SD2. 0 agreement, The recognition process of the above four types of cards is shown in the figure below, I also wrote a Chinese version of the map attached.
5. png
6. png

2. SDK Drive defect

As mentioned above, the initialization process, Mainly through cmd8 and acmd41 returned OCR The value of the register identifies the four types of cards. So let's see here SDK The original code can be found, The original SDK centring CMD8 Whether the command responds is not distinguished, If you haven't read it response The initialization fails. And the follow-up is not correct OCR register CCS Bit to judge, Cause it can not judge is 2G incapacity SDSC The card or 2-32G the SDHC card, Identify it uniformly as SDHC card, Different from the above SD You can see the difference between card read and write 2G Internal card, It is byte addressed 2G Outside card, Addressing the block, Because of origin SDK Not making distinctions leads to 2G The inner card can be successfully initialized, However, read and write failures may occur. Drive problems can also cause fatfs Have a problem.

int wm_sd_card_initialize (uint32_t *rca) 
{
    int ret = -1; 
    uint32_t respCmd[4]; 
    int recnt = 5; 
    
    wm_sdh_config () ; 
    //======================================================
    // set up
    // Test:   Init sequence,  With response check
    // CMD 0  Reset Card
    // CMD 8  Get voltage  (Only 2. 0 Card response to this) 
    // CMD55  Indicate Next Command are Application specific
    // ACMD41 Get Voltage windows
    // CMD 2  CID reg
    // CMD 3  Get RCA. 
    //======================================================
begin: 
    wm_sdh_send_cmd (0,  0,  0x04) ;  //Send CMD0
    sm_sdh_wait_interrupt (0,  -1) ; 
    delay_cnt (1000) ; 
    wm_sdh_send_cmd (8,  0x1AA,  0x44) ;  //Send CMD8
    sm_sdh_wait_interrupt (0,  -1) ; 
    wm_sdh_get_response (respCmd,  2) ; 
    sh_dumpBuffer ("CMD8 respCmd",   (char *) respCmd,  5) ; 
    if (respCmd[0] ! = 0x1AA ||  (respCmd[1] & 0xFF)  ! = 8) 
    {
        TEST_DEBUG ("CMD8 Error\n") ; 
        printf ("CMD8 Error\n") ; 
        if (recnt--) 
            goto begin; 
        goto end;                          //When here 5 subread cmd8 hind response When unsuccessful,  Will jump directly to the initialization failure,  No distinction is made
    }
    while (1) 
    {
        wm_sdh_send_cmd (55,  0,  0x44) ;  //Send CMD55
        sm_sdh_wait_interrupt (0,  -1) ; 
        wm_sdh_get_response (respCmd,  2) ; 
        sh_dumpBuffer ("CMD55 respCmd",   (char *) respCmd,  5) ; 
        if ( (respCmd[1] & 0xFF)  ! = 55) 
        {
            printf ("respCmd Error\n") ; 
            goto end; 
        }
            

        wm_sdh_send_cmd (41,  0xC0100000,  0x44) ;  //Send ACMD41
        sm_sdh_wait_interrupt (0,  -1) ; 
        sm_sdh_wait_interrupt (3,  1000) ;  //On account of sd In the specification,  Acmd41 returned crc Always be 11111,  It should be ignored crc; here crc Errors should be ignored.  
        wm_sdh_get_response (respCmd,  2) ; 
        sh_dumpBuffer ("ACMD41 respCmd",   (char *) respCmd,  5) ; 
        if ( (respCmd[1] & 0xFF)  ! = 0x3F)  //sd The specification definition is fixed as 0x3F, So lead to crc mistake
        {
            printf ("respCmd Error - 2\n") ; 
            goto end; 
        }
        if (respCmd[0] " "  31 & 0x1) 
        {
            TEST_DEBUG ("card is ready\n") ;          //Not right here CCS Bit judgment,  indistinguishable SDSC with SDHC
            printf ("card is ready\n") ; 
            break; 
        }
    }

    wm_sdh_send_cmd (2,  0,  0x54) ;  //Send CMD2
    sm_sdh_wait_interrupt (0,  -1) ; 
    sm_sdh_wait_interrupt (3,  1000) ; 
    wm_sdh_get_response (respCmd,  4) ; 
    sh_dumpBuffer ("CMD2 respCmd",   (char *) respCmd,  16) ; 
    if ( (respCmd[3] " "  24 & 0xFF)  ! = 0x3F)  //sd The specification definition is fixed as 0x3F, So lead to crc mistake
    {
        printf ("respCmd Error - 3\n") ; 
        goto end; 
    }
    wm_sdh_send_cmd (3,  0,  0x44) ;  //Send CMD3
    sm_sdh_wait_interrupt (0,  -1) ; 
    wm_sdh_get_response (respCmd,  2) ; 
    sh_dumpBuffer ("CMD3 respCmd",   (char *) respCmd,  5) ; 
    if ( (respCmd[1] & 0xFF)  ! = 3) 
    {
        printf ("respCmd Error - 4\n") ; 
        goto end; 
    }
    *rca = respCmd[0] " "  16; 
    TEST_DEBUG ("RCA = %x\n",  *rca) ; 

    ret = 0; 
end: 
    return ret; 
}

3. Driver modification

[1] edit wm_sdio_host. h, In the header file SD_CardInfo_t One is actually already defined in the structure CardType The variable is used to identify the card type, Here we just need to add 3 A macro definition to indicate the card type. because mmc Cards are not used much, So I didn't increase it mmc Card recognition.

#define CardType_SD     0x01
#define CardType_SDSC     0x02
#define CardType_SDHC     0x03
//The struct is already defined in the header file,  You can see the initial SDK One has been defined CardType The variable is used to identify the card type
typedef struct
{
  long long CardCapacity; 
  u32 CardBlockSize; 
  u16 RCA; 
  u8 CardType; 
} SD_CardInfo_t; 

[2] edit wm_sdio_host. c Hit the mark wm_sd_card_initialize function, Modify as follows:

int wm_sd_card_initialize (uint32_t *rca) 
{
    int ret = -1; 
    uint32_t respCmd[4]; 
    int recnt = 5; 
    
    u8 temp_type = 0x00; 
    
    wm_sdh_config () ; 
    //======================================================
    // set up
    // Test:   Init sequence,  With response check
    // CMD 0  Reset Card
    // CMD 8  Get voltage  (Only 2. 0 Card response to this) 
    // CMD55  Indicate Next Command are Application specific
    // ACMD41 Get Voltage windows
    // CMD 2  CID reg
    // CMD 3  Get RCA. 
    //======================================================
begin: 
    wm_sdh_send_cmd (0,  0,  0x04) ;  //Send CMD0
    sm_sdh_wait_interrupt (0,  -1) ; 
    delay_cnt (1000) ; 
    wm_sdh_send_cmd (8,  0x1AA,  0x44) ;  //Send CMD8
    sm_sdh_wait_interrupt (0,  -1) ; 
    wm_sdh_get_response (respCmd,  2) ; 
    sh_dumpBuffer ("CMD8 respCmd",   (char *) respCmd,  5) ; 
    if (respCmd[0] ! = 0x1AA ||  (respCmd[1] & 0xFF)  ! = 8) 
    {
        TEST_DEBUG ("CMD8 Error\n") ; 
        if (recnt--) 
            goto begin; 
        temp_type =0x01;  // If no reply is received SD1. 0 card 
    }
    while (1) 
    {
        wm_sdh_send_cmd (55,  0,  0x44) ;  //Send CMD55
        sm_sdh_wait_interrupt (0,  -1) ; 
        wm_sdh_get_response (respCmd,  2) ; 
        sh_dumpBuffer ("CMD55 respCmd",   (char *) respCmd,  5) ; 
        if ( (respCmd[1] & 0xFF)  ! = 55) 
            goto end; 

        wm_sdh_send_cmd (41,  0xC0100000,  0x44) ;  //Send ACMD41
        sm_sdh_wait_interrupt (0,  -1) ; 
        sm_sdh_wait_interrupt (3,  1000) ;  //On account of sd In the specification,  Acmd41 returned crc Always be 11111,  It should be ignored crc; here crc Errors should be ignored.  
        wm_sdh_get_response (respCmd,  2) ; 
        sh_dumpBuffer ("ACMD41 respCmd",   (char *) respCmd,  5) ; 
        if ( (respCmd[1] & 0xFF)  ! = 0x3F)  //sd The specification definition is fixed as 0x3F, So lead to crc mistake
            goto end; 
        if (respCmd[0] " "  31 & 0x1) 
        {
            TEST_DEBUG ("card is ready\n") ; 
            // On the basis of CCS Bit to determine which type of card
            if  ( (respCmd[0] " "  30 == 0x3)  &&  (temp_type == 0x0) ) 
            {
                SDCardInfo. CardType = CardType_SDHC; 
                printf ("\nCardtype[%d]:  SDHC\n",  SDCardInfo. CardType) ; 
            }
            else if  ( (respCmd[0] " "  30 == 0x2)  &&  (temp_type == 0x0) ) 
            {
                SDCardInfo. CardType = CardType_SDSC; 
                printf ("\nCardtype[%d]:  SDSC\n",  SDCardInfo. CardType) ; 
            }
            else if  (temp_type == 0x1) 
            {
                SDCardInfo. CardType = CardType_SD; 
                printf ("\nCardtype[%d]:  SD\n",  SDCardInfo. CardType) ; 
            }
            break; 
        }
    }

    wm_sdh_send_cmd (2,  0,  0x54) ;  //Send CMD2
    sm_sdh_wait_interrupt (0,  -1) ; 
    sm_sdh_wait_interrupt (3,  1000) ; 
    wm_sdh_get_response (respCmd,  4) ; 
    sh_dumpBuffer ("CMD2 respCmd",   (char *) respCmd,  16) ; 
    if ( (respCmd[3] " "  24 & 0xFF)  ! = 0x3F)  //sd The specification definition is fixed as 0x3F, So lead to crc mistake
        goto end; 
    wm_sdh_send_cmd (3,  0,  0x44) ;  //Send CMD3
    sm_sdh_wait_interrupt (0,  -1) ; 
    wm_sdh_get_response (respCmd,  2) ; 
    sh_dumpBuffer ("CMD3 respCmd",   (char *) respCmd,  5) ; 
    if ( (respCmd[1] & 0xFF)  ! = 3) 
        goto end; 
    *rca = respCmd[0] " "  16; 
    TEST_DEBUG ("RCA = %x\n",  *rca) ; 

    ret = 0; 
end: 
    return ret; 
}

[3] towards wm_sdio_host_demo. c Modification of, this demo There is no distinction between different cards using different operations, Here we refine by card type, All cards can be read and written by block reading and writing. Both read and write functions here need to be modified, Show here sdh_card_wr_sb Function modification, The other function does the same thing.

static int sdh_card_wr_sb (uint32_t rca,  uint8_t bus_width,  const uint32_t tsize) 
{
    int ret = -1; 
    int i = 0; 
    char* buf = NULL; 
    char* bufR = NULL; 

    buf = tls_mem_alloc (512) ; 
    if (buf == NULL) 
        goto end; 
    bufR = tls_mem_alloc (512) ; 
    if (bufR == NULL) 
        goto end; 
    random_get_bytes (buf,  512) ; 
    TEST_DEBUG ("bus width %s\n",  bus_width == 0 ?  "1bit" :  "4bits") ; 
    ret = wm_sd_card_set_bus_width (rca,  bus_width) ; 
    if (ret) 
        goto end; 
    ret = wm_sd_card_set_blocklen (0x200) ;  //512
    if (ret) 
        goto end; 

    for (i=0;  i " (tsize/512) ;  i++) 
    {
        //Judge whether or not SDHC card,  If so,  block addressing,  Otherwise,  bytes are addressed,  Need to multiply 512
        if  (SDCardInfo. CardType == CardType_SDHC) 
        {
            ret = wm_sd_card_block_write (rca,  i,  buf) ; 
        }
        else if  ( (SDCardInfo. CardType == CardType_SDSC)  ||  (SDCardInfo. CardType == CardType_SD) ) 
        {
            ret = wm_sd_card_block_write (rca,  i * 512,  buf) ; 
        }
        if (ret) 
            goto end; 
    }
    ret = wm_sd_card_query_status (rca,  NULL) ; 
    if (ret) 
        goto end; 
    for (i=0;  i " (tsize/512) ;  i++) 
    {
        if  (SDCardInfo. CardType == CardType_SDHC) 
        {
            ret = wm_sd_card_block_read (rca,  i,  bufR) ; 
        }
        else if  ( (SDCardInfo. CardType == CardType_SDSC)  ||  (SDCardInfo. CardType == CardType_SD) ) 
        {
            ret = wm_sd_card_block_read (rca,  i * 512,  bufR) ; 
        }
        if (ret) 
            goto end; 
        if (memcmp (buf,  bufR,  512) ) 
        {
            ret = -2; 
            goto end; 
        }
    }

    ret = 0; 
end: 
    if (buf) 
    {
        tls_mem_free (buf) ; 
    }
    if (bufR) 
    {
        tls_mem_free (bufR) ; 
    }
    TEST_DEBUG ("ret %d\n",  ret) ; 
    return ret; 
}

[4] fatfs the diskio. c Modification of, prograft fatfs File system read and write functions also make no distinction between block read and write and byte read, The mount will fail 2G Inside the card needs to be right disk_write and disk_write The function is modified as follows:

static int MMC_disk_write (    BYTE *buff,  LBA_t sector,  UINT count) 
{
    int ret,  i; 
    int buflen = BLOCK_SIZE*count; 
    BYTE *wrbuff = buff; 
    
    if  ( ( (u32) buff) &0x3) 
    {
        wrbuff = tls_mem_alloc (buflen) ; 
        if  (wrbuff == NULL)  /*non aligned 4*/
        {
            return -1; 
        }
        memcpy (wrbuff,  buff,  buflen) ; 
    }
    
    for ( i = 0;  i  " TRY_COUNT;  i++ ) 
    {
        if (count == 1) 
        {
            //Judge whether or not SDHC card,  If so,  block addressing,  Otherwise,  bytes are addressed,  Need to multiply 512
            if  (SDCardInfo. CardType == CardType_SDHC) 
            {
                ret = wm_sd_card_block_write (fs_rca,  sector,   (char *) wrbuff) ; 
            }
            else if  ( (SDCardInfo. CardType == CardType_SDSC)  ||  (SDCardInfo. CardType == CardType_SD) ) 
            {
                ret = wm_sd_card_block_write (fs_rca,  sector * BLOCK_SIZE,   (char *) wrbuff) ; 
            }
        }
        else if (count "  1) 
        {
            if  (SDCardInfo. CardType == CardType_SDHC) 
            {
                ret = wm_sd_card_blocks_write (fs_rca,  sector,   (char *) wrbuff,  buflen) ; 
            }
            else if  ( (SDCardInfo. CardType == CardType_SDSC)  ||  (SDCardInfo. CardType == CardType_SD) ) 
            {
                for  (int j = 0;  j  " count;  j++) 
                {
                    ret = wm_sd_card_blocks_write (fs_rca,  sector + j* BLOCK_SIZE,   (char *) wrbuff,  BLOCK_SIZE) ; 
                }
            }
        }
        if ( ret == 0 )  
        {
            break; 
        }
    }

    if (wrbuff ! = buff) 
    {
        tls_mem_free (wrbuff) ; 
    }

    return ret; 
}

static int MMC_disk_read (    BYTE *buff,  LBA_t sector,  UINT count) 
{
    int ret,  i; 
    int buflen = BLOCK_SIZE*count; 
    BYTE *rdbuff = buff; 

    if  ( ( (u32) buff) &0x3)  /*non aligned 4*/
    {
        rdbuff = tls_mem_alloc (buflen) ; 
        if  (rdbuff == NULL) 
        {
            return -1; 
        }
    }
    
    for ( i=0;  i "TRY_COUNT;  i++ ) 
    {   
        if (count == 1) 
        {
            //Judge whether or not SDHC card,  If so,  block addressing,  Otherwise,  bytes are addressed,  Need to multiply 512
            if  (SDCardInfo. CardType == CardType_SDHC) 
            {
                ret = wm_sd_card_block_read (fs_rca,  sector,   (char *) rdbuff) ; 
            }
            else if  ( (SDCardInfo. CardType == CardType_SDSC)  ||  (SDCardInfo. CardType == CardType_SD) ) 
            {
                ret = wm_sd_card_block_read (fs_rca,  sector * BLOCK_SIZE,   (char *) rdbuff) ; 
            }
        }
        else if (count "  1) 
        {
            if  (SDCardInfo. CardType == CardType_SDHC) 
            {
                ret = wm_sd_card_blocks_read (fs_rca,  sector,   (char *) rdbuff,  buflen) ; 
            }
            else if  ( (SDCardInfo. CardType == CardType_SDSC)  ||  (SDCardInfo. CardType == CardType_SD) ) 
            {
                for  (int j = 0;  j  " count;  j++) 
                {
                    ret = wm_sd_card_blocks_read (fs_rca,  sector + j* BLOCK_SIZE,   (char *) rdbuff,  BLOCK_SIZE) ; 
                }
            }
        }
        if ( ret == 0 )  
            break; 
    }

    if (rdbuff ! = buff) 
    {
        if (ret == 0) 
        {
            memcpy (buff,  rdbuff,  buflen) ; 
        }
        tls_mem_free (rdbuff) ; 
    }

    return ret; 
}

4. Experimental result

[1] operational SD card: I only have two on hand right now SD card, A sheet for 4G the SDHC card, The other is 128MB the SD card, As shown in the following picture.
8. jpg

[2] The result is displayed: As shown in the following picture, Both can be read, written, and mounted successfully Fatfs
1. png
2. png
3. png
4. png

Finally attach Baidu cloud link

I personally have no problems in the test, If anything bug You can communicate in the comments section
link: https: //pan. baidu. com/s/1YFtnyO1YzOUhDGhLEiWuXw
Extract code: e4fx

6 Pieces of review

publish
problem