/**
* GD32F303RC SD卡驱动测试程序
*/
#include "gd32f30x.h"
#include "sd_card_driver.h"
#include <stdio.h>
/* 测试数据缓冲区 */
#define TEST_BLOCK_SIZE 512
uint8_t writeBuffer[TEST_BLOCK_SIZE];
uint8_t readBuffer[TEST_BLOCK_SIZE];
/* 串口初始化 */
void UART_Init(void)
{
/* 使能GPIO和USART时钟 */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
/* 配置USART0 Tx (PA9)为复用推挽输出 */
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
/* 配置USART0 Rx (PA10)为浮空输入 */
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
/* USART配置 */
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200);
usart_word_length_set(USART0, USART_WL_8BIT);
usart_stop_bit_set(USART0, USART_STB_1BIT);
usart_parity_config(USART0, USART_PM_NONE);
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
}
/* 重定向printf函数到USART0 */
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
int main(void)
{
SD_Status status;
SD_CardInfo cardInfo;
/* 系统时钟配置 */
SystemInit();
/* 初始化串口 */
UART_Init();
printf("GD32F303RC SD卡测试程序
");
/* 初始化SDIO接口 */
SDIO_Init();
/* 初始化SD卡 */
printf("正在初始化SD卡...
");
status = SD_CardInit();
if(status == SD_OK) {
printf("SD卡初始化成功!
");
/* 获取卡信息 */
status = SD_GetCardInfo();
if(status == SD_OK) {
SD_GetInfo(&cardInfo);
printf("卡类型: %s
", cardInfo.type == 1 ? "SDSC" : "SDHC/SDXC");
printf("卡容量: %lu MB
", cardInfo.capacity);
printf("块大小: %lu 字节
", cardInfo.block_size);
/* 测试读写操作 */
printf("准备测试读写操作...
");
/* 填充测试数据 */
for(int i = 0; i < TEST_BLOCK_SIZE; i++) {
writeBuffer[i] = (uint8_t)i;
}
/* 写入测试块 */
printf("写入测试块...
");
status = SD_WriteBlock(0, writeBuffer);
if(status == SD_OK) {
printf("写入成功!
");
/* 读取测试块 */
printf("读取测试块...
");
status = SD_ReadBlock(0, readBuffer);
if(status == SD_OK) {
printf("读取成功!
");
/* 验证数据 */
for(int i = 0; i < TEST_BLOCK_SIZE; i++) {
if(readBuffer[i] != writeBuffer[i]) {
printf("数据验证失败! 位置: %d, 预期: 0x%02X, 实际: 0x%02X
",
i, writeBuffer[i], readBuffer[i]);
break;
}
}
printf("数据验证成功!
");
} else {
printf("读取失败! 状态: %d
", status);
}
} else {
printf("写入失败! 状态: %d
", status);
}
} else {
printf("获取卡信息失败! 状态: %d
", status);
}
} else {
printf("SD卡初始化失败! 状态: %d
", status);
}
while(1) {
/* 主循环 */
}
}
/**
* GD32F303RC SD卡驱动程序 - 基于SDIO接口
* 支持SD卡初始化、数据读写等功能
*/
#include "gd32f30x.h"
#include "sd_card_driver.h"
#include <string.h>
/* SDIO时钟频率设置 */
#define SDIO_CK_DIV_INIT 0x7F /* 初始化时频率约400kHz */
#define SDIO_CK_DIV_NORMAL 0x03 /* 正常通信时频率约24MHz */
/* SD卡命令定义 */
#define CMD0 0 /* 复位SD卡 */
#define CMD1 1 /* 初始化SD卡 */
#define ACMD41 41 /* 初始化SDHC卡 */
#define CMD8 8 /* 检查SD卡支持的电压 */
#define CMD16 16 /* 设置块大小 */
#define CMD17 17 /* 读单块 */
#define CMD24 24 /* 写单块 */
#define CMD55 55 /* 发送应用命令前缀 */
#define CMD58 58 /* 读取OCR寄存器 */
/* SD卡响应类型 */
typedef enum {
RESPONSE_NONE = 0, /* 无响应 */
RESPONSE_SHORT = 1, /* 短响应(48位) */
RESPONSE_LONG = 2, /* 长响应(136位) */
} SD_ResponseType;
/* SD卡状态 */
typedef enum {
SD_OK = 0, /* 成功 */
SD_ERROR = 1, /* 错误 */
SD_TIMEOUT = 2, /* 超时 */
SD_NOT_SUPPORTED = 3, /* 不支持 */
} SD_Status;
/* SD卡信息结构体 */
typedef struct {
uint32_t type; /* 卡类型 */
uint32_t capacity; /* 卡容量(MB) */
uint32_t block_size; /* 块大小(字节) */
} SD_CardInfo;
/* 全局变量 */
static SD_CardInfo g_sdCardInfo;
/**
* 初始化SDIO接口
*/
void SDIO_Init(void)
{
/* 使能SDIO和GPIO时钟 */
rcu_periph_clock_enable(RCU_SDIO);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
/* 配置SDIO引脚 */
/* PC8: SDIO_D0, PC9: SDIO_D1, PC10: SDIO_D2, PC11: SDIO_D3 */
/* PC12: SDIO_CK, PD2: SDIO_CMD */
gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
/* 配置SDIO参数 */
/* 关闭SDIO */
SDIO_CTL(SDIO) &= ~SDIO_CTL_SDIOEN;
/* 设置时钟分频 - 初始化时使用低频率(约400kHz) */
SDIO_CLKCR(SDIO) = (SDIO_CK_DIV_INIT << 8) |
SDIO_CLKCR_WIDBUS_1B |
SDIO_CLKCR_PWRSAV |
SDIO_CLKCR_BYPASS |
SDIO_CLKCR_CLKEN;
/* 使能SDIO */
SDIO_CTL(SDIO) |= SDIO_CTL_SDIOEN;
}
/**
* 发送SD卡命令
* @param cmd 命令号
* @param arg 命令参数
* @param response_type 响应类型
* @return 命令响应
*/
uint32_t SDIO_SendCommand(uint8_t cmd, uint32_t arg, SD_ResponseType response_type)
{
uint32_t timeout = 0xFFFF;
/* 等待命令线空闲 */
while((SDIO_STAT(SDIO) & SDIO_STAT_CMDACT) && (timeout-- > 0));
if(timeout == 0) return SD_TIMEOUT;
/* 清除中断标志 */
SDIO_ICR(SDIO) = 0x0007FFDF;
/* 设置命令参数 */
SDIO_ARG(SDIO) = arg;
/* 设置命令寄存器 */
SDIO_CMD(SDIO) = (cmd & 0x3F) |
((response_type == RESPONSE_LONG) ? SDIO_CMD_RESPTYP_136BIT :
(response_type == RESPONSE_SHORT) ? SDIO_CMD_RESPTYP_48BIT : 0) |
((response_type != RESPONSE_NONE) ? SDIO_CMD_WAITRESP : 0) |
SDIO_CMD_CMDSEND;
/* 等待命令发送完成 */
timeout = 0xFFFF;
if(response_type != RESPONSE_NONE) {
while(!(SDIO_STAT(SDIO) & SDIO_STAT_CMDRDY) && (timeout-- > 0));
if(timeout == 0) return SD_TIMEOUT;
}
/* 返回响应 */
if(response_type == RESPONSE_SHORT) {
return SDIO_RESP0(SDIO);
} else if(response_type == RESPONSE_LONG) {
return SDIO_RESP1(SDIO);
}
return SD_OK;
}
/**
* 初始化SD卡
* @return 操作状态
*/
SD_Status SD_CardInit(void)
{
uint32_t response;
uint32_t timeout;
uint8_t ocr[4];
/* 发送74个时钟周期 */
for(int i = 0; i < 10; i++) {
SDIO_SendCommand(0, 0, RESPONSE_NONE);
}
/* 发送CMD0 - 复位SD卡 */
response = SDIO_SendCommand(CMD0, 0, RESPONSE_SHORT);
if(response != 0x01) return SD_ERROR;
/* 发送CMD8 - 检查SD卡支持的电压 */
response = SDIO_SendCommand(CMD8, 0x1AA, RESPONSE_SHORT);
if(response == 0x01) {
/* SDHC卡 */
g_sdCardInfo.type = 2; /* SDHC/SDXC */
/* 发送ACMD41 - 初始化SDHC卡 */
timeout = 0xFFFF;
do {
SDIO_SendCommand(CMD55, 0, RESPONSE_SHORT);
response = SDIO_SendCommand(ACMD41, 0x40000000, RESPONSE_SHORT);
} while((response & 0x01) && (timeout-- > 0));
if(timeout == 0) return SD_TIMEOUT;
/* 发送CMD58 - 读取OCR寄存器 */
response = SDIO_SendCommand(CMD58, 0, RESPONSE_SHORT);
ocr[0] = (response >> 24) & 0xFF;
ocr[1] = (response >> 16) & 0xFF;
ocr[2] = (response >> 8) & 0xFF;
ocr[3] = response & 0xFF;
/* 设置块大小为512字节 */
response = SDIO_SendCommand(CMD16, 512, RESPONSE_SHORT);
if(response != 0x00) return SD_ERROR;
g_sdCardInfo.block_size = 512;
} else {
/* SDSC卡或MMC卡 */
g_sdCardInfo.type = 1; /* SDSC */
/* 发送CMD1 - 初始化SDSC卡 */
timeout = 0xFFFF;
do {
response = SDIO_SendCommand(CMD1, 0, RESPONSE_SHORT);
} while((response & 0x01) && (timeout-- > 0));
if(timeout == 0) return SD_TIMEOUT;
/* 设置块大小为512字节 */
response = SDIO_SendCommand(CMD16, 512, RESPONSE_SHORT);
if(response != 0x00) return SD_ERROR;
g_sdCardInfo.block_size = 512;
}
/* 提高通信频率 */
SDIO_CLKCR(SDIO) = (SDIO_CK_DIV_NORMAL << 8) |
SDIO_CLKCR_WIDBUS_1B |
SDIO_CLKCR_PWRSAV |
SDIO_CLKCR_BYPASS |
SDIO_CLKCR_CLKEN;
return SD_OK;
}
/**
* 读取SD卡容量信息
* @return 操作状态
*/
SD_Status SD_GetCardInfo(void)
{
uint32_t response;
uint8_t cid[16];
uint8_t csd[16];
uint32_t capacity;
/* 发送CMD2 - 获取CID */
response = SDIO_SendCommand(CMD2, 0, RESPONSE_LONG);
if(response != 0x00) return SD_ERROR;
/* 读取CID */
for(int i = 0; i < 4; i++) {
cid[i*4] = (SDIO_RESP1(SDIO) >> 24) & 0xFF;
cid[i*4+1] = (SDIO_RESP1(SDIO) >> 16) & 0xFF;
cid[i*4+2] = (SDIO_RESP1(SDIO) >> 8) & 0xFF;
cid[i*4+3] = SDIO_RESP1(SDIO) & 0xFF;
}
/* 发送CMD3 - 获取RCA */
response = SDIO_SendCommand(CMD3, 0, RESPONSE_SHORT);
if(response == 0x00) return SD_ERROR;
/* 发送CMD9 - 获取CSD */
response = SDIO_SendCommand(CMD9, (response & 0xFFFF0000), RESPONSE_LONG);
if(response != 0x00) return SD_ERROR;
/* 读取CSD */
for(int i = 0; i < 4; i++) {
csd[i*4] = (SDIO_RESP1(SDIO) >> 24) & 0xFF;
csd[i*4+1] = (SDIO_RESP1(SDIO) >> 16) & 0xFF;
csd[i*4+2] = (SDIO_RESP1(SDIO) >> 8) & 0xFF;
csd[i*4+3] = SDIO_RESP1(SDIO) & 0xFF;
}
/* 计算容量 */
if(g_sdCardInfo.type == 2) { /* SDHC/SDXC */
uint32_t c_size = ((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9];
capacity = (c_size + 1) * 512 / 1024 / 1024; /* MB */
} else { /* SDSC */
uint8_t csd_ver = (csd[0] >> 6) & 0x03;
uint32_t c_size;
if(csd_ver == 0) { /* CSD version 1.0 */
uint32_t c_size_mult = ((csd[10] & 0x03) << 1) | ((csd[11] >> 7) & 0x01);
uint32_t read_bl_len = csd[5] & 0x0F;
c_size = ((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] >> 6) & 0x03);
capacity = (c_size + 1) * (1 << (c_size_mult + 2)) * (1 << read_bl_len) / 1024 / 1024; /* MB */
} else { /* CSD version 2.0 */
c_size = ((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9];
capacity = (c_size + 1) * 512 / 1024 / 1024; /* MB */
}
}
g_sdCardInfo.capacity = capacity;
return SD_OK;
}
/**
* 读取单个数据块
* @param block_addr 块地址
* @param buffer 数据缓冲区
* @return 操作状态
*/
SD_Status SD_ReadBlock(uint32_t block_addr, uint8_t *buffer)
{
uint32_t timeout;
/* 如果是SDSC卡,需要转换为字节地址 */
if(g_sdCardInfo.type == 1) {
block_addr *= g_sdCardInfo.block_size;
}
/* 发送CMD17 - 读取单块 */
if(SDIO_SendCommand(CMD17, block_addr, RESPONSE_SHORT) != 0x00) {
return SD_ERROR;
}
/* 等待数据准备好 */
timeout = 0xFFFF;
while(!(SDIO_STAT(SDIO) & SDIO_STAT_DBCKEND) && (timeout-- > 0));
if(timeout == 0) return SD_TIMEOUT;
/* 读取数据 */
for(int i = 0; i < g_sdCardInfo.block_size; i += 4) {
uint32_t data = SDIO_FIFO(SDIO);
buffer[i] = (data >> 24) & 0xFF;
buffer[i+1] = (data >> 16) & 0xFF;
buffer[i+2] = (data >> 8) & 0xFF;
buffer[i+3] = data & 0xFF;
}
return SD_OK;
}
/**
* 写入单个数据块
* @param block_addr 块地址
* @param buffer 数据缓冲区
* @return 操作状态
*/
SD_Status SD_WriteBlock(uint32_t block_addr, uint8_t *buffer)
{
uint32_t timeout;
/* 如果是SDSC卡,需要转换为字节地址 */
if(g_sdCardInfo.type == 1) {
block_addr *= g_sdCardInfo.block_size;
}
/* 配置数据传输 */
SDIO_DCTRL(SDIO) = 0;
SDIO_DLEN(SDIO) = g_sdCardInfo.block_size;
SDIO_DCTRL(SDIO) = SDIO_DCTRL_DBLOCKSIZE_512B |
SDIO_DCTRL_DTEN |
SDIO_DCTRL_DTDIR_TX;
/* 发送CMD24 - 写入单块 */
if(SDIO_SendCommand(CMD24, block_addr, RESPONSE_SHORT) != 0x00) {
return SD_ERROR;
}
/* 写入数据 */
for(int i = 0; i < g_sdCardInfo.block_size; i += 4) {
uint32_t data = (buffer[i] << 24) | (buffer[i+1] << 16) | (buffer[i+2] << 8) | buffer[i+3];
SDIO_FIFO(SDIO) = data;
}
/* 等待数据传输完成 */
timeout = 0xFFFF;
while(!(SDIO_STAT(SDIO) & SDIO_STAT_DBCKEND) && (timeout-- > 0));
if(timeout == 0) return SD_TIMEOUT;
/* 等待卡就绪 */
timeout = 0xFFFFFF;
while(!(SDIO_STAT(SDIO) & SDIO_STAT_RTO) && (timeout-- > 0));
return SD_OK;
}
/**
* 获取SD卡信息
* @param card_info 卡信息结构体指针
*/
void SD_GetInfo(SD_CardInfo *card_info)
{
memcpy(card_info, &g_sdCardInfo, sizeof(SD_CardInfo));
}
/**
* GD32F303RC SD卡驱动头文件
*/
#ifndef __SD_CARD_DRIVER_H__
#define __SD_CARD_DRIVER_H__
#include "gd32f30x.h"
/* SD卡状态 */
typedef enum {
SD_OK = 0, /* 成功 */
SD_ERROR = 1, /* 错误 */
SD_TIMEOUT = 2, /* 超时 */
SD_NOT_SUPPORTED = 3, /* 不支持 */
} SD_Status;
/* SD卡信息结构体 */
typedef struct {
uint32_t type; /* 卡类型 */
uint32_t capacity; /* 卡容量(MB) */
uint32_t block_size; /* 块大小(字节) */
} SD_CardInfo;
/* 函数声明 */
void SDIO_Init(void);
SD_Status SD_CardInit(void);
SD_Status SD_GetCardInfo(void);
SD_Status SD_ReadBlock(uint32_t block_addr, uint8_t *buffer);
SD_Status SD_WriteBlock(uint32_t block_addr, uint8_t *buffer);
void SD_GetInfo(SD_CardInfo *card_info);
#endif /* __SD_CARD_DRIVER_H__ */
下一篇:spi nand引脚定义