711|1

445

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【兆易GD32H759I-EVAL】--4.SD卡测试 [复制链接]

  本帖最后由 dirty 于 2024-5-12 19:34 编辑

      本篇讲述开发板SD卡读写.

一.硬件原理

      开发板板载SD卡座,插入SD卡,可数据块读写、擦除、上锁与解锁。SD卡引脚定义:PD2--CMD、PC12--CLK、PB13--D0、PC9--D1、PC10--D2、PC11--D3.

 

图1:SDIO接口卡座

引脚                           功能

VCC                      电源

GND                       地

D0                          数据传输引脚,用于单线双向数据传输

D1、D2、D3         附加数据传输引脚

CMD                     命令传输引脚,用于控制sd卡的命令传输

CLK                      时钟引脚,提供时钟信号以同步数据传输

CD                       卡位检测脚,用于检测SD卡是否插入卡槽

 

      跳线帽连接:JP16跳线帽PB13脚与SDIO_D0引脚短接。JP64、JP52、JP62同样打到SDIO侧。

 

二.代码准备

1.引脚初始化

/*!
    \brief      configure the GPIO of SDIO interface
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void gpio_config(void)
{
    /* configure the SDIO_DAT0(PB13), SDIO_DAT1(PC9), SDIO_DAT2(PC10), SDIO_DAT3(PC11), SDIO_CLK(PC12) and SDIO_CMD(PD2) */
    gpio_af_set(GPIOB, GPIO_AF_12, GPIO_PIN_13);
    gpio_af_set(GPIOC, GPIO_AF_12, GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
    gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_2);

    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_13);
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);

    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_13);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);

    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_12);

    gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_2);
}

2.初始化SD,获取CID与CSD

/*!
    \brief      initialize the card and get CID and CSD of the card
    \param[in]  none
    \param[out] none
    \retval     sd_error_enum
*/
sd_error_enum sd_card_init(void)
{
    sd_error_enum status = SD_OK;
    uint16_t temp_rca = 0x01U;

    if(SDIO_POWER_OFF == sdio_power_state_get(SDIO)) {
        status = SD_OPERATION_IMPROPER;
        return status;
    }

    /* the card is not I/O only card */
    if(SDIO_SECURE_DIGITAL_IO_CARD != cardtype) {
        /* send CMD2(SD_CMD_ALL_SEND_CID) to get the CID numbers */
        sdio_command_response_config(SDIO, SD_CMD_ALL_SEND_CID, (uint32_t)0x0, SDIO_RESPONSETYPE_LONG);
        sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
        sdio_csm_enable(SDIO);
        /* check if some error occurs */
        status = r2_error_check();
        if(SD_OK != status) {
            return status;
        }

        /* store the CID numbers */
        sd_cid[0] = sdio_response_get(SDIO, SDIO_RESPONSE0);
        sd_cid[1] = sdio_response_get(SDIO, SDIO_RESPONSE1);
        sd_cid[2] = sdio_response_get(SDIO, SDIO_RESPONSE2);
        sd_cid[3] = sdio_response_get(SDIO, SDIO_RESPONSE3);
    }

    /* the card is SD memory card or the I/O card has the memory portion */
    if((SDIO_STD_CAPACITY_SD_CARD_V1_1 == cardtype) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == cardtype) || (SDIO_STD_CAPACITY_SD_CARD_V3_0 == cardtype) ||
            (SDIO_HIGH_CAPACITY_SD_CARD == cardtype) || (SDIO_SECURE_DIGITAL_IO_COMBO_CARD == cardtype)) {
        /* send CMD3(SEND_RELATIVE_ADDR) to ask the card to publish a new relative address (RCA) */
        sdio_command_response_config(SDIO, SD_CMD_SEND_RELATIVE_ADDR, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
        sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
        sdio_csm_enable(SDIO);
        /* check if some error occurs */
        status = r6_error_check(SD_CMD_SEND_RELATIVE_ADDR, &temp_rca);
        if(SD_OK != status) {
            return status;
        }
    }

    if(SDIO_SECURE_DIGITAL_IO_CARD != cardtype) {
        /* the card is not I/O only card */
        sd_rca = temp_rca;

        /* send CMD9(SEND_CSD) to get the addressed card's card-specific data (CSD) */
        sdio_command_response_config(SDIO, (uint32_t)SD_CMD_SEND_CSD, ((uint32_t)temp_rca) << SD_RCA_SHIFT, SDIO_RESPONSETYPE_LONG);
        sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO);
        sdio_csm_enable(SDIO);
        /* check if some error occurs */
        status = r2_error_check();
        if(SD_OK != status) {
            return status;
        }

        /* store the card-specific data (CSD) */
        sd_csd[0] = sdio_response_get(SDIO, SDIO_RESPONSE0);
        sd_csd[1] = sdio_response_get(SDIO, SDIO_RESPONSE1);
        sd_csd[2] = sdio_response_get(SDIO, SDIO_RESPONSE2);
        sd_csd[3] = sdio_response_get(SDIO, SDIO_RESPONSE3);
    }
    return status;
}

