【GD32450I-EVAL】+10SD卡测试

DDZZ669   2020-10-17 21:38 楼主

SD卡,即安全数码卡(Secure Digital ),GD32的SDIO接口可以用来驱动SD卡,另外,SDIO还定义了SD I/O卡、多媒体卡(MMC)和CE-ATA卡主机接口。

 

1 SD卡基础介绍

1.1 接口

板子上的SD卡接口原理图:

1.png

1.2 SD卡与microSD卡

microSD卡又叫TF卡,是SD卡的缩小版,平时用的较多也是microSD,也经常习惯把microSD卡叫做SD卡。

2.png

1.3 容量

  • SDSC:标准容量卡(Secure Digital Standard Capacity),上限至2GB,支持FAT 12, 16格式
  • SDHC:高容量卡(Secure Digital High Capacity),2GB至 32GB,支持FAT 32格式
  • SDXC:容量扩大化卡(Secure Digital eXtended Capacity)32GB至2TB,支持exFAT格式

 

2 SDIO

2.1 基本结构

GD32的SDIO 的结构框图如下图,主要由APB 接口和SDIO 适配器两大部分组成。

3.png

APB 接口:包括通过APB2 总线访问的寄存器、用于数据传输的FIFO 单元以及产生中断和DMA 请求信号。

  • 寄存器单元:包含所有的系统寄存器,生成信号用于控制卡与控制器之间的通信。

  • 数据FIFO 单元:有一个数据缓冲区,用于发送和接收 FIFO

SDIO 适配器:由控制单元、命令单元和数据单元组成。控制单元管理时钟信号,命令单元管理命令的传输,数据单元管理数据的传输。

  • SDIO_CLK:SDIO 控制器提供给卡的时钟。每个时钟周期在命令线(SDIO_CMD)和所有的数据线(SDIO_DAT)上直接发送一位命令或数据。对于SD卡可以在0 MHz 到25 MHz。

  • SDIO_CMD:该信号是双向命令通道,用于卡的初始化和命令的传输。命令从SDIO 控制器发送到卡,响应从卡发送到主机。

  • SDIO_DAT[7:0]:这些信号线都是双向数据通道。数据信号线操作在推挽模式。每次只有卡或者主机会驱动这些信号。默认情况下,上电或者复位后仅 DAT0 用于数据传输。

2.2 寄存器

  • SD卡有一些特殊功能寄存器
  • CID:宽度128位,卡标识号,每个读 写( RW )卡应具有唯一的标识号。
  • RCA:宽度16位,卡相对地址,在初始化的时候确定。
  • CSD:宽度128位,卡描述数据:卡操作条件的信息。
  • SCR:宽度64位,SD卡配置寄存器:SD卡特定信息数据。
  • OCR:宽度32位,操作条件寄存。

2.3 命令

SDIO通过发送各种命令的方式来操作SD卡,如下图:

4.png

 

程序中的命令列表:

/* SD memory card bus commands index */
#define SD_CMD_GO_IDLE_STATE                  ((uint8_t)0)   /* CMD0, GO_IDLE_STATE */
#define SD_CMD_ALL_SEND_CID                   ((uint8_t)2)   /* CMD2, ALL_SEND_CID */
#define SD_CMD_SEND_RELATIVE_ADDR             ((uint8_t)3)   /* CMD3, SEND_RELATIVE_ADDR */
#define SD_CMD_SET_DSR                        ((uint8_t)4)   /* CMD4, SET_DSR */
#define SD_CMD_SWITCH_FUNC                    ((uint8_t)6)   /* CMD6, SWITCH_FUNC */
#define SD_CMD_SELECT_DESELECT_CARD           ((uint8_t)7)   /* CMD7, SELECT_DESELECT_CARD */
#define SD_CMD_SEND_IF_COND                   ((uint8_t)8)   /* CMD8, SEND_IF_COND */
#define SD_CMD_SEND_CSD                       ((uint8_t)9)   /* CMD9, SEND_CSD */
#define SD_CMD_SEND_CID                       ((uint8_t)10)  /* CMD10, SEND_CID */
#define SD_CMD_STOP_TRANSMISSION              ((uint8_t)12)  /* CMD12, STOP_TRANSMISSION */
#define SD_CMD_SEND_STATUS                    ((uint8_t)13)  /* CMD13, SEND_STATUS */
#define SD_CMD_GO_INACTIVE_STATE              ((uint8_t)15)  /* CMD15, GO_INACTIVE_STATE */
#define SD_CMD_SET_BLOCKLEN                   ((uint8_t)16)  /* CMD16, SET_BLOCKLEN */
#define SD_CMD_READ_SINGLE_BLOCK              ((uint8_t)17)  /* CMD17, READ_SINGLE_BLOCK */
#define SD_CMD_READ_MULTIPLE_BLOCK            ((uint8_t)18)  /* CMD18, READ_MULTIPLE_BLOCK */
#define SD_CMD_WRITE_BLOCK                    ((uint8_t)24)  /* CMD24, WRITE_BLOCK */
#define SD_CMD_WRITE_MULTIPLE_BLOCK           ((uint8_t)25)  /* CMD25, WRITE_MULTIPLE_BLOCK */
#define SD_CMD_PROG_CSD                       ((uint8_t)27)  /* CMD27, PROG_CSD */
#define SD_CMD_SET_WRITE_PROT                 ((uint8_t)28)  /* CMD28, SET_WRITE_PROT */
#define SD_CMD_CLR_WRITE_PROT                 ((uint8_t)29)  /* CMD29, CLR_WRITE_PROT */
#define SD_CMD_SEND_WRITE_PROT                ((uint8_t)30)  /* CMD30, SEND_WRITE_PROT */
#define SD_CMD_ERASE_WR_BLK_START             ((uint8_t)32)  /* CMD32, ERASE_WR_BLK_START */
#define SD_CMD_ERASE_WR_BLK_END               ((uint8_t)33)  /* CMD33, ERASE_WR_BLK_END */
#define SD_CMD_ERASE                          ((uint8_t)38)  /* CMD38, ERASE */
#define SD_CMD_LOCK_UNLOCK                    ((uint8_t)42)  /* CMD42, LOCK_UNLOCK */
#define SD_CMD_APP_CMD                        ((uint8_t)55)  /* CMD55, APP_CMD */
#define SD_CMD_GEN_CMD                        ((uint8_t)56)  /* CMD56, GEN_CMD */

/* SD memory card application specific commands index */
#define SD_APPCMD_SET_BUS_WIDTH               ((uint8_t)6)   /* ACMD6, SET_BUS_WIDTH */
#define SD_APPCMD_SD_STATUS                   ((uint8_t)13)  /* ACMD13, SD_STATUS */
#define SD_APPCMD_SEND_NUM_WR_BLOCKS          ((uint8_t)22)  /* ACMD22, SEND_NUM_WR_BLOCKS */
#define SD_APPCMD_SET_WR_BLK_ERASE_COUNT      ((uint8_t)23)  /* ACMD23, SET_WR_BLK_ERASE_COUNT */
#define SD_APPCMD_SD_SEND_OP_COND             ((uint8_t)41)  /* ACMD41, SD_SEND_OP_COND */
#define SD_APPCMD_SET_CLR_CARD_DETECT         ((uint8_t)42)  /* ACMD42, SET_CLR_CARD_DETECT */
#define SD_APPCMD_SEND_SCR                    ((uint8_t)51)  /* ACMD51, SEND_SCR */

3 例子程序分析

3.1 SD卡初始化

