[研电赛技术支持] 【GD32H757Z海棠派使用手册】第十二讲 SDIO-SD卡读写实验

[复制链接]
2255|0
 楼主| 聚沃科技 发表于 2024-6-5 10:26 | 显示全部楼层 |阅读模式
H757首图.png
12.1 实验内容
通过本实验主要学习以下内容:
• SDIO操作原理
• SD卡读写实现
12.2 实验原理
SD卡是一种主要以Nand Flash作为存储介质,具有体积小、数据传输速度快以及支持热插拔的优点。如今,已被广泛应用于数码相机、便携式移动设备以及手机等多种设备中。SD卡的驱动一般有SPI接口或SDIO接口,本例程介绍使用GD32F4xxSDIO接口驱动SD卡的实现。
12.2.1 SD卡基础知识
SD:secure digital memory card是一种安全存储器件。属性是快闪存储器(flash eeprom),功能用来存储数据。
图片1.png
SD卡虽然是薄薄的一片,但是它并不是一个整体,而是由大量的集成电路组成。SD卡的内部结构如下图所示,主要由信号端子,接口控制器和存储区组成。
图片2.png
SD卡主要有两种模式,SD模式和SPI模式。不同模式下,接口定义不同。下面是SD卡的引脚。
图片3.png
两种模式的接口定义如下
图片4.png
SD模式中,主要由VCC(电源)VSS(GND)CLK(时钟,由主控提供)CMD(命令)DAT0-3(数据输入输出),由6线制组成进行通信。SPI模式,主要采用4线制通信,除了电源地外,由MISOMOSICLKCS组成。下面简单介绍SD模式的操作。
要驱动SD卡工作,主要涉及两个步骤。第一个步骤是SD卡的识别过程。第二个步骤是对SD卡进行读写过程,即主机控制器和SD卡之间进行数据传输的过程。
要使SD卡能正常工作,一是要给SD卡供给稳定的电压,二是要SD卡按用户规定的方式工作。这两项工作的实现,都是主机控制器通过给SD卡发送控制命令来实现的。
主机(SDIO控制器)要驱动SD卡工作,要使用许多的命令,包括应用层命令ACMD 和 通用命令 CMD. 主机(SDIO控制器)把命令发送给SD卡,SD卡会作出回应,这里的回应叫做响应,响应命令分为6类,分别是R1R1bR2R3R6R7。主机(SDIO控制器)给SD卡发送命令之后,SD卡会作出响应,响应中包含主机(SDIO控制器)需要的数据,这些数据有SD的信息,容量,和存储数据等等。上面已经提到了,SD卡工作,主要是识别和数据传输,它的识别过程有些复杂,写代码的时候,可以参考协议给的初始化流程图。数据传输包括读和写,单字节和多字节读写。下两节描述识别初始化流程图和数据读写时序图。
1、读写数据的时序图
SDIOSD卡通信一般以数据块的形式进行传输,SDIO()数据块读操作,如下图所示。
图片5.png
SDIO()数据块写操作,如下图所示。
图片6.png
2、命令格式
SDIO所有的命令和响应都是在SDIO_CMD引脚上面传输的,命令长度固定为48位,SDIO命令格式如下表所示。
图片7.png
3、寄存器
SDIO控制器的寄存器,主要设置SDIO控制器和命令的索引与参数。SD卡有5个寄存器CID,RCA,CSD,SCR.OCRSD卡的信息从SD卡寄存器中获取。
SD卡正常工作,就是根据SD卡初始化流程图,发送命令,收到回复,直到流程结束。传输数据,也是根据读写时序图,将要发送的数据放进命令中发送出去。
12.2.2 SDIO模块原理
SDIO为安全的数字输入输出接口,可以用于驱动SD卡、EMMC等,主要特征如下:
◼ e*MMC: 与多媒体卡系统规格书 V4.2 及之前的版本全兼容。有三种不同的数据总线模式:1 (默认)4 位和 8 位;
◼ SD 卡: 与SD 存储卡规格版本3.0 全兼容;
◼ SD I/O: 与 SD I/O 卡规格版本 3.0 全兼容,有两种不同的数据总线模式: 1 (默认)4位(包括SDRDDR);
◼ 104MHz 数据传输频率和8 位数据传输模式;
中断和 DMA 请求;
数据传输支持 DDR 模式。  
SDIO模块结构框图如下所示。主要包括以下三个部分:SDIO 适配器:由控制单元、命令单元和数据单元组成,控制单元管理时钟信号,命令单元管理命令的传输,数据单元管理数据的传输; AHB 接口:包括通过 AHB 总线访问的寄存器、用于数据传输的 FIFO 单元以及产生中断和 DMA 请求信号; 内部 DMAIDMA)以及 AHB 主机接口  。
图片8.png
SDIO模块可以实现对SD卡的完全驱动以及协议的实现,包括命令、响应等相关操作,本例程实现使用SDIO驱动SD卡初始化以及读写测试等相关操作,具体实现可以参考GD32H7用户手册以及代码解析等。
12.3 硬件设计
SD卡相关硬件电路如下图所示,实验板上具有SD卡卡座,信号线上有四根数据线,一根CMD命令线以及一根CLK时钟线,所有信号线通过10K电阻进行上拉,电源地信号线具有10uf以及100nf电容,SD卡插入时,金属接触点朝下插入。
图片9.png
12.4 代码解析
12.4.1 SDIO初始化配置函数
SDIO初始化配置在sd_io_init()函数中,其中包括sd_init()初始化、sd_card_information_get()SD卡信息获取、sd_card_select_deselect()SD卡选择、sd_cardstatus_get()SD卡状态获取、sd_bus_mode_config()SD卡总线宽度配置以及sd_transfer_mode_config()SD卡通信模式配置,历程中选择了4线查询模式。
  1. C
  2. sd_error_enum sd_io_init(void)
  3. {
  4.     sd_error_enum status = SD_OK;
  5.     uint32_t cardstate = 0;

  6.     status = sd_init();
  7.     if(SD_OK == status) {
  8.         status = sd_card_information_get(&sd_cardinfo);
  9.     }
  10.     if(SD_OK == status) {
  11.         status = sd_card_select_deselect(sd_cardinfo.card_rca);
  12.     }
  13.     status = sd_cardstatus_get(&cardstate);
  14.     if(cardstate & 0x02000000) {
  15.         printf_log("\r\n the card is locked!");

  16.         status = sd_lock_unlock(SD_UNLOCK);
  17.         if(status != SD_OK) {
  18.             return SD_LOCK_UNLOCK_FAILED;
  19.         } else {
  20.             printf_log("\r\n the card is unlocked successfully!");
  21.         }
  22.     }

  23.     if((SD_OK == status) && (!(cardstate & 0x02000000))) {
  24.         /* set bus mode */
  25. #if (SDIO_BUSMODE == BUSMODE_4BIT)
  26.         status = sd_bus_mode_config(SDIO_BUSMODE_4BIT, SDIO_SPEEDMODE);
  27. #else
  28.         status = sd_bus_mode_config(SDIO_BUSMODE_1BIT, SDIO_SPEEDMODE);
  29. #endif
  30.     }

  31. #ifdef USE_18V_SWITCH
  32.     if(SD_OK == status) {
  33.         /* UHS-I Hosts can perform sampling point tuning using tuning command   */
  34.         status = sd_tuning();
  35.     }
  36. #endif /* USE_18V_SWITCH */

  37.     if(SD_OK == status) {
  38.         /* set data transfer mode */
  39.         /* if use 1.8V high speed mode, please select the DMA mode */
  40.         status = sd_transfer_mode_config(SDIO_DTMODE);
  41.     }
  42.     return status;
  43. }
