SD卡,即安全数码卡(Secure Digital ),GD32的SDIO接口可以用来驱动SD卡,另外,SDIO还定义了SD I/O卡、多媒体卡(MMC)和CE-ATA卡主机接口。
板子上的SD卡接口原理图:
microSD卡又叫TF卡,是SD卡的缩小版,平时用的较多也是microSD,也经常习惯把microSD卡叫做SD卡。
GD32的SDIO 的结构框图如下图,主要由APB 接口和SDIO 适配器两大部分组成。
APB 接口:包括通过APB2 总线访问的寄存器、用于数据传输的FIFO 单元以及产生中断和DMA 请求信号。
寄存器单元:包含所有的系统寄存器,生成信号用于控制卡与控制器之间的通信。
数据FIFO 单元:有一个数据缓冲区,用于发送和接收 FIFO
SDIO 适配器:由控制单元、命令单元和数据单元组成。控制单元管理时钟信号,命令单元管理命令的传输,数据单元管理数据的传输。
SDIO_CLK:SDIO 控制器提供给卡的时钟。每个时钟周期在命令线(SDIO_CMD)和所有的数据线(SDIO_DAT)上直接发送一位命令或数据。对于SD卡可以在0 MHz 到25 MHz。
SDIO_CMD:该信号是双向命令通道,用于卡的初始化和命令的传输。命令从SDIO 控制器发送到卡,响应从卡发送到主机。
SDIO_DAT[7:0]:这些信号线都是双向数据通道。数据信号线操作在推挽模式。每次只有卡或者主机会驱动这些信号。默认情况下,上电或者复位后仅 DAT0 用于数据传输。
SDIO通过发送各种命令的方式来操作SD卡,如下图:
程序中的命令列表:
/* SD memory card bus commands index */
#define SD_CMD_GO_IDLE_STATE ((uint8_t)0) /* CMD0, GO_IDLE_STATE */
#define SD_CMD_ALL_SEND_CID ((uint8_t)2) /* CMD2, ALL_SEND_CID */
#define SD_CMD_SEND_RELATIVE_ADDR ((uint8_t)3) /* CMD3, SEND_RELATIVE_ADDR */
#define SD_CMD_SET_DSR ((uint8_t)4) /* CMD4, SET_DSR */
#define SD_CMD_SWITCH_FUNC ((uint8_t)6) /* CMD6, SWITCH_FUNC */
#define SD_CMD_SELECT_DESELECT_CARD ((uint8_t)7) /* CMD7, SELECT_DESELECT_CARD */
#define SD_CMD_SEND_IF_COND ((uint8_t)8) /* CMD8, SEND_IF_COND */
#define SD_CMD_SEND_CSD ((uint8_t)9) /* CMD9, SEND_CSD */
#define SD_CMD_SEND_CID ((uint8_t)10) /* CMD10, SEND_CID */
#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12) /* CMD12, STOP_TRANSMISSION */
#define SD_CMD_SEND_STATUS ((uint8_t)13) /* CMD13, SEND_STATUS */
#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15) /* CMD15, GO_INACTIVE_STATE */
#define SD_CMD_SET_BLOCKLEN ((uint8_t)16) /* CMD16, SET_BLOCKLEN */
#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17) /* CMD17, READ_SINGLE_BLOCK */
#define SD_CMD_READ_MULTIPLE_BLOCK ((uint8_t)18) /* CMD18, READ_MULTIPLE_BLOCK */
#define SD_CMD_WRITE_BLOCK ((uint8_t)24) /* CMD24, WRITE_BLOCK */
#define SD_CMD_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /* CMD25, WRITE_MULTIPLE_BLOCK */
#define SD_CMD_PROG_CSD ((uint8_t)27) /* CMD27, PROG_CSD */
#define SD_CMD_SET_WRITE_PROT ((uint8_t)28) /* CMD28, SET_WRITE_PROT */
#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29) /* CMD29, CLR_WRITE_PROT */
#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30) /* CMD30, SEND_WRITE_PROT */
#define SD_CMD_ERASE_WR_BLK_START ((uint8_t)32) /* CMD32, ERASE_WR_BLK_START */
#define SD_CMD_ERASE_WR_BLK_END ((uint8_t)33) /* CMD33, ERASE_WR_BLK_END */
#define SD_CMD_ERASE ((uint8_t)38) /* CMD38, ERASE */
#define SD_CMD_LOCK_UNLOCK ((uint8_t)42) /* CMD42, LOCK_UNLOCK */
#define SD_CMD_APP_CMD ((uint8_t)55) /* CMD55, APP_CMD */
#define SD_CMD_GEN_CMD ((uint8_t)56) /* CMD56, GEN_CMD */
/* SD memory card application specific commands index */
#define SD_APPCMD_SET_BUS_WIDTH ((uint8_t)6) /* ACMD6, SET_BUS_WIDTH */
#define SD_APPCMD_SD_STATUS ((uint8_t)13) /* ACMD13, SD_STATUS */
#define SD_APPCMD_SEND_NUM_WR_BLOCKS ((uint8_t)22) /* ACMD22, SEND_NUM_WR_BLOCKS */
#define SD_APPCMD_SET_WR_BLK_ERASE_COUNT ((uint8_t)23) /* ACMD23, SET_WR_BLK_ERASE_COUNT */
#define SD_APPCMD_SD_SEND_OP_COND ((uint8_t)41) /* ACMD41, SD_SEND_OP_COND */
#define SD_APPCMD_SET_CLR_CARD_DETECT ((uint8_t)42) /* ACMD42, SET_CLR_CARD_DETECT */
#define SD_APPCMD_SEND_SCR ((uint8_t)51) /* ACMD51, SEND_SCR */
sd_error_enum sd_config(void)
{
sd_error_enum status = SD_OK;
uint32_t cardstate = 0;
/* initialize the card */
status = sd_init();//SD卡初始化---GPIO、SDIO
if(SD_OK == status)
{
status = sd_card_information_get(&sd_cardinfo);//获取SD卡信息
}
if(SD_OK == status)
{
status = sd_card_select_deselect(sd_cardinfo.card_rca);//挂载SD卡
}
status = sd_cardstatus_get(&cardstate);
if(cardstate & 0x02000000)
{
printf("\r\n the card is locked!");
while (1){
}
}
if ((SD_OK == status) && (!(cardstate & 0x02000000)))
{
/* set bus mode */
status = sd_bus_mode_config(SDIO_BUSMODE_4BIT);//配置总线模式
}
if (SD_OK == status)
{
/* set data transfer mode */
status = sd_transfer_mode_config( SD_POLLING_MODE );//配置传输模式
}
return status;
}
包括sd卡的版本,类型,容量,块大小与数量等。
void card_info_get(void)
{
uint8_t sd_spec, sd_spec3, sd_spec4, sd_security;
uint32_t block_count, block_size;
uint16_t temp_ccc;
printf("\r\n Card information:");
//SD卡版本
sd_spec = (sd_scr[1] & 0x0F000000) >> 24;
sd_spec3 = (sd_scr[1] & 0x00008000) >> 15;
sd_spec4 = (sd_scr[1] & 0x00000400) >> 10;
if(2 == sd_spec)
{
if(1 == sd_spec3)
{
if(1 == sd_spec4)
{
printf("\r\n## Card version 4.xx ##");
}
else
{
printf("\r\n## Card version 3.0x ##");
}
}
else
{
printf("\r\n## Card version 2.00 ##");
}
}
else if(1 == sd_spec)
{
printf("\r\n## Card version 1.10 ##");
}
else if(0 == sd_spec)
{
printf("\r\n## Card version 1.0x ##");
}
//SD卡类型
sd_security = (sd_scr[1] & 0x00700000) >> 20;
if(2 == sd_security)
{
printf("\r\n## SDSC card ##");//标准容量卡SDSC,最大2G
}
else if(3 == sd_security)
{
printf("\r\n## SDHC card ##");//高容量卡SDHC,最大32G
}
else if(4 == sd_security)
{
printf("\r\n## SDXC card ##");
}
block_count = (sd_cardinfo.card_csd.c_size + 1)*1024;
block_size = 512;
//SD卡容量
printf("\r\n## Device size is %dKB ##", sd_card_capacity_get());
//SD卡 块的大小
printf("\r\n## Block size is %dB ##", block_size);
//SD卡 块的个数
printf("\r\n## Block count is %d ##", block_count);
if(sd_cardinfo.card_csd.read_bl_partial)
{
printf("\r\n## Partial blocks for read allowed ##" );
}
if(sd_cardinfo.card_csd.write_bl_partial)
{
printf("\r\n## Partial blocks for write allowed ##" );
}
//SD卡 卡命令集
temp_ccc = sd_cardinfo.card_csd.ccc;
printf("\r\n## CardCommandClasses is: %x ##", temp_ccc);
if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc))
{
printf("\r\n## Block operation supported ##");
}
if(SD_CCC_ERASE & temp_ccc)
{
printf("\r\n## Erase supported ##");
}
if(SD_CCC_WRITE_PROTECTION & temp_ccc)
{
printf("\r\n## Write protection supported ##");
}
if(SD_CCC_LOCK_CARD & temp_ccc)
{
printf("\r\n## Lock unlock supported ##");
}
if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc)
{
printf("\r\n## Application specific supported ##");
}
if(SD_CCC_IO_MODE & temp_ccc)
{
printf("\r\n## I/O mode supported ##");
}
if(SD_CCC_SWITCH & temp_ccc)
{
printf("\r\n## Switch function supported ##");
}
}
//开始SD卡测试
printf("\r\n\r\n Card test:");
/* single block operation test =============单个块读写测试============= */
sd_error = sd_block_write(buf_write, 100*512, 512);//---------写入数据
if(SD_OK != sd_error)
{
printf("\r\n Block write fail!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1)
{
}
}
else
{
printf("\r\n Block write success!");
}
sd_error = sd_block_read(buf_read, 100*512, 512);//-----------读取数据
if(SD_OK != sd_error)
{
printf("\r\n Block read fail!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1)
{
}
}else
{
printf("\r\n Block read success!");
//打印读取到的数据
pdata = (uint8_t *)buf_read;
/* print data by USART */
printf("\r\n");
for(i = 0; i < 128; i++)
{
printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
pdata += 4;
if(0 == (i + 1) % 4)
{
printf("\r\n");
}
}
}
/* lock and unlock operation test */
if(SD_CCC_LOCK_CARD & sd_cardinfo.card_csd.ccc)
{
/* lock the card */
sd_error = sd_lock_unlock(SD_LOCK); //-----------SD卡加锁
if(SD_OK != sd_error)
{
printf("\r\n Lock failed!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1)
{
}
}else
{
printf("\r\n The card is locked!");
}
sd_error = sd_erase(100*512, 101*512);//-------------SD卡擦除
if(SD_OK != sd_error)
{
printf("\r\n Erase failed!");
}
else
{
printf("\r\n Erase success!");
}
/* unlock the card */
sd_error = sd_lock_unlock(SD_UNLOCK);//--------------SD卡解锁
if(SD_OK != sd_error)
{
printf("\r\n Unlock failed!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1){
}
}
else
{
printf("\r\n The card is unlocked!");
}
sd_error = sd_erase(100*512, 101*512);//------------SD卡擦除
if(SD_OK != sd_error){
printf("\r\n Erase failed!");
}else{
printf("\r\n Erase success!");
}
sd_error = sd_block_read(buf_read, 100*512, 512);//--------------SD卡读取
if(SD_OK != sd_error)
{
printf("\r\n Block read fail!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1){
}
}
else
{
printf("\r\n Block read success!");
pdata = (uint8_t *)buf_read;
/* print data by USART */
printf("\r\n");
for(i = 0; i < 128; i++)
{
printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
pdata += 4;
if(0 == (i + 1) % 4)
{
printf("\r\n");
}
}
}
}
/* multiple blocks operation test =============多个块读写测试============= */
sd_error = sd_multiblocks_write(buf_write, 200*512, 512, 3);//----------多个块写入数据
if(SD_OK != sd_error)
{
printf("\r\n Multiple block write fail!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1){
}
}
else
{
printf("\r\n Multiple block write success!");
}
sd_error = sd_multiblocks_read(buf_read, 200*512, 512, 3);//------------多个块读取数据
if(SD_OK != sd_error)
{
printf("\r\n Multiple block read fail!");
/* turn on LED1, LED3 and turn off LED2 */
gd_eval_led_on(LED1);
gd_eval_led_on(LED3);
gd_eval_led_off(LED2);
while (1){
}
}
else
{
printf("\r\n Multiple block read success!");
pdata = (uint8_t *)buf_read;
/* print data by USART */
printf("\r\n");
for(i = 0; i < 512; i++)
{
printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
pdata += 4;
if(0 == (i + 1) % 4)
{
printf("\r\n");
}
}
}
通过串口打印测试结果,从结果来看,测试用到的microSD卡为:4.xx版的SDHC大容量卡,16GB(15441920KB),支持块操作,支持加锁解锁操作。
数据读写测试了单个块写入读取与多个块写入读取正常,在加锁后则无法读取,解锁后可正常读取。
Card init success!
Card information:
## Card version 4.xx ##
## SDHC card ##
## Device size is 15441920KB ##
## Block size is 512B ##
## Block count is 30883840 ##
## CardCommandClasses is: db7 ##
## Block operation supported ##
## Erase supported ##
## Lock unlock supported ##
## Application specific supported ##
## Switch function supported ##
Card test:
Block write success!
Block read success!
0 0 0 0 1 0 0 0 2 0 0 0 3 0 0 0
4 0 0 0 5 0 0 0 6 0 0 0 7 0 0 0
...略去若干行
112 0 0 0 113 0 0 0 114 0 0 0 115 0 0 0
116 0 0 0 117 0 0 0 118 0 0 0 119 0 0 0
120 0 0 0 121 0 0 0 122 0 0 0 123 0 0 0
124 0 0 0 125 0 0 0 126 0 0 0 127 0 0 0
The card is locked!
Erase failed!
The card is unlocked!
Erase success!
Block read success!
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...略去若干行
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Multiple block write success!
Multiple block read success!
0 0 0 0 1 0 0 0 2 0 0 0 3 0 0 0
4 0 0 0 5 0 0 0 6 0 0 0 7 0 0 0
...略去若干行
112 0 0 0 113 0 0 0 114 0 0 0 115 0 0 0
116 0 0 0 117 0 0 0 118 0 0 0 119 0 0 0
120 0 0 0 121 0 0 0 122 0 0 0 123 0 0 0
124 0 0 0 125 0 0 0 126 0 0 0 127 0 0 0
128 0 0 0 129 0 0 0 130 0 0 0 131 0 0 0
132 0 0 0 133 0 0 0 134 0 0 0 135 0 0 0
...略去若干行
236 0 0 0 237 0 0 0 238 0 0 0 239 0 0 0
240 0 0 0 241 0 0 0 242 0 0 0 243 0 0 0
244 0 0 0 245 0 0 0 246 0 0 0 247 0 0 0
248 0 0 0 249 0 0 0 250 0 0 0 251 0 0 0
252 0 0 0 253 0 0 0 254 0 0 0 255 0 0 0
0 1 0 0 1 1 0 0 2 1 0 0 3 1 0 0
4 1 0 0 5 1 0 0 6 1 0 0 7 1 0 0
...略去若干行
112 1 0 0 113 1 0 0 114 1 0 0 115 1 0 0
116 1 0 0 117 1 0 0 118 1 0 0 119 1 0 0
120 1 0 0 121 1 0 0 122 1 0 0 123 1 0 0
124 1 0 0 125 1 0 0 126 1 0 0 127 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...略去若干行
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
本帖最后由 DDZZ669 于 2020-10-17 21:37 编辑
感谢分享,每一个测评都做得这么认真!