sd_error_enum sd_config(void)
{
    sd_error_enum status = SD_OK;
    uint32_t cardstate = 0;
	
    /* initialize the card */
    status = sd_init();//SD卡初始化---GPIO、SDIO
    if(SD_OK == status)
	{
        status = sd_card_information_get(&sd_cardinfo);//获取SD卡信息
    }
    if(SD_OK == status)
	{
        status = sd_card_select_deselect(sd_cardinfo.card_rca);//挂载SD卡
    }
	
    status = sd_cardstatus_get(&cardstate);
    if(cardstate & 0x02000000)
	{
        printf("\r\n the card is locked!");
        while (1){
        }
    }
    if ((SD_OK == status) && (!(cardstate & 0x02000000)))
    {
        /* set bus mode */
        status = sd_bus_mode_config(SDIO_BUSMODE_4BIT);//配置总线模式
    }
    if (SD_OK == status)
    {
        /* set data transfer mode */
        status = sd_transfer_mode_config( SD_POLLING_MODE );//配置传输模式
    }
    return status;
}

3.2 读取SD卡基本信息

包括sd卡的版本,类型,容量,块大小与数量等。

void card_info_get(void)
{
    uint8_t sd_spec, sd_spec3, sd_spec4, sd_security;
    uint32_t block_count, block_size;
    uint16_t temp_ccc;
    printf("\r\n Card information:");
	
	//SD卡版本
    sd_spec = (sd_scr[1] & 0x0F000000) >> 24;
    sd_spec3 = (sd_scr[1] & 0x00008000) >> 15;
    sd_spec4 = (sd_scr[1] & 0x00000400) >> 10;
    if(2 == sd_spec)
    {
        if(1 == sd_spec3)
        {
            if(1 == sd_spec4) 
            {
                printf("\r\n## Card version 4.xx ##");
            }
            else 
            {
                printf("\r\n## Card version 3.0x ##");
            }
        }
        else 
        {
            printf("\r\n## Card version 2.00 ##");
        }
    }
    else if(1 == sd_spec) 
    {
        printf("\r\n## Card version 1.10 ##");
    }
    else if(0 == sd_spec) 
    {
        printf("\r\n## Card version 1.0x ##");
    }
    
	//SD卡类型
    sd_security = (sd_scr[1] & 0x00700000) >> 20;
    if(2 == sd_security) 
    {
        printf("\r\n## SDSC card ##");//标准容量卡SDSC,最大2G
    }
    else if(3 == sd_security) 
    {   
        printf("\r\n## SDHC card ##");//高容量卡SDHC,最大32G
    }
    else if(4 == sd_security) 
    {
        printf("\r\n## SDXC card ##");
    }
    
    block_count = (sd_cardinfo.card_csd.c_size + 1)*1024;
    block_size = 512;
	
	//SD卡容量
    printf("\r\n## Device size is %dKB ##", sd_card_capacity_get());
	
	//SD卡 块的大小
    printf("\r\n## Block size is %dB ##", block_size);
	
	//SD卡 块的个数
    printf("\r\n## Block count is %d ##", block_count);
    
    if(sd_cardinfo.card_csd.read_bl_partial)
	{
        printf("\r\n## Partial blocks for read allowed ##" );
    }
    if(sd_cardinfo.card_csd.write_bl_partial)
	{
        printf("\r\n## Partial blocks for write allowed ##" );
    }
	
	//SD卡 卡命令集
    temp_ccc = sd_cardinfo.card_csd.ccc;
    printf("\r\n## CardCommandClasses is: %x ##", temp_ccc);
    if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc))
	{
        printf("\r\n## Block operation supported ##");
    }
    if(SD_CCC_ERASE & temp_ccc)
	{
        printf("\r\n## Erase supported ##");
    }
    if(SD_CCC_WRITE_PROTECTION & temp_ccc)
	{
        printf("\r\n## Write protection supported ##");
    }
    if(SD_CCC_LOCK_CARD & temp_ccc)
	{
        printf("\r\n## Lock unlock supported ##");
    }
    if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc)
	{
        printf("\r\n## Application specific supported ##");
    }
    if(SD_CCC_IO_MODE & temp_ccc)
	{
        printf("\r\n## I/O mode supported ##");
    }
    if(SD_CCC_SWITCH & temp_ccc)
	{
        printf("\r\n## Switch function supported ##");
    }
}

3.3 SD卡测试

//开始SD卡测试
printf("\r\n\r\n Card test:");