12.4.2 获取SD卡信息函数
获取SD卡信息的函数如下所示,card_info_get()。
  1. C
  2. void card_info_get(void)
  3. {
  4.     uint8_t sd_spec, sd_spec3, sd_spec4, sd_security;
  5.     uint32_t block_count, block_size;
  6.     uint16_t temp_ccc;
  7.     printf_log("\r\n Card information:");
  8.     sd_spec = (sd_scr[1] & 0x0F000000) >> 24;
  9.     sd_spec3 = (sd_scr[1] & 0x00008000) >> 15;
  10.     sd_spec4 = (sd_scr[1] & 0x00000400) >> 10;
  11.     if(2 == sd_spec) {
  12.         if(1 == sd_spec3) {
  13.             if(1 == sd_spec4) {
  14.                 printf_log("\r\n## Card version 4.xx ##");
  15.             } else {
  16.                 printf_log("\r\n## Card version 3.0x ##");
  17.             }
  18.         } else {
  19.             printf_log("\r\n## Card version 2.00 ##");
  20.         }
  21.     } else if(1 == sd_spec) {
  22.         printf_log("\r\n## Card version 1.10 ##");
  23.     } else if(0 == sd_spec) {
  24.         printf_log("\r\n## Card version 1.0x ##");
  25.     }

  26.     sd_security = (sd_scr[1] & 0x00700000) >> 20;
  27.     if(2 == sd_security) {
  28.         printf_log("\r\n## security v1.01 ##");
  29.     } else if(3 == sd_security) {
  30.         printf_log("\r\n## security v2.00 ##");
  31.     } else if(4 == sd_security) {
  32.         printf_log("\r\n## security v3.00 ##");
  33.     }

  34.     block_count = (sd_cardinfo.card_csd.c_size + 1) * 1024;
  35.     block_size = 512;
  36.     printf_log("\r\n## Device size is %dKB ##", sd_card_capacity_get());
  37.     printf_log("\r\n## Block size is %dB ##", block_size);
  38.     printf_log("\r\n## Block count is %d ##", block_count);

  39.     if(sd_cardinfo.card_csd.read_bl_partial) {
  40.         printf_log("\r\n## Partial blocks for read allowed ##");
  41.     }
  42.     if(sd_cardinfo.card_csd.write_bl_partial) {
  43.         printf_log("\r\n## Partial blocks for write allowed ##");
  44.     }
  45.     temp_ccc = sd_cardinfo.card_csd.ccc;
  46.     printf_log("\r\n## CardCommandClasses is: %x ##", temp_ccc);
  47.     if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc)) {
  48.         printf_log("\r\n## Block operation supported ##");
  49.     }
  50.     if(SD_CCC_ERASE & temp_ccc) {
  51.         printf_log("\r\n## Erase supported ##");
  52.     }
  53.     if(SD_CCC_WRITE_PROTECTION & temp_ccc) {
  54.         printf_log("\r\n## Write protection supported ##");
  55.     }
  56.     if(SD_CCC_LOCK_CARD & temp_ccc) {
  57.         printf_log("\r\n## Lock unlock supported ##");
  58.     }
  59.     if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc) {
  60.         printf_log("\r\n## Application specific supported ##");
  61.     }
  62.     if(SD_CCC_IO_MODE & temp_ccc) {
  63.         printf_log("\r\n## I/O mode supported ##");
  64.     }
  65.     if(SD_CCC_SWITCH & temp_ccc) {
  66.         printf_log("\r\n## Switch function supported ##");
  67.     }
  68. }
