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

[复制链接]
1649|0
 楼主| 聚沃科技 发表于 2024-6-23 10:59 | 显示全部楼层 |阅读模式
红枫派首图.png
23.1 实验内容
通过本实验主要学习以下内容:
• SDIO操作原理
• SD卡读写实现
23.2 实验原理
SD卡是一种主要以Nand Flash作为存储介质,具有体积小、数据传输速度快以及支持热插拔的优点。如今,已被广泛应用于数码相机、便携式移动设备以及手机等多种设备中。SD卡的驱动一般有SPI接口或SDIO接口,本例程介绍使用GD32F303SDIO接口驱动SD卡的实现。
23.2.1 SD卡基础知识
SD:secure digital memory card是一种安全存储器件。属性是快闪存储器(flash eeprom),功能用来存储数据。
图片5.png
SD卡虽然是薄薄的一片,但是它并不是一个整体,而是由大量的集成电路组成。SD卡的内部结构如下图所示,主要由信号端子,接口控制器和存储区组成。
图片6.png
SD卡主要有两种模式,SD模式和SPI模式。不同模式下,接口定义不同。下面是SD卡的引脚。
图片7.png
两种模式的接口定义如下
图片8.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()数据块读操作,如下图所示。
图片9.png
SDIO()数据块写操作,如下图所示。
图片10.png
2、命令格式
SDIO所有的命令和响应都是在SDIO_CMD引脚上面传输的,命令长度固定为48位,SDIO命令格式如下表所示。
图片11.png
3、寄存器
SDIO控制器的寄存器,主要设置SDIO控制器和命令的索引与参数。SD卡有5个寄存器CID,RCA,CSD,SCR.OCRSD卡的信息从SD卡寄存器中获取。
SD卡正常工作,就是根据SD卡初始化流程图,发送命令,收到回复,直到流程结束。传输数据,也是根据读写时序图,将要发送的数据放进命令中发送出去。
23.2.2 SDIO模块原理
SDIO为安全的数字输入输出接口,可以用于驱动SD卡、EMMC等,主要特征如下:
◼ MMC: 与多媒体卡系统规格书 V4.2 及之前的版本全兼容。有三种不同的数据总线模式:1 (默认)4 位和 8 位;
◼ SD 卡: 与SD 存储卡规格版本2.0 全兼容;
◼ SD I/O: 与 SD I/O 卡规格版本 2.0 全兼容,有两种不同的数据总线模式: 1 (默认)4位;
◼ CE-ATA: 与 CE-ATA 数字协议版本 1.1 全兼容;
◼ 48MHz 数据传输频率和8 位数据传输模式;
中断和 DMA 请求;
完成信号使能和失能(CE-ATA)。  
SDIO模块结构框图如下所示。主要包含两大部分:SDIO 适配器:由控制单元、命令单元和数据单元组成,控制单元管理时钟信号,命令单元管理命令的传输,数据单元管理数据的传输;AHB 接口:包括通过 AHB 总线访问的寄存器、用于数据传输的 FIFO 单元以及产生中断和DMA 请求信号。  
图片12.png
SDIO模块可以实现对SD卡的完全驱动以及协议的实现,包括命令、响应等相关操作,本例程实现使用SDIO驱动SD卡初始化以及读写测试等相关操作,具体实现可以参考GD32F303用户手册以及代码解析等。
23.3 硬件设计
SD卡相关硬件电路如下图所示,实验板上具有SD卡卡座,信号线上有四根数据线,一根CMD命令线以及一根CLK时钟线,所有信号线通过10K电阻进行上拉,电源地信号线具有10uf以及100nf电容,SD卡插入时,金属接触点朝下插入。
图片13.png
23.4 代码解析
23.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("\r\n the card is locked!");
  16.         while (1){
  17.         }
  18.     }
  19.     if ((SD_OK == status) && (!(cardstate & 0x02000000)))
  20.     {
  21.         /* set bus mode */
  22.         status = sd_bus_mode_config(SDIO_BUSMODE_4BIT);
  23. //        status = sd_bus_mode_config( SDIO_BUSMODE_1BIT );
  24.     }
  25.     if (SD_OK == status)
  26.     {
  27.         /* set data transfer mode */
  28. //        status = sd_transfer_mode_config( SD_DMA_MODE );
  29.         status = sd_transfer_mode_config( SD_POLLING_MODE );
  30.     }
  31.     return status;
  32. }