/* single block operation test  =============单个块读写测试============= */
sd_error = sd_block_write(buf_write, 100*512, 512);//---------写入数据
if(SD_OK != sd_error)
{
    printf("\r\n Block write fail!");
    /* turn on LED1, LED3 and turn off LED2 */
    gd_eval_led_on(LED1);
    gd_eval_led_on(LED3);
    gd_eval_led_off(LED2);
    while (1)
    {
    }
}
else
{
    printf("\r\n Block write success!");
}

sd_error = sd_block_read(buf_read, 100*512, 512);//-----------读取数据
if(SD_OK != sd_error)
{
    printf("\r\n Block read fail!");
    /* turn on LED1, LED3 and turn off LED2 */
    gd_eval_led_on(LED1);
    gd_eval_led_on(LED3);
    gd_eval_led_off(LED2);
    while (1)
    {
    }
}else
{
    printf("\r\n Block read success!");
    //打印读取到的数据
    pdata = (uint8_t *)buf_read;
    /* print data by USART */
    printf("\r\n");
    for(i = 0; i < 128; i++)
    {
        printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
        pdata += 4;
        if(0 == (i + 1) % 4)
        {
            printf("\r\n");
        }
    }
}

/* lock and unlock operation test */
if(SD_CCC_LOCK_CARD & sd_cardinfo.card_csd.ccc)
{
    /* lock the card */
    sd_error = sd_lock_unlock(SD_LOCK); //-----------SD卡加锁
    if(SD_OK != sd_error)
    {
        printf("\r\n Lock failed!");
        /* turn on LED1, LED3 and turn off LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED3);
        gd_eval_led_off(LED2);
        while (1)
        {

        }
    }else
    {
        printf("\r\n The card is locked!");
    }
    sd_error = sd_erase(100*512, 101*512);//-------------SD卡擦除
    if(SD_OK != sd_error)
    {
        printf("\r\n Erase failed!");
    }
    else
    {
        printf("\r\n Erase success!");
    }

    /* unlock the card */
    sd_error = sd_lock_unlock(SD_UNLOCK);//--------------SD卡解锁
    if(SD_OK != sd_error)
    {
        printf("\r\n Unlock failed!");
        /* turn on LED1, LED3 and turn off LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED3);
        gd_eval_led_off(LED2);
        while (1){
        }
    }
    else
    {
        printf("\r\n The card is unlocked!");
    }
    sd_error = sd_erase(100*512, 101*512);//------------SD卡擦除
    if(SD_OK != sd_error){
        printf("\r\n Erase failed!");
    }else{
        printf("\r\n Erase success!");
    }

    sd_error = sd_block_read(buf_read, 100*512, 512);//--------------SD卡读取
    if(SD_OK != sd_error)
    {
        printf("\r\n Block read fail!");
        /* turn on LED1, LED3 and turn off LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED3);
        gd_eval_led_off(LED2);
        while (1){
        }
    }
    else
    {
        printf("\r\n Block read success!");
        pdata = (uint8_t *)buf_read;
        /* print data by USART */
        printf("\r\n");
        for(i = 0; i < 128; i++)
        {
            printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
            pdata += 4;
            if(0 == (i + 1) % 4)
            {
                printf("\r\n");
            }
        }		
    }
}

/* multiple blocks operation test =============多个块读写测试============= */
sd_error = sd_multiblocks_write(buf_write, 200*512, 512, 3);//----------多个块写入数据
if(SD_OK != sd_error)
{
    printf("\r\n Multiple block write fail!");
    /* turn on LED1, LED3 and turn off LED2 */
    gd_eval_led_on(LED1);
    gd_eval_led_on(LED3);
    gd_eval_led_off(LED2);
    while (1){
    }
}
else
{
    printf("\r\n Multiple block write success!");
}
sd_error = sd_multiblocks_read(buf_read, 200*512, 512, 3);//------------多个块读取数据
if(SD_OK != sd_error)
{
    printf("\r\n Multiple block read fail!");
    /* turn on LED1, LED3 and turn off LED2 */
    gd_eval_led_on(LED1);
    gd_eval_led_on(LED3);
    gd_eval_led_off(LED2);
    while (1){
    }
}
else
{
    printf("\r\n Multiple block read success!");
    pdata = (uint8_t *)buf_read;
    /* print data by USART */
    printf("\r\n");
    for(i = 0; i < 512; i++)
    {
        printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
        pdata += 4;
        if(0 == (i + 1) % 4)
        {
            printf("\r\n");
        }
    }
}

3.4 测试结果

通过串口打印测试结果,从结果来看,测试用到的microSD卡为:4.xx版的SDHC大容量卡,16GB(15441920KB),支持块操作,支持加锁解锁操作。

数据读写测试了单个块写入读取与多个块写入读取正常,在加锁后则无法读取,解锁后可正常读取。

 

 

Card init success!

 Card information:
## Card version 4.xx ##
## SDHC card ##
## Device size is 15441920KB ##
## Block size is 512B ##
## Block count is 30883840 ##
## CardCommandClasses is: db7 ##
## Block operation supported ##
## Erase supported ##
## Lock unlock supported ##
## Application specific supported ##
## Switch function supported ##

 Card test:
 Block write success!
 Block read success!
   0   0   0   0    1   0   0   0    2   0   0   0    3   0   0   0 
   4   0   0   0    5   0   0   0    6   0   0   0    7   0   0   0 
...略去若干行
 112   0   0   0  113   0   0   0  114   0   0   0  115   0   0   0 
 116   0   0   0  117   0   0   0  118   0   0   0  119   0   0   0 
 120   0   0   0  121   0   0   0  122   0   0   0  123   0   0   0 
 124   0   0   0  125   0   0   0  126   0   0   0  127   0   0   0 

 The card is locked!
 Erase failed!
 The card is unlocked!
 Erase success!
 Block read success!
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
  ...略去若干行
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 

 Multiple block write success!
 Multiple block read success!
   0   0   0   0    1   0   0   0    2   0   0   0    3   0   0   0 
   4   0   0   0    5   0   0   0    6   0   0   0    7   0   0   0 
  ...略去若干行
 112   0   0   0  113   0   0   0  114   0   0   0  115   0   0   0 
 116   0   0   0  117   0   0   0  118   0   0   0  119   0   0   0 
 120   0   0   0  121   0   0   0  122   0   0   0  123   0   0   0 
 124   0   0   0  125   0   0   0  126   0   0   0  127   0   0   0 
 128   0   0   0  129   0   0   0  130   0   0   0  131   0   0   0 
 132   0   0   0  133   0   0   0  134   0   0   0  135   0   0   0 
 ...略去若干行
 236   0   0   0  237   0   0   0  238   0   0   0  239   0   0   0 
 240   0   0   0  241   0   0   0  242   0   0   0  243   0   0   0 
 244   0   0   0  245   0   0   0  246   0   0   0  247   0   0   0 
 248   0   0   0  249   0   0   0  250   0   0   0  251   0   0   0 
 252   0   0   0  253   0   0   0  254   0   0   0  255   0   0   0 
   0   1   0   0    1   1   0   0    2   1   0   0    3   1   0   0 
   4   1   0   0    5   1   0   0    6   1   0   0    7   1   0   0 
  ...略去若干行
 112   1   0   0  113   1   0   0  114   1   0   0  115   1   0   0 
 116   1   0   0  117   1   0   0  118   1   0   0  119   1   0   0 
 120   1   0   0  121   1   0   0  122   1   0   0  123   1   0   0 
 124   1   0   0  125   1   0   0  126   1   0   0  127   1   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
  ...略去若干行
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 
   0   0   0   0    0   0   0   0    0   0   0   0    0   0   0   0 

 

本帖最后由 DDZZ669 于 2020-10-17 21:37 编辑

回复评论 (2)

感谢分享,每一个测评都做得这么认真!

点赞  2020-10-18 18:16
玩板看这里: https://bbs.eeworld.com.cn/elecplay.html EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!
点赞  2020-10-19 10:22
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复