12.4.3 SD卡数据块写入函数
SD卡数据块写入函数如下所示,通过该函数可实现SD卡数据块的数据写入。
  1. C
  2. sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint32_t writeaddr, uint16_t blocksize)
  3. {
  4.     /* initialize the variables */
  5.     sd_error_enum status = SD_OK;
  6.     uint8_t cardstate = 0U;
  7.     uint32_t count = 0U, align = 0U, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = pwritebuffer;
  8.     uint32_t transbytes = 0U, restwords = 0U, response = 0U;
  9.     __IO uint32_t timeout = 0U;

  10.     if(NULL == pwritebuffer) {
  11.         status = SD_PARAMETER_INVALID;
  12.         return status;
  13.     }

  14.     transerror = SD_OK;
  15.     transend = 0U;
  16.     totalnumber_bytes = 0U;
  17.     /* clear all DSM configuration */
  18.     sdio_data_config(SDIO, 0U, 0U, SDIO_DATABLOCKSIZE_1BYTE);
  19.     sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD);
  20.     sdio_dsm_disable(SDIO);
  21.     sdio_idma_disable(SDIO);

  22.     /* check whether the card is locked */
  23.     if(sdio_response_get(SDIO, SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED) {
  24.         status = SD_LOCK_UNLOCK_FAILED;
  25.         return status;
  26.     }

  27.     /* blocksize is fixed in 512B for SDHC card */
  28.     if(SDIO_HIGH_CAPACITY_SD_CARD != cardtype) {
  29.         writeaddr *= 512U;
  30.     } else {
  31.         blocksize = 512U;
  32.     }

  33.     align = blocksize & (blocksize - 1U);
  34.     if((blocksize > 0U) && (blocksize <= 2048U) && (0U == align)) {
  35.         datablksize = sd_datablocksize_get(blocksize);
  36.         /* send CMD16(SET_BLOCKLEN) to set the block length */
  37.         sdio_command_response_config(SDIO, SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT);
  38.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  39.         sdio_csm_enable(SDIO);

  40.         /* check if some error occurs */
  41.         status = r1_error_check(SD_CMD_SET_BLOCKLEN);
  42.         if(SD_OK != status) {
  43.             return status;
  44.         }
  45.     } else {
  46.         status = SD_PARAMETER_INVALID;
  47.         return status;
  48.     }

  49.     /* send CMD13(SEND_STATUS), addressed card sends its status registers */
  50.     sdio_command_response_config(SDIO, SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  51.     sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  52.     sdio_csm_enable(SDIO);
  53.     /* check if some error occurs */
  54.     status = r1_error_check(SD_CMD_SEND_STATUS);
  55.     if(SD_OK != status) {
  56.         return status;
  57.     }

  58.     response = sdio_response_get(SDIO, SDIO_RESPONSE0);
  59.     timeout = 100000U;

  60.     while((0U == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0U)) {
  61.         /* continue to send CMD13 to polling the state of card until buffer empty or timeout */
  62.         --timeout;
  63.         /* send CMD13(SEND_STATUS), addressed card sends its status registers */
  64.         sdio_command_response_config(SDIO, SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  65.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  66.         sdio_csm_enable(SDIO);
  67.         /* check if some error occurs */
  68.         status = r1_error_check(SD_CMD_SEND_STATUS);
  69.         if(SD_OK != status) {
  70.             return status;
  71.         }
  72.         response = sdio_response_get(SDIO, SDIO_RESPONSE0);
  73.     }
  74.     if(0U == timeout) {
  75.         return SD_ERROR;
  76.     }

  77.     stopcondition = 0U;
  78.     totalnumber_bytes = blocksize;

  79.     /* configure the SDIO data transmisson */
  80.     sdio_data_config(SDIO, SD_DATATIMEOUT, totalnumber_bytes, datablksize);
  81.     sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD);
  82.     sdio_trans_start_enable(SDIO);

  83.     if(SD_POLLING_MODE == transmode) {
  84.         /* send CMD24(WRITE_BLOCK) to write a block */
  85.         sdio_command_response_config(SDIO, SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT);
  86.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  87.         sdio_csm_enable(SDIO);
  88.         /* check if some error occurs */
  89.         status = r1_error_check(SD_CMD_WRITE_BLOCK);
  90.         if(SD_OK != status) {
  91.             return status;
  92.         }

  93.         /* polling mode */
  94.         while(!sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_TXURE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_DTEND)) {
  95.             if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_TFH)) {
  96.                 /* at least 8 words can be written into the FIFO */
  97.                 if((totalnumber_bytes - transbytes) < SD_FIFOHALF_BYTES) {
  98.                     restwords = (totalnumber_bytes - transbytes) / 4U + (((totalnumber_bytes - transbytes) % 4U == 0U) ? 0U : 1U);
  99.                     for(count = 0U; count < restwords; count++) {
  100.                         sdio_data_write(SDIO, *ptempbuff);
  101.                         ++ptempbuff;
  102.                         transbytes += 4U;
  103.                     }
  104.                 } else {
  105.                     for(count = 0U; count < SD_FIFOHALF_WORDS; count++) {
  106.                         sdio_data_write(SDIO, *(ptempbuff + count));
  107.                     }
  108.                     /* 8 words(32 bytes) has been transferred */
  109.                     ptempbuff += SD_FIFOHALF_WORDS;
  110.                     transbytes += SD_FIFOHALF_BYTES;
  111.                 }
  112.             }
  113.         }
  114.         sdio_trans_start_disable(SDIO);
  115.         /* whether some error occurs and return it */
  116.         if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR)) {
  117.             status = SD_DATA_CRC_ERROR;
  118.             sdio_flag_clear(SDIO, SDIO_FLAG_DTCRCERR);
  119.             return status;
  120.         } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTTMOUT)) {
  121.             status = SD_DATA_TIMEOUT;
  122.             sdio_flag_clear(SDIO, SDIO_FLAG_DTTMOUT);
  123.             return status;
  124.         } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_TXURE)) {
  125.             status = SD_TX_UNDERRUN_ERROR;
  126.             sdio_flag_clear(SDIO, SDIO_FLAG_TXURE);
  127.             return status;
  128.         } else {
  129.             /* if else end */
  130.         }

  131.     } else if(SD_DMA_MODE == transmode) {
  132.         /* DMA mode */
  133.         /* enable the SDIO corresponding interrupts and DMA */
  134.         sdio_interrupt_enable(SDIO, SDIO_INT_DTCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_TXURE | SDIO_INT_DTEND);
  135.         dma_config(pwritebuffer, (uint32_t)(blocksize >> 5));
  136.         sdio_idma_enable(SDIO);

  137.         /* send CMD24(WRITE_BLOCK) to write a block */
  138.         sdio_command_response_config(SDIO, SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT);
  139.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  140.         sdio_csm_enable(SDIO);
  141.         /* check if some error occurs */
  142.         status = r1_error_check(SD_CMD_WRITE_BLOCK);
  143.         if(SD_OK != status) {
  144.             return status;
  145.         }

  146.         while((0U == transend) && (SD_OK == transerror)) {
  147.         }

  148.         if(SD_OK != transerror) {
  149.             return transerror;
  150.         }
  151.     } else {
  152.         status = SD_PARAMETER_INVALID;
  153.         return status;
  154.     }

  155.     /* clear the DATA_FLAGS flags */
  156.     sdio_flag_clear(SDIO, SDIO_MASK_DATA_FLAGS);
  157.     /* get the card state and wait the card is out of programming and receiving state */
  158.     status = sd_card_state_get(&cardstate);
  159.     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))) {
  160.         status = sd_card_state_get(&cardstate);
  161.     }
  162.     return status;
  163. }