23.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("\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.     {
  13.         if(1 == sd_spec3)
  14.         {
  15.             if(1 == sd_spec4)
  16.             {
  17.                // printf("\r\n## Card version 4.xx ##");
  18.             }
  19.             else
  20.             {
  21.               //  printf("\r\n## Card version 3.0x ##");
  22.             }
  23.         }
  24.         else
  25.         {
  26.            // printf("\r\n## Card version 2.00 ##");
  27.         }
  28.     }
  29.     else if(1 == sd_spec)
  30.     {
  31.        // printf("\r\n## Card version 1.10 ##");
  32.     }
  33.     else if(0 == sd_spec)
  34.     {
  35.        // printf("\r\n## Card version 1.0x ##");
  36.     }
  37.    
  38.     sd_security = (sd_scr[1] & 0x00700000) >> 20;
  39.     if(2 == sd_security)
  40.     {
  41.       //  printf("\r\n## SDSC card ##");
  42.     }
  43.     else if(3 == sd_security)
  44.     {   
  45.        // printf("\r\n## SDHC card ##");
  46.     }
  47.     else if(4 == sd_security)
  48.     {
  49.        // printf("\r\n## SDXC card ##");
  50.     }
  51.    
  52.     block_count = (sd_cardinfo.card_csd.c_size + 1)*1024;
  53.     block_size = 512;
  54. //    printf("\r\n## Device size is %dKB ##", sd_card_capacity_get());
  55. //    printf("\r\n## Block size is %dB ##", block_size);
  56. //    printf("\r\n## Block count is %d ##", block_count);
  57.    
  58.     if(sd_cardinfo.card_csd.read_bl_partial){
  59.       //  printf("\r\n## Partial blocks for read allowed ##" );
  60.     }
  61.     if(sd_cardinfo.card_csd.write_bl_partial){
  62.        // printf("\r\n## Partial blocks for write allowed ##" );
  63.     }
  64.     temp_ccc = sd_cardinfo.card_csd.ccc;
  65.     //printf("\r\n## CardCommandClasses is: %x ##", temp_ccc);
  66.     if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc)){
  67.       //  printf("\r\n## Block operation supported ##");
  68.     }
  69.     if(SD_CCC_ERASE & temp_ccc){
  70.       //  printf("\r\n## Erase supported ##");
  71.     }
  72.     if(SD_CCC_WRITE_PROTECTION & temp_ccc){
  73.       //  printf("\r\n## Write protection supported ##");
  74.     }
  75.     if(SD_CCC_LOCK_CARD & temp_ccc){
  76.      //   printf("\r\n## Lock unlock supported ##");
  77.     }
  78.     if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc){
  79.      //   printf("\r\n## Application specific supported ##");
  80.     }
  81.     if(SD_CCC_IO_MODE & temp_ccc){
  82.       //  printf("\r\n## I/O mode supported ##");
  83.     }
  84.     if(SD_CCC_SWITCH & temp_ccc){
  85.       //  printf("\r\n## Switch function supported ##");
  86.     }
  87. }