3.初始化SD Card并置到待机状态

/*!
    \brief      initialize the SD card and make it in standby state
    \param[in]  none
    \param[out] none
    \retval     sd_error_enum
*/
sd_error_enum sd_init(void)
{
    sd_error_enum status = SD_OK;
    /* configure the RCU and GPIO, deinitialize the SDIO */
    rcu_config();
    gpio_config();
    sdio_deinit(SDIO);

    /* configure the clock and work voltage */
    status = sd_power_on();
    if(SD_OK != status) {
        return status;
    }

    /* initialize the card and get CID and CSD of the card */
    status = sd_card_init();
    if(SD_OK != status) {
        return status;
    }

    /* configure the SDIO peripheral */
    sdio_clock_config(SDIO, SDIO_SDIOCLKEDGE_RISING, SDIO_CLOCKPWRSAVE_DISABLE, SD_CLK_DIV_INIT);
    sdio_bus_mode_set(SDIO, SDIO_BUSMODE_1BIT);
    sdio_hardware_clock_disable(SDIO);

    return status;
}

4.SD卡初始化并置到总线传输模式


/*!
    \brief      initialize the card, get the card information, set the bus mode and transfer mode
    \param[in]  none
    \param[out] none
    \retval     sd_error_enum
*/
sd_error_enum sd_io_init(void)
{
    sd_error_enum status = SD_OK;
    uint32_t cardstate = 0;

    status = sd_init();
    if(SD_OK == status) {
        status = sd_card_information_get(&sd_cardinfo);
    }
    if(SD_OK == status) {
        status = sd_card_select_deselect(sd_cardinfo.card_rca);
    }
    status = sd_cardstatus_get(&cardstate);
    if(cardstate & 0x02000000) {
        printf("\r\n the card is locked!");
        status = sd_lock_unlock(SD_UNLOCK);
        if(status != SD_OK) {
            return SD_LOCK_UNLOCK_FAILED;
        } else {
            printf("\r\n the card is unlocked successfully!");
        }
    }

    if((SD_OK == status) && (!(cardstate & 0x02000000))) {
        /* set bus mode */
#if (SDIO_BUSMODE == BUSMODE_4BIT)
        status = sd_bus_mode_config(SDIO_BUSMODE_4BIT, SDIO_SPEEDMODE);
#else
        status = sd_bus_mode_config(SDIO_BUSMODE_1BIT, SDIO_SPEEDMODE);
#endif
    }

    if(SD_OK == status) {
        /* set data transfer mode */
        status = sd_transfer_mode_config(SDIO_DTMODE);
    }
    return status;
}

5.获取sd卡信息,包含有SD卡容量、卡类、操作支持情况等。

/*!
    \brief      get the card information and print it out by USRAT
    \param[in]  none
    \param[out] none
    \retval     none
*/
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_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_security = (sd_scr[1] & 0x00700000) >> 20;
    if(2 == sd_security) {
        printf("\r\n## security v1.01 ##");
    } else if(3 == sd_security) {
        printf("\r\n## security v2.00 ##");
    } else if(4 == sd_security) {
        printf("\r\n## security v3.00 ##");
    }

    block_count = (sd_cardinfo.card_csd.c_size + 1) * 1024;
    block_size = 512;
    printf("\r\n## Device size is %dKB ##", sd_card_capacity_get());
    printf("\r\n## Block size is %dB ##", block_size);
    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 ##");
    }
    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 ##");
    }
}

6.main函数如下