12.4.4 SD卡数据块读取函数
SD卡数据块读取函数如下所示。
  1. C
  2. sd_error_enum sd_block_read(uint32_t *preadbuffer, uint32_t readaddr, uint16_t blocksize)
  3. {
  4.     /* initialize the variables */
  5.     sd_error_enum status = SD_OK;
  6.     uint32_t count = 0U, align = 0U, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = preadbuffer;
  7.     __IO uint32_t timeout = 0U;

  8.     if(NULL == preadbuffer) {
  9.         status = SD_PARAMETER_INVALID;
  10.         return status;
  11.     }

  12.     transerror = SD_OK;
  13.     transend = 0U;
  14.     totalnumber_bytes = 0U;
  15.     /* clear all DSM configuration */
  16.     sdio_data_config(SDIO, 0U, 0U, SDIO_DATABLOCKSIZE_1BYTE);
  17.     sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD);
  18.     sdio_dsm_disable(SDIO);
  19.     sdio_idma_disable(SDIO);

  20.     /* check whether the card is locked */
  21.     if(sdio_response_get(SDIO, SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED) {
  22.         status = SD_LOCK_UNLOCK_FAILED;
  23.         return status;
  24.     }

  25.     /* blocksize is fixed in 512B for SDHC card */
  26.     if(SDIO_HIGH_CAPACITY_SD_CARD != cardtype) {
  27.         readaddr *= 512U;
  28.     } else {
  29.         blocksize = 512U;
  30.     }

  31.     align = blocksize & (blocksize - 1U);

  32.     if((blocksize > 0U) && (blocksize <= 2048U) && (0U == align)) {
  33.         datablksize = sd_datablocksize_get(blocksize);
  34.         /* send CMD16(SET_BLOCKLEN) to set the block length */
  35.         sdio_command_response_config(SDIO, SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT);
  36.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  37.         sdio_csm_enable(SDIO);

  38.         /* check if some error occurs */
  39.         status = r1_error_check(SD_CMD_SET_BLOCKLEN);
  40.         if(SD_OK != status) {
  41.             return status;
  42.         }
  43.     } else {
  44.         status = SD_PARAMETER_INVALID;
  45.         return status;
  46.     }

  47.     stopcondition = 0U;
  48.     totalnumber_bytes = (uint32_t)blocksize;

  49.     if(SD_POLLING_MODE == transmode) {

  50.         /* configure SDIO data transmisson */
  51.         sdio_data_config(SDIO, SD_DATATIMEOUT, totalnumber_bytes, datablksize);
  52.         sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOSDIO);
  53.         sdio_trans_start_enable(SDIO);


  54.         /* send CMD17(READ_SINGLE_BLOCK) to read a block */
  55.         sdio_command_response_config(SDIO, SD_CMD_READ_SINGLE_BLOCK, (uint32_t)readaddr, SDIO_RESPONSETYPE_SHORT);
  56.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  57.         sdio_csm_enable(SDIO);
  58.         /* check if some error occurs */
  59.         status = r1_error_check(SD_CMD_READ_SINGLE_BLOCK);
  60.         if(SD_OK != status) {
  61.             return status;
  62.         }

  63.         /* polling mode */
  64.         while(!sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_RXORE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_DTEND)) {
  65.             if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_RFH)) {
  66.                 /* at least 8 words can be read in the FIFO */
  67.                 for(count = 0U; count < SD_FIFOHALF_WORDS; count++) {
  68.                     *(ptempbuff + count) = sdio_data_read(SDIO);
  69.                 }
  70.                 ptempbuff += SD_FIFOHALF_WORDS;
  71.             }
  72.         }

  73.         sdio_trans_start_disable(SDIO);

  74.         /* whether some error occurs and return it */
  75.         if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR)) {
  76.             status = SD_DATA_CRC_ERROR;
  77.             sdio_flag_clear(SDIO, SDIO_FLAG_DTCRCERR);
  78.             return status;
  79.         } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTTMOUT)) {
  80.             status = SD_DATA_TIMEOUT;
  81.             sdio_flag_clear(SDIO, SDIO_FLAG_DTTMOUT);
  82.             return status;
  83.         } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_RXORE)) {
  84.             status = SD_RX_OVERRUN_ERROR;
  85.             sdio_flag_clear(SDIO, SDIO_FLAG_RXORE);
  86.             return status;
  87.         } else {
  88.             /* if else end */
  89.         }

  90.         while((SET != sdio_flag_get(SDIO, SDIO_FLAG_RFE)) && (SET == sdio_flag_get(SDIO, SDIO_FLAG_DATSTA))) {
  91.             *ptempbuff = sdio_data_read(SDIO);
  92.             ++ptempbuff;
  93.         }
  94.         /* clear the DATA_FLAGS flags */
  95.         sdio_flag_clear(SDIO, SDIO_MASK_DATA_FLAGS);
  96.     } else if(SD_DMA_MODE == transmode) {
  97.         /* DMA mode */
  98.         /* enable the SDIO corresponding interrupts and DMA function */
  99.         sdio_interrupt_enable(SDIO, SDIO_INT_CCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_RXORE | SDIO_INT_DTEND);
  100.         dma_config(preadbuffer, (uint32_t)(blocksize >> 5));
  101.         sdio_idma_enable(SDIO);

  102.         /* configure SDIO data transmisson */
  103.         sdio_data_config(SDIO, SD_DATATIMEOUT, totalnumber_bytes, datablksize);
  104.         sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOSDIO);
  105.         sdio_trans_start_enable(SDIO);

  106.         /* send CMD17(READ_SINGLE_BLOCK) to read a block */
  107.         sdio_command_response_config(SDIO, SD_CMD_READ_SINGLE_BLOCK, (uint32_t)readaddr, SDIO_RESPONSETYPE_SHORT);
  108.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  109.         sdio_csm_enable(SDIO);
  110.         /* check if some error occurs */
  111.         status = r1_error_check(SD_CMD_READ_SINGLE_BLOCK);
  112.         if(SD_OK != status) {
  113.             return status;
  114.         }

  115.         while((0U == transend) && (SD_OK == transerror)) {
  116.         }
  117.         if(SD_OK != transerror) {
  118.             return transerror;
  119.         }
  120.     } else {
  121.         status = SD_PARAMETER_INVALID;
  122.     }
  123.     return status;
  124. }