23.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 = 0;
  7.     uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = pwritebuffer;
  8.     uint32_t transbytes = 0, restwords = 0, response = 0;
  9.     __IO uint32_t timeout = 0;
  10.    
  11.     if(NULL == pwritebuffer){
  12.         status = SD_PARAMETER_INVALID;
  13.         return status;
  14.     }
  15.    
  16.     transerror = SD_OK;
  17.     transend = 0;
  18.     totalnumber_bytes = 0;
  19.     /* clear all DSM configuration */
  20.     sdio_data_config(0, 0, SDIO_DATABLOCKSIZE_1BYTE);
  21.     sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
  22.     sdio_dsm_disable();
  23.     sdio_dma_disable();
  24.    
  25.     /* check whether the card is locked */
  26.     if(sdio_response_get(SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED){
  27.         status = SD_LOCK_UNLOCK_FAILED;
  28.         return status;
  29.     }
  30.    
  31.     /* blocksize is fixed in 512B for SDHC card */
  32.     if(SDIO_HIGH_CAPACITY_SD_CARD == cardtype){
  33.         blocksize = 512;
  34.         writeaddr /= 512;
  35.     }
  36.    
  37.     align = blocksize & (blocksize - 1);
  38.     if((blocksize > 0) && (blocksize <= 2048) && (0 == align)){
  39.         datablksize = sd_datablocksize_get(blocksize);
  40.         /* send CMD16(SET_BLOCKLEN) to set the block length */
  41.         sdio_command_response_config(SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT);
  42.         sdio_wait_type_set(SDIO_WAITTYPE_NO);
  43.         sdio_csm_enable();
  44.         
  45.         /* check if some error occurs */
  46.         status = r1_error_check(SD_CMD_SET_BLOCKLEN);
  47.         if(SD_OK != status){
  48.             return status;
  49.         }
  50.     }else{
  51.         status = SD_PARAMETER_INVALID;
  52.         return status;
  53.     }
  54.    
  55.     /* send CMD13(SEND_STATUS), addressed card sends its status registers */
  56.     sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  57.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  58.     sdio_csm_enable();
  59.     /* check if some error occurs */
  60.     status = r1_error_check(SD_CMD_SEND_STATUS);
  61.     if(SD_OK != status){
  62.         return status;
  63.     }
  64.    
  65.     response = sdio_response_get(SDIO_RESPONSE0);
  66.     timeout = 100000;

  67.     while((0 == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0)){
  68.         /* continue to send CMD13 to polling the state of card until buffer empty or timeout */
  69.         --timeout;
  70.         /* send CMD13(SEND_STATUS), addressed card sends its status registers */
  71.         sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  72.         sdio_wait_type_set(SDIO_WAITTYPE_NO);
  73.         sdio_csm_enable();
  74.         /* check if some error occurs */
  75.         status = r1_error_check(SD_CMD_SEND_STATUS);
  76.         if(SD_OK != status){
  77.             return status;
  78.         }
  79.         response = sdio_response_get(SDIO_RESPONSE0);
  80.     }
  81.     if(0 == timeout){
  82.         return SD_ERROR;
  83.     }
  84.    
  85.     /* send CMD24(WRITE_BLOCK) to write a block */
  86.     sdio_command_response_config(SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT);
  87.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  88.     sdio_csm_enable();
  89.     /* check if some error occurs */
  90.     status = r1_error_check(SD_CMD_WRITE_BLOCK);
  91.     if(SD_OK != status){
  92.         return status;
  93.     }
  94.    
  95.     stopcondition = 0;
  96.     totalnumber_bytes = blocksize;
  97.    
  98.     /* configure the SDIO data transmission */
  99.     sdio_data_config(SD_DATATIMEOUT, totalnumber_bytes, datablksize);
  100.     sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
  101.     sdio_dsm_enable();
  102.    
  103.     if(SD_POLLING_MODE == transmode){
  104.         /* polling mode */
  105.         while(!sdio_flag_get(SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_TXURE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_STBITE)){
  106.             if(RESET != sdio_flag_get(SDIO_FLAG_TFH)){
  107.                 /* at least 8 words can be written into the FIFO */
  108.                 if((totalnumber_bytes - transbytes) < SD_FIFOHALF_BYTES){
  109.                     restwords = (totalnumber_bytes - transbytes)/4 + (((totalnumber_bytes - transbytes)%4 == 0) ? 0 : 1);
  110.                     for(count = 0; count < restwords; count++){
  111.                         sdio_data_write(*ptempbuff);
  112.                         ++ptempbuff;
  113.                         transbytes += 4;
  114.                     }
  115.                 }else{
  116.                     for(count = 0; count < SD_FIFOHALF_WORDS; count++){
  117.                         sdio_data_write(*(ptempbuff + count));
  118.                     }
  119.                     /* 8 words(32 bytes) has been transferred */
  120.                     ptempbuff += SD_FIFOHALF_WORDS;
  121.                     transbytes += SD_FIFOHALF_BYTES;
  122.                 }
  123.             }
  124.         }
  125.         
  126.         /* whether some error occurs and return it */
  127.         if(RESET != sdio_flag_get(SDIO_FLAG_DTCRCERR)){
  128.             status = SD_DATA_CRC_ERROR;
  129.             sdio_flag_clear(SDIO_FLAG_DTCRCERR);
  130.             return status;
  131.         }else if(RESET != sdio_flag_get(SDIO_FLAG_DTTMOUT)){
  132.             status = SD_DATA_TIMEOUT;
  133.             sdio_flag_clear(SDIO_FLAG_DTTMOUT);
  134.             return status;
  135.         }else if(RESET != sdio_flag_get(SDIO_FLAG_TXURE)){
  136.             status = SD_TX_UNDERRUN_ERROR;
  137.             sdio_flag_clear(SDIO_FLAG_TXURE);
  138.             return status;
  139.         }else if(RESET != sdio_flag_get(SDIO_FLAG_STBITE)){
  140.             status = SD_START_BIT_ERROR;
  141.             sdio_flag_clear(SDIO_FLAG_STBITE);
  142.             return status;
  143.         }
  144.     }else if(SD_DMA_MODE == transmode){
  145.         /* DMA mode */
  146.         /* enable the SDIO corresponding interrupts and DMA */
  147.         sdio_interrupt_enable(SDIO_INT_DTCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_TXURE | SDIO_INT_DTEND | SDIO_INT_STBITE);
  148.         dma_transfer_config(pwritebuffer, blocksize);
  149.         sdio_dma_enable();
  150.         
  151.         timeout = 100000;
  152.         while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)){
  153.             timeout--;
  154.             if(0 == timeout){
  155.                 return SD_ERROR;
  156.             }
  157.         }
  158.         while ((0 == transend) && (SD_OK == transerror)){
  159.         }

  160.         if(SD_OK != transerror){
  161.             return transerror;
  162.         }
  163.     }else{
  164.         status = SD_PARAMETER_INVALID;
  165.         return status;
  166.     }
  167.    
  168.     /* clear the SDIO_INTC flags */
  169.     sdio_flag_clear(SDIO_MASK_INTC_FLAGS);
  170.     /* get the card state and wait the card is out of programming and receiving state */
  171.     status = sd_card_state_get(&cardstate);
  172.     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))){
  173.         status = sd_card_state_get(&cardstate);
  174.     }
  175.     return status;
  176. }
