【兆易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卡功能进行了测验。
|