12.4.5 SDlockunlock配置函数
SDlockunlock配置函数如下所示。通过形参实现对SD卡的lockunlock,若希望lock SD卡,lcokstate配置为SD_LOCK;若希望unlock SD卡,lockstate配置为SD_UNLOCK.
  1. C
  2. sd_error_enum sd_lock_unlock(uint8_t lockstate)
  3. {
  4.     sd_error_enum status = SD_OK;
  5.     uint8_t cardstate = 0U, tempbyte = 0U;
  6.     uint32_t pwd1 = 0U, pwd2 = 0U, response = 0U, timeout = 0U;
  7.     uint16_t tempccc = 0U;

  8.     /* get the card command classes from CSD */
  9.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_24_31BITS) >> 24U);
  10.     tempccc = ((uint16_t)tempbyte << 4U);
  11.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_16_23BITS) >> 16U);
  12.     tempccc |= (((uint16_t)tempbyte & 0xF0U) >> 4U);

  13.     if(0U == (tempccc & SD_CCC_LOCK_CARD)) {
  14.         /* don't support the lock command */
  15.         status = SD_FUNCTION_UNSUPPORTED;
  16.         return status;
  17.     }
  18.     /* password pattern */
  19.     pwd1 = (0x01020600U | lockstate);
  20.     pwd2 = 0x03040506U;

  21.     /* clear all DSM configuration */
  22.     sdio_data_config(SDIO, 0U, 0U, SDIO_DATABLOCKSIZE_1BYTE);
  23.     sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD);
  24.     sdio_dsm_disable(SDIO);
  25.     sdio_idma_disable(SDIO);

  26.     /* send CMD16(SET_BLOCKLEN) to set the block length */
  27.     sdio_command_response_config(SDIO, SD_CMD_SET_BLOCKLEN, (uint32_t)8U, SDIO_RESPONSETYPE_SHORT);
  28.     sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  29.     sdio_csm_enable(SDIO);
  30.     /* check if some error occurs */
  31.     status = r1_error_check(SD_CMD_SET_BLOCKLEN);
  32.     if(SD_OK != status) {
  33.         return status;
  34.     }

  35.     /* send CMD13(SEND_STATUS), addressed card sends its status register */
  36.     sdio_command_response_config(SDIO, SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  37.     sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  38.     sdio_csm_enable(SDIO);
  39.     /* check if some error occurs */
  40.     status = r1_error_check(SD_CMD_SEND_STATUS);
  41.     if(SD_OK != status) {
  42.         return status;
  43.     }

  44.     response = sdio_response_get(SDIO, SDIO_RESPONSE0);
  45.     timeout = 100000U;
  46.     while((0U == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0U)) {
  47.         /* continue to send CMD13 to polling the state of card until buffer empty or timeout */
  48.         --timeout;
  49.         /* send CMD13(SEND_STATUS), addressed card sends its status registers */
  50.         sdio_command_response_config(SDIO, SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  51.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  52.         sdio_csm_enable(SDIO);
  53.         /* check if some error occurs */
  54.         status = r1_error_check(SD_CMD_SEND_STATUS);
  55.         if(SD_OK != status) {
  56.             return status;
  57.         }
  58.         response = sdio_response_get(SDIO, SDIO_RESPONSE0);
  59.     }
  60.     if(0U == timeout) {
  61.         status = SD_ERROR;
  62.         return status;
  63.     }

  64.     /* send CMD42(LOCK_UNLOCK) to set/reset the password or lock/unlock the card */
  65.     sdio_command_response_config(SDIO, SD_CMD_LOCK_UNLOCK, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
  66.     sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  67.     sdio_csm_enable(SDIO);
  68.     /* check if some error occurs */
  69.     status = r1_error_check(SD_CMD_LOCK_UNLOCK);
  70.     if(SD_OK != status) {
  71.         return status;
  72.     }

  73.     response = sdio_response_get(SDIO, SDIO_RESPONSE0);

  74.     /* configure the SDIO data transmisson */
  75.     sdio_data_config(SDIO, SD_DATATIMEOUT, (uint32_t)8, SDIO_DATABLOCKSIZE_8BYTES);
  76.     sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD);
  77.     sdio_dsm_enable(SDIO);

  78.     /* write password pattern */
  79.     sdio_data_write(SDIO, pwd1);
  80.     sdio_data_write(SDIO, pwd2);

  81.     /* whether some error occurs and return it */
  82.     if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR)) {
  83.         status = SD_DATA_CRC_ERROR;
  84.         sdio_flag_clear(SDIO, SDIO_FLAG_DTCRCERR);
  85.         return status;
  86.     } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTTMOUT)) {
  87.         status = SD_DATA_TIMEOUT;
  88.         sdio_flag_clear(SDIO, SDIO_FLAG_DTTMOUT);
  89.         return status;
  90.     } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_TXURE)) {
  91.         status = SD_TX_UNDERRUN_ERROR;
  92.         sdio_flag_clear(SDIO, SDIO_FLAG_TXURE);
  93.         return status;
  94.     } else {
  95.         /* if else end */
  96.     }

  97.     /* clear the SDIO_INTC flags */
  98.     sdio_flag_clear(SDIO, SDIO_MASK_INTC_FLAGS);
  99.     /* get the card state and wait the card is out of programming and receiving state */
  100.     status = sd_card_state_get(&cardstate);
  101.     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))) {
  102.         status = sd_card_state_get(&cardstate);
  103.     }
  104.     return status;
  105. }