23.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 = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = preadbuffer;
  7.     __IO uint32_t timeout = 0;
  8.    
  9.     if(NULL == preadbuffer){
  10.         status = SD_PARAMETER_INVALID;
  11.         return status;
  12.     }
  13.    
  14.     transerror = SD_OK;
  15.     transend = 0;
  16.     totalnumber_bytes = 0;
  17.     /* clear all DSM configuration */
  18.     sdio_data_config(0, 0, SDIO_DATABLOCKSIZE_1BYTE);
  19.     sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
  20.     sdio_dsm_disable();
  21.     sdio_dma_disable();
  22.    
  23.     /* check whether the card is locked */
  24.     if(sdio_response_get(SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED){
  25.         status = SD_LOCK_UNLOCK_FAILED;
  26.         return status;
  27.     }
  28.    
  29.     /* blocksize is fixed in 512B for SDHC card */
  30.     if(SDIO_HIGH_CAPACITY_SD_CARD == cardtype){
  31.         blocksize = 512;
  32.         readaddr /= 512;
  33.     }
  34.    
  35.     align = blocksize & (blocksize - 1);
  36.     if((blocksize > 0) && (blocksize <= 2048) && (0 == align)){
  37.         datablksize = sd_datablocksize_get(blocksize);
  38.         /* send CMD16(SET_BLOCKLEN) to set the block length */
  39.         sdio_command_response_config(SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT);
  40.         sdio_wait_type_set(SDIO_WAITTYPE_NO);
  41.         sdio_csm_enable();
  42.         
  43.         /* check if some error occurs */
  44.         status = r1_error_check(SD_CMD_SET_BLOCKLEN);
  45.         if(SD_OK != status){
  46.             return status;
  47.         }
  48.     }else{
  49.         status = SD_PARAMETER_INVALID;
  50.         return status;
  51.     }
  52.    
  53.     stopcondition = 0;
  54.     totalnumber_bytes = blocksize;
  55.    
  56.     /* configure SDIO data transmission */
  57.     sdio_data_config(SD_DATATIMEOUT, totalnumber_bytes, datablksize);
  58.     sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOSDIO);
  59.     sdio_dsm_enable();
  60.    
  61.     /* send CMD17(READ_SINGLE_BLOCK) to read a block */
  62.     sdio_command_response_config(SD_CMD_READ_SINGLE_BLOCK, (uint32_t)readaddr, SDIO_RESPONSETYPE_SHORT);
  63.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  64.     sdio_csm_enable();
  65.     /* check if some error occurs */
  66.     status = r1_error_check(SD_CMD_READ_SINGLE_BLOCK);
  67.     if(SD_OK != status){
  68.         return status;
  69.     }
  70.    
  71.     if(SD_POLLING_MODE == transmode){
  72.         /* polling mode */
  73.         while(!sdio_flag_get(SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_RXORE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_STBITE)){
  74.             if(RESET != sdio_flag_get(SDIO_FLAG_RFH)){
  75.                 /* at least 8 words can be read in the FIFO */
  76.                 for(count = 0; count < SD_FIFOHALF_WORDS; count++){
  77.                     *(ptempbuff + count) = sdio_data_read();
  78.                 }
  79.                 ptempbuff += SD_FIFOHALF_WORDS;
  80.             }
  81.         }
  82.         
  83.         /* whether some error occurs and return it */
  84.         if(RESET != sdio_flag_get(SDIO_FLAG_DTCRCERR)){
  85.             status = SD_DATA_CRC_ERROR;
  86.             sdio_flag_clear(SDIO_FLAG_DTCRCERR);
  87.             return status;
  88.         }else if(RESET != sdio_flag_get(SDIO_FLAG_DTTMOUT)){
  89.             status = SD_DATA_TIMEOUT;
  90.             sdio_flag_clear(SDIO_FLAG_DTTMOUT);
  91.             return status;
  92.         }else if(RESET != sdio_flag_get(SDIO_FLAG_RXORE)){
  93.             status = SD_RX_OVERRUN_ERROR;
  94.             sdio_flag_clear(SDIO_FLAG_RXORE);
  95.             return status;
  96.         }else if(RESET != sdio_flag_get(SDIO_FLAG_STBITE)){
  97.             status = SD_START_BIT_ERROR;
  98.             sdio_flag_clear(SDIO_FLAG_STBITE);
  99.             return status;
  100.         }
  101.         while(RESET != sdio_flag_get(SDIO_FLAG_RXDTVAL)){
  102.             *ptempbuff = sdio_data_read();
  103.             ++ptempbuff;
  104.         }
  105.         /* clear the SDIO_INTC flags */
  106.         sdio_flag_clear(SDIO_MASK_INTC_FLAGS);
  107.     }else if(SD_DMA_MODE == transmode){
  108.         /* DMA mode */
  109.         /* enable the SDIO corresponding interrupts and DMA function */
  110.         sdio_interrupt_enable(SDIO_INT_CCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_RXORE | SDIO_INT_DTEND | SDIO_INT_STBITE);
  111.         sdio_dma_enable();
  112.         dma_receive_config(preadbuffer, blocksize);
  113.         timeout = 100000;
  114.         while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)){
  115.             timeout--;
  116.             if(0 == timeout){
  117.                 return SD_ERROR;
  118.             }
  119.         }
  120.     }else{
  121.         status = SD_PARAMETER_INVALID;
  122.     }
  123.     return status;
  124. }