int main()
{
    sd_error_enum sd_error;
    ErrStatus state = ERROR;

    uint16_t i = 5;
#ifdef DATA_PRINT
    uint8_t *pdata;
#endif /* DATA_PRINT */

    /* enable the CPU Cache */
    cache_enable();

    /* configure the NVIC and USART */
    nvic_config();
    systick_config();
    gd_eval_com_init(EVAL_COM);
    gd_eval_led_init(LED1);
    gd_eval_led_init(LED2);

    /* turn off all the LEDs */
    gd_eval_led_off(LED1);
    gd_eval_led_off(LED2);

    /* flash the LEDs for 1 time */
    led_flash(1);

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

    if(i) {
        printf("\r\n Card init success!\r\n");
    } else {
        printf("\r\n Card init failed!\r\n");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    }

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


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

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

    printf("\r\n\r\n Card test:");
    /* single block operation test */
    sd_error = sd_block_write(buf_write, 100, 512);
    if(SD_OK != sd_error) {
        printf("\r\n Block write fail!");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    } else {
        printf("\r\n Block write success!");
    }

    sd_error = sd_block_read(buf_read, 100, 512);
    if(SD_OK != sd_error) {
        printf("\r\n Block read fail!");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    } else {
        printf("\r\n Block read success!");
#ifdef DATA_PRINT
        SCB_CleanInvalidateDCache_by_Addr(buf_read, 512 * 4);
        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");
            }
        }
#endif /* DATA_PRINT */
    }

    /* compare the write date and the read data */
    state = memory_compare(buf_write, buf_read, 128);
    if(SUCCESS == state) {
        printf("\r\n Single block read compare successfully!");
    } else {
        printf("\r\n Single block read compare fail!");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    }

    /* 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);
        if(SD_OK != sd_error) {
            printf("\r\n Lock failed!");
            /* turn on LED1, LED2 */
            gd_eval_led_on(LED1);
            gd_eval_led_on(LED2);
            while(1) {
            }
        } else {
            printf("\r\n The card is locked!");
        }
        sd_error = sd_erase(100, 101);
        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);
        if(SD_OK != sd_error) {
            printf("\r\n Unlock failed!");
            /* turn on LED1, LED2 */
            gd_eval_led_on(LED1);
            gd_eval_led_on(LED2);
            while(1) {
            }
        } else {
            printf("\r\n The card is unlocked!");
        }
        sd_error = sd_erase(100, 101);
        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);
        if(SD_OK != sd_error) {
            printf("\r\n Block read fail!");
            /* turn on LED1, LED2 */
            gd_eval_led_on(LED1);
            gd_eval_led_on(LED2);
            while(1) {
            }
        } else {
            printf("\r\n Block read success!");
#ifdef DATA_PRINT
            SCB_CleanInvalidateDCache_by_Addr(buf_read, 512 * 4);
            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");
                }
            }
#endif /* DATA_PRINT */
        }
    }

    /* multiple blocks operation test */
    sd_error = sd_multiblocks_write(buf_write, 200, 512, 3);
    if(SD_OK != sd_error) {
        printf("\r\n Multiple block write fail!");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    } else {
        printf("\r\n Multiple block write success!");
    }

    sd_error = sd_multiblocks_read(buf_read, 200, 512, 3);
    if(SD_OK != sd_error) {
        printf("\r\n Multiple block read fail!");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    } else {
        printf("\r\n Multiple block read success!");
#ifdef DATA_PRINT
        SCB_CleanInvalidateDCache_by_Addr(buf_read, 512 * 4);
        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");
            }
        }
#endif /* DATA_PRINT */
    }
    /* compare the write date and the read data */
    state = memory_compare(buf_write, buf_read, 128 * 3);
    if(SUCCESS == state) {
        printf("\r\n Multiple block read compare successfully!");
    } else {
        printf("\r\n Multiple block read compare fail!");
        /* turn on LED1, LED2 */
        gd_eval_led_on(LED1);
        gd_eval_led_on(LED2);
        while(1) {
        }
    }
    printf("\r\n SD card test successfully!");

    while(1) {};
}

 

三.编译烧录测试

      断电插上SD卡,上电编译烧录后,在SDIO接口引脚跳线帽连接正确情况下,SD卡测试日志如下:

图2:SD卡测试

 

      从日志可以看到SDk卡容量32GB,卡的操作支持情况以及SD卡的读写情况。至此,对SD卡功能进行了测验。

 

最新回复

学习了对SD卡功能进行了测验,挺好   详情 回复 发表于 2024-5-12 21:58
点赞 关注
 
 

回复
举报

6587

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

学习了对SD卡功能进行了测验,挺好

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表