12.4.6 SDerase擦除操作函数
SD卡擦除操作函数如下,其形参为擦除起始地址以及结束地址。
  1. C
  2. sd_error_enum sd_erase(uint32_t startaddr, uint32_t endaddr)
  3. {
  4.     /* initialize the variables */
  5.     sd_error_enum status = SD_OK;
  6.     uint32_t count = 0U, clkdiv = 0U;
  7.     __IO uint32_t delay = 0U;
  8.     uint8_t cardstate = 0U, tempbyte = 0U;
  9.     uint16_t tempccc = 0U;

  10.     /* get the card command classes from CSD */
  11.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_24_31BITS) >> 24U);
  12.     tempccc = (uint16_t)((uint16_t)tempbyte << 4U);
  13.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_16_23BITS) >> 16U);
  14.     tempccc |= ((uint16_t)tempbyte & 0xF0U) >> 4U;
  15.     if(0U == (tempccc & SD_CCC_ERASE)) {
  16.         /* don't support the erase command */
  17.         status = SD_FUNCTION_UNSUPPORTED;
  18.         return status;
  19.     }
  20.     clkdiv = (SDIO_CLKCTL(SDIO) & SDIO_CLKCTL_DIV);
  21.     clkdiv *= 2U;
  22.     delay = 168000U / clkdiv;

  23.     /* check whether the card is locked */
  24.     if(sdio_response_get(SDIO, SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED) {
  25.         status = SD_LOCK_UNLOCK_FAILED;
  26.         return(status);
  27.     }

  28.     /* blocksize is fixed in 512B for SDHC card */
  29.     if(SDIO_HIGH_CAPACITY_SD_CARD != cardtype) {
  30.         startaddr *= 512U;
  31.         endaddr *= 512U;
  32.     }

  33.     if((SDIO_STD_CAPACITY_SD_CARD_V1_1 == cardtype) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == cardtype) ||
  34.             (SDIO_HIGH_CAPACITY_SD_CARD == cardtype)) {
  35.         /* send CMD32(ERASE_WR_BLK_START) to set the address of the first write block to be erased */
  36.         sdio_command_response_config(SDIO, SD_CMD_ERASE_WR_BLK_START, startaddr, SDIO_RESPONSETYPE_SHORT);
  37.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  38.         sdio_csm_enable(SDIO);
  39.         /* check if some error occurs */
  40.         status = r1_error_check(SD_CMD_ERASE_WR_BLK_START);
  41.         if(SD_OK != status) {
  42.             return status;
  43.         }

  44.         /* send CMD33(ERASE_WR_BLK_END) to set the address of the last write block of the continuous range to be erased */
  45.         sdio_command_response_config(SDIO, SD_CMD_ERASE_WR_BLK_END, endaddr, SDIO_RESPONSETYPE_SHORT);
  46.         sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  47.         sdio_csm_enable(SDIO);
  48.         /* check if some error occurs */
  49.         status = r1_error_check(SD_CMD_ERASE_WR_BLK_END);
  50.         if(SD_OK != status) {
  51.             return status;
  52.         }
  53.     }

  54.     /* send CMD38(ERASE) to set the address of the first write block to be erased */
  55.     sdio_command_response_config(SDIO, SD_CMD_ERASE, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
  56.     sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
  57.     sdio_csm_enable(SDIO);
  58.     /* check if some error occurs */
  59.     status = r1_error_check(SD_CMD_ERASE);
  60.     if(SD_OK != status) {
  61.         return status;
  62.     }
  63.     /* loop until the counter is reach to the calculated time */
  64.     for(count = 0U; count < delay; count++) {
  65.     }
  66.     /* get the card state and wait the card is out of programming and receiving state */
  67.     status = sd_card_state_get(&cardstate);
  68.     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))) {
  69.         status = sd_card_state_get(&cardstate);
  70.     }
  71.     return status;
  72. }