23.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 = 0, tempbyte = 0;
  6.     uint32_t pwd1 = 0, pwd2 = 0, response = 0;
  7.     __IO uint32_t timeout = 0;
  8.     uint16_t tempccc = 0;
  9.    
  10.     /* get the card command classes from CSD */
  11.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_24_31BITS) >> 24);
  12.     tempccc = (uint16_t)((uint16_t)tempbyte << 4);
  13.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_16_23BITS) >> 16);
  14.     tempccc |= (uint16_t)((uint16_t)(tempbyte & 0xF0) >> 4);
  15.    
  16.     if(0 == (tempccc & SD_CCC_LOCK_CARD)){
  17.         /* don't support the lock command */
  18.         status = SD_FUNCTION_UNSUPPORTED;
  19.         return status;
  20.     }
  21.     /* password pattern */
  22.     pwd1 = (0x01020600|lockstate);
  23.     pwd2 = 0x03040506;
  24.    
  25.     /* clear all DSM configuration */
  26.     sdio_data_config(0, 0, SDIO_DATABLOCKSIZE_1BYTE);
  27.     sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
  28.     sdio_dsm_disable();
  29.     sdio_dma_disable();
  30.    
  31.     /* send CMD16(SET_BLOCKLEN) to set the block length */
  32.     sdio_command_response_config(SD_CMD_SET_BLOCKLEN, (uint32_t)8, SDIO_RESPONSETYPE_SHORT);
  33.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  34.     sdio_csm_enable();
  35.     /* check if some error occurs */
  36.     status = r1_error_check(SD_CMD_SET_BLOCKLEN);
  37.     if(SD_OK != status){
  38.         return status;
  39.     }
  40.    
  41.     /* send CMD13(SEND_STATUS), addressed card sends its status register */
  42.     sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  43.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  44.     sdio_csm_enable();
  45.     /* check if some error occurs */
  46.     status = r1_error_check(SD_CMD_SEND_STATUS);
  47.     if(SD_OK != status){
  48.         return status;
  49.     }
  50.    
  51.     response = sdio_response_get(SDIO_RESPONSE0);
  52.     timeout = 100000;
  53.     while((0 == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0)){
  54.         /* continue to send CMD13 to polling the state of card until buffer empty or timeout */
  55.         --timeout;
  56.         /* send CMD13(SEND_STATUS), addressed card sends its status registers */
  57.         sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
  58.         sdio_wait_type_set(SDIO_WAITTYPE_NO);
  59.         sdio_csm_enable();
  60.         /* check if some error occurs */
  61.         status = r1_error_check(SD_CMD_SEND_STATUS);
  62.         if(SD_OK != status){
  63.             return status;
  64.         }
  65.         response = sdio_response_get(SDIO_RESPONSE0);
  66.     }
  67.     if(0 == timeout){
  68.         return SD_ERROR;
  69.     }
  70.    
  71.     /* send CMD42(LOCK_UNLOCK) to set/reset the password or lock/unlock the card */
  72.     sdio_command_response_config(SD_CMD_LOCK_UNLOCK, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
  73.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  74.     sdio_csm_enable();
  75.     /* check if some error occurs */
  76.     status = r1_error_check(SD_CMD_LOCK_UNLOCK);
  77.     if(SD_OK != status){
  78.         return status;
  79.     }
  80.    
  81.     response = sdio_response_get(SDIO_RESPONSE0);
  82.    
  83.     /* configure the SDIO data transmission */
  84.     sdio_data_config(SD_DATATIMEOUT, (uint32_t)8, SDIO_DATABLOCKSIZE_8BYTES);
  85.     sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
  86.     sdio_dsm_enable();
  87.    
  88.     /* write password pattern */
  89.     sdio_data_write(pwd1);
  90.     sdio_data_write(pwd2);
  91.    
  92.     /* whether some error occurs and return it */
  93.     if(RESET != sdio_flag_get(SDIO_FLAG_DTCRCERR)){
  94.         status = SD_DATA_CRC_ERROR;
  95.         sdio_flag_clear(SDIO_FLAG_DTCRCERR);
  96.         return status;
  97.     }else if(RESET != sdio_flag_get(SDIO_FLAG_DTTMOUT)){
  98.         status = SD_DATA_TIMEOUT;
  99.         sdio_flag_clear(SDIO_FLAG_DTTMOUT);
  100.         return status;
  101.     }else if(RESET != sdio_flag_get(SDIO_FLAG_TXURE)){
  102.         status = SD_TX_UNDERRUN_ERROR;
  103.         sdio_flag_clear(SDIO_FLAG_TXURE);
  104.         return status;
  105.     }else if(RESET != sdio_flag_get(SDIO_FLAG_STBITE)){
  106.         status = SD_START_BIT_ERROR;
  107.         sdio_flag_clear(SDIO_FLAG_STBITE);
  108.         return status;
  109.     }
  110.    
  111.     /* clear the SDIO_INTC flags */
  112.     sdio_flag_clear(SDIO_MASK_INTC_FLAGS);
  113.     /* get the card state and wait the card is out of programming and receiving state */
  114.     status = sd_card_state_get(&cardstate);
  115.     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))){
  116.         status = sd_card_state_get(&cardstate);
  117.     }
  118.     return status;
  119. }
23.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 = 0, clkdiv = 0;
  7.     __IO uint32_t delay = 0;
  8.     uint8_t cardstate = 0, tempbyte = 0;
  9.     uint16_t tempccc = 0;
  10.    
  11.     /* get the card command classes from CSD */
  12.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_24_31BITS) >> 24);
  13.     tempccc = (uint16_t)((uint16_t)tempbyte << 4);
  14.     tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_16_23BITS) >> 16);
  15.     tempccc |= (uint16_t)((uint16_t)(tempbyte & 0xF0) >> 4);
  16.     if(0 == (tempccc & SD_CCC_ERASE)){
  17.         /* don't support the erase command */
  18.         status = SD_FUNCTION_UNSUPPORTED;
  19.         return status;
  20.     }
  21.     clkdiv = (SDIO_CLKCTL & SDIO_CLKCTL_DIV);
  22.     clkdiv += ((SDIO_CLKCTL & SDIO_CLKCTL_DIV8)>>31)*256;
  23.     clkdiv += 2;
  24.     delay = 120000 / clkdiv;
  25.    
  26.     /* check whether the card is locked */
  27.     if (sdio_response_get(SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED){
  28.         status = SD_LOCK_UNLOCK_FAILED;
  29.         return(status);
  30.     }
  31.    
  32.     /* blocksize is fixed in 512B for SDHC card */
  33.     if (SDIO_HIGH_CAPACITY_SD_CARD == cardtype){
  34.         startaddr /= 512;
  35.         endaddr /= 512;
  36.     }
  37.    
  38.     if((SDIO_STD_CAPACITY_SD_CARD_V1_1 == cardtype) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == cardtype) ||
  39.         (SDIO_HIGH_CAPACITY_SD_CARD == cardtype)){
  40.         /* send CMD32(ERASE_WR_BLK_START) to set the address of the first write block to be erased */
  41.         sdio_command_response_config(SD_CMD_ERASE_WR_BLK_START, startaddr, SDIO_RESPONSETYPE_SHORT);
  42.         sdio_wait_type_set(SDIO_WAITTYPE_NO);
  43.         sdio_csm_enable();
  44.         /* check if some error occurs */
  45.         status = r1_error_check(SD_CMD_ERASE_WR_BLK_START);
  46.         if(SD_OK != status){
  47.             return status;
  48.         }
  49.         
  50.         /* send CMD33(ERASE_WR_BLK_END) to set the address of the last write block of the continuous range to be erased */
  51.         sdio_command_response_config(SD_CMD_ERASE_WR_BLK_END, endaddr, SDIO_RESPONSETYPE_SHORT);
  52.         sdio_wait_type_set(SDIO_WAITTYPE_NO);
  53.         sdio_csm_enable();
  54.         /* check if some error occurs */
  55.         status = r1_error_check(SD_CMD_ERASE_WR_BLK_END);
  56.         if(SD_OK != status){
  57.             return status;
  58.         }
  59.     }
  60.    
  61.     /* send CMD38(ERASE) to set the address of the first write block to be erased */
  62.     sdio_command_response_config(SD_CMD_ERASE, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
  63.     sdio_wait_type_set(SDIO_WAITTYPE_NO);
  64.     sdio_csm_enable();
  65.     /* check if some error occurs */
  66.     status = r1_error_check(SD_CMD_ERASE);
  67.     if(SD_OK != status){
  68.         return status;
  69.     }
  70.     /* loop until the counter is reach to the calculated time */
  71.     for(count = 0; count < delay; count++){
  72.     }
  73.     /* get the card state and wait the card is out of programming and receiving state */
  74.     status = sd_card_state_get(&cardstate);
  75.     while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))){
  76.         status = sd_card_state_get(&cardstate);
  77.     }
  78.     return status;
  79. }