12.4.7 主函数
SD卡主函数如下,可实现对SD卡的擦写读以及加锁解锁操作。
  1. C
  2. int main()
  3. {
  4.     sd_error_enum sd_error;
  5.     Drv_Err state = DRV_ERROR;

  6.     uint16_t i = 5;
  7. #ifdef DATA_PRINT
  8.     uint8_t *pdata;
  9. #endif /* DATA_PRINT */

  10.     /* enable the CPU Cache */
  11.     driver_init();

  12.     /* configure the NVIC and USART */
  13.     nvic_config();
  14.    
  15.     bsp_led_group_init();

  16.     /* turn off all the LEDs */
  17.     bsp_led_off(&LED1);
  18.     bsp_led_off(&LED2);

  19.     /* initialize the card */                  
  20.     do {
  21.         sd_error = sd_io_init();
  22.     } while((SD_OK != sd_error) && (--i));

  23.     if(i) {
  24.         printf_log("\r\n Card init success!\r\n");
  25.     } else {
  26.         printf_log("\r\n Card init failed!\r\n");
  27.         /* turn on LED1, LED2 */
  28.         bsp_led_on(&LED1);
  29.         bsp_led_on(&LED2);
  30.         while(1) {
  31.         }
  32.     }

  33.     /* get the information of the card and print it out by USART */
  34.     card_info_get();


  35.     /* init the write buffer */
  36.     for(i = 0; i < 512; i++) {
  37.         buf_write[i] = i;
  38.     }

  39.     /* clean and invalidate buffer in D-Cache */
  40.     SCB_CleanInvalidateDCache_by_Addr(buf_write, 512 * 4);

  41.     printf_log("\r\n\r\n Card test:");
  42.     /* single block operation test */
  43.     sd_error = sd_block_write(buf_write, 100, 512);
  44.     if(SD_OK != sd_error) {
  45.         printf_log("\r\n Block write fail!");
  46.         /* turn on LED1, LED2 */
  47.         bsp_led_on(&LED1);
  48.         bsp_led_on(&LED2);
  49.         while(1) {
  50.         }
  51.     } else {
  52.         printf_log("\r\n Block write success!");
  53.     }

  54.     sd_error = sd_block_read(buf_read, 100, 512);
  55.     if(SD_OK != sd_error) {
  56.         printf_log("\r\n Block read fail!");
  57.         /* turn on LED1, LED2 */
  58.         bsp_led_on(&LED1);
  59.         bsp_led_on(&LED2);
  60.         while(1) {
  61.         }
  62.     } else {
  63.         printf_log("\r\n Block read success!");
  64. #ifdef DATA_PRINT
  65.         SCB_CleanInvalidateDCache_by_Addr(buf_read, 512 * 4);
  66.         pdata = (uint8_t *)buf_read;
  67.         /* print data by USART */
  68.         printf_log("\r\n");
  69.         for(i = 0; i < 128; i++) {
  70.             printf_log(" %3d %3d %3d %3d ", *pdata, *(pdata + 1), *(pdata + 2), *(pdata + 3));
  71.             pdata += 4;
  72.             if(0 == (i + 1) % 4) {
  73.                 printf_log("\r\n");
  74.             }
  75.         }
  76. #endif /* DATA_PRINT */
  77.     }

  78.     /* compare the write date and the read data */
  79.     state = memory_compare((uint8_t *)buf_write, (uint8_t *)buf_read, 128*4);
  80.     if(SUCCESS == state) {
  81.         printf_log("\r\n Single block read compare successfully!");
  82.     } else {
  83.         printf_log("\r\n Single block read compare fail!");
  84.         /* turn on LED1, LED2 */
  85.         bsp_led_on(&LED1);
  86.         bsp_led_on(&LED2);
  87.         while(1) {
  88.         }
  89.     }

  90.     /* lock and unlock operation test */
  91.     if(SD_CCC_LOCK_CARD & sd_cardinfo.card_csd.ccc) {
  92.         /* lock the card */
  93.         sd_error = sd_lock_unlock(SD_LOCK);
  94.         if(SD_OK != sd_error) {
  95.             printf_log("\r\n Lock failed!");
  96.             /* turn on LED1, LED2 */
  97.             bsp_led_on(&LED1);
  98.             bsp_led_on(&LED2);
  99.             while(1) {
  100.             }
  101.         } else {
  102.             printf_log("\r\n The card is locked!");
  103.         }
  104.         sd_error = sd_erase(100, 101);
  105.         if(SD_OK != sd_error) {
  106.             printf_log("\r\n Erase failed!");
  107.         } else {
  108.             printf_log("\r\n Erase success!");
  109.         }

  110.         /* unlock the card */
  111.         sd_error = sd_lock_unlock(SD_UNLOCK);
  112.         if(SD_OK != sd_error) {
  113.             printf_log("\r\n Unlock failed!");
  114.             /* turn on LED1, LED2 */
  115.             bsp_led_on(&LED1);
  116.             bsp_led_on(&LED2);
  117.             while(1) {
  118.             }
  119.         } else {
  120.             printf_log("\r\n The card is unlocked!");
  121.         }
  122.         sd_error = sd_erase(100, 101);
  123.         if(SD_OK != sd_error) {
  124.             printf_log("\r\n Erase failed!");
  125.         } else {
  126.             printf_log("\r\n Erase success!");
  127.         }

  128.         sd_error = sd_block_read(buf_read, 100, 512);
  129.         if(SD_OK != sd_error) {
  130.             printf_log("\r\n Block read fail!");
  131.             /* turn on LED1, LED2 */
  132.             bsp_led_on(&LED1);
  133.             bsp_led_on(&LED2);
  134.             while(1) {
  135.             }
  136.         } else {
  137.             printf_log("\r\n Block read success!");
  138. #ifdef DATA_PRINT
  139.             SCB_CleanInvalidateDCache_by_Addr(buf_read, 512 * 4);
  140.             pdata = (uint8_t *)buf_read;
  141.             /* print data by USART */
  142.             printf_log("\r\n");
  143.             for(i = 0; i < 128; i++) {
  144.                 printf_log(" %3d %3d %3d %3d ", *pdata, *(pdata + 1), *(pdata + 2), *(pdata + 3));
  145.                 pdata += 4;
  146.                 if(0 == (i + 1) % 4) {
  147.                     printf_log("\r\n");
  148.                 }
  149.             }
  150. #endif /* DATA_PRINT */
  151.         }
  152.     }

  153.     /* multiple blocks operation test */
  154.     sd_error = sd_multiblocks_write(buf_write, 200, 512, 3);
  155.     if(SD_OK != sd_error) {
  156.         printf_log("\r\n Multiple block write fail!");
  157.         /* turn on LED1, LED2 */
  158.         bsp_led_on(&LED1);
  159.         bsp_led_on(&LED2);
  160.         while(1) {
  161.         }
  162.     } else {
  163.         printf_log("\r\n Multiple block write success!");
  164.     }

  165.     sd_error = sd_multiblocks_read(buf_read, 200, 512, 3);
  166.     if(SD_OK != sd_error) {
  167.         printf_log("\r\n Multiple block read fail!");
  168.         /* turn on LED1, LED2 */
  169.         bsp_led_on(&LED1);
  170.         bsp_led_on(&LED2);
  171.         while(1) {
  172.         }
  173.     } else {
  174.         printf_log("\r\n Multiple block read success!");
  175. #ifdef DATA_PRINT
  176.         SCB_CleanInvalidateDCache_by_Addr(buf_read, 512 * 4);
  177.         pdata = (uint8_t *)buf_read;
  178.         /* print data by USART */
  179.         printf_log("\r\n");
  180.         for(i = 0; i < 512; i++) {
  181.             printf_log(" %3d %3d %3d %3d ", *pdata, *(pdata + 1), *(pdata + 2), *(pdata + 3));
  182.             pdata += 4;
  183.             if(0 == (i + 1) % 4) {
  184.                 printf_log("\r\n");
  185.             }
  186.         }
  187. #endif /* DATA_PRINT */
  188.     }
  189.     /* compare the write date and the read data */
  190.     state = memory_compare((uint8_t *)buf_write, (uint8_t *)buf_read, 128*3*4);
  191.    
  192.     if(SUCCESS == state) {
  193.         printf_log("\r\n Multiple block read compare successfully!");
  194.     } else {
  195.         printf_log("\r\n Multiple block read compare fail!");
  196.         /* turn on LED1, LED2 */
  197.         bsp_led_on(&LED1);
  198.         bsp_led_on(&LED2);
  199.         while(1) {
  200.         }
  201.     }
  202.     printf_log("\r\n SD card test successfully!");
  203.     while(1) {};
  204. }
12.5 实验结果
SD卡读写实验例程烧录到海棠派开发板中,并在卡槽中插入SD卡,在液晶屏上,将会观察到SD卡相关操作结果。
本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462

您需要登录后才可以回帖 登录 | 注册

本版积分规则

170

主题

190

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部