23.4.7 主函数
SD卡主函数如下,可实现对SD卡的擦写读以及加锁解锁操作。
  1. C
  2. int main(void)
  3. {
  4.     sd_error_enum sd_error;
  5.     uint16_t i = 5;
  6. #ifdef DATA_PRINT
  7.     uint8_t *pdata;
  8. #endif /* DATA_PRINT */
  9.    
  10.     /* configure the NVIC, USART and LED */
  11.     nvic_config();
  12.          
  13.           bsp_uart_init(&BOARD_UART);
  14.    
  15.     /* initialize the card */
  16.     do{
  17.         sd_error = sd_io_init();
  18.     }while((SD_OK != sd_error) && (--i));
  19.    
  20.     if(i){
  21.         printf("\r\n Card init success!\r\n");
  22.     }else{
  23.         printf("\r\n Card init failed!\r\n");
  24.         while (1){
  25.         }
  26.     }
  27.    
  28.     /* get the information of the card and print it out by USART */
  29.     card_info_get();
  30.    
  31.     /* init the write buffer */
  32.     for(i=0; i<512; i++){
  33.         buf_write[i] = i;
  34.     }
  35.    
  36.     printf("\r\n\r\n Card test:");
  37.    
  38.     /* single block operation test */
  39.     sd_error = sd_block_write(buf_write, 100*512, 512);
  40.     if(SD_OK != sd_error){
  41.                         
  42.         printf("\r\n Block write fail!");
  43.         while (1){
  44.         }
  45.     }else{
  46.         printf("\r\n Block write success!");
  47.     }
  48.     sd_error = sd_block_read(buf_read, 100*512, 512);
  49.     if(SD_OK != sd_error){
  50.         printf("\r\n Block read fail!");

  51.         while (1){
  52.         }
  53.     }else{
  54.         //printf("\r\n Block read success!");
  55. #ifdef DATA_PRINT
  56.         pdata = (uint8_t *)buf_read;
  57.         /* print data by USART */
  58.         printf("\r\n");
  59.         for(i = 0; i < 128; i++){
  60.             printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
  61.             pdata += 4;
  62.             if(0 == (i + 1) % 4){
  63.                 printf("\r\n");
  64.             }
  65.         }
  66. #endif /* DATA_PRINT */
  67.     }
  68.    
  69.     /* lock and unlock operation test */
  70.     if(SD_CCC_LOCK_CARD & sd_cardinfo.card_csd.ccc){
  71.         /* lock the card */
  72.         sd_error = sd_lock_unlock(SD_LOCK);
  73.         if(SD_OK != sd_error){
  74.             printf("\r\n Lock failed!");
  75.             while (1){
  76.             }
  77.         }else{
  78.             printf("\r\n The card is locked!");
  79.         }
  80.         sd_error = sd_erase(100*512, 101*512);
  81.         if(SD_OK != sd_error){
  82.             printf("\r\n Erase failed!");
  83.         }else{
  84.                                         __NOP();
  85.             printf("\r\n Erase success!");
  86.         }
  87.         
  88.         /* unlock the card */
  89.         sd_error = sd_lock_unlock(SD_UNLOCK);
  90.         if(SD_OK != sd_error){
  91.             printf("\r\n Unlock failed!");
  92.             while (1){
  93.             }
  94.         }else{
  95.             printf("\r\n The card is unlocked!");
  96.         }
  97.         sd_error = sd_erase(100*512, 101*512);
  98.         if(SD_OK != sd_error){
  99.             printf("\r\n Erase failed!");
  100.         }else{
  101.             printf("\r\n Erase success!");
  102.         }
  103.         
  104.         sd_error = sd_block_read(buf_read, 100*512, 512);
  105.         if(SD_OK != sd_error){
  106.             printf("\r\n Block read fail!");
  107.             while (1){
  108.             }
  109.         }else{
  110.             printf("\r\n Block read success!");
  111. #ifdef DATA_PRINT
  112.         pdata = (uint8_t *)buf_read;
  113.         /* print data by USART */
  114.         printf("\r\n");
  115.         for(i = 0; i < 128; i++){
  116.             printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
  117.             pdata += 4;
  118.             if(0 == (i + 1) % 4){
  119.                 printf("\r\n");
  120.             }
  121.         }
  122. #endif /* DATA_PRINT */
  123.         }
  124.     }
  125.    
  126.     /* multiple blocks operation test */
  127.     sd_error = sd_multiblocks_write(buf_write, 200*512, 512, 3);
  128.     if(SD_OK != sd_error){
  129.         printf("\r\n Multiple block write fail!");
  130.         while (1){
  131.         }
  132.     }else{
  133.         printf("\r\n Multiple block write success!");
  134.     }
  135.     sd_error = sd_multiblocks_read(buf_read, 200*512, 512, 3);
  136.     if(SD_OK != sd_error){
  137.         printf("\r\n Multiple block read fail!");

  138.         while (1){
  139.         }
  140.     }else{
  141.         printf("\r\n Multiple block read success!");
  142. #ifdef DATA_PRINT
  143.         pdata = (uint8_t *)buf_read;
  144.         /* print data by USART */
  145.         printf("\r\n");
  146.         for(i = 0; i < 512; i++){
  147.             printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
  148.             pdata += 4;
  149.             if(0 == (i + 1) % 4){
  150.                 printf("\r\n");
  151.             }
  152.         }
  153. #endif /* DATA_PRINT */
  154.     }
  155.    
  156.     while (1){
  157.     }
  158. }
23.5 实验结果
SD卡读写实验例程烧录到红枫派开发板中,并在卡槽中插入SD卡,打开对应串口复位芯片,将会观察到SD卡相关操作结果。
图片14.png

本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462



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

本版积分规则

170

主题

190

帖子

13

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