在使用 STM32 的 SDIO 接口实现大容量存储器访问时(如SD卡、SDHC卡或SDXC卡),主要需要处理以下几个方面的问题:初始化、读取数据和写入数据。下面将详细介绍这些方面,并提供相应的代码示例。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
获取更多嵌入式资料可点击链接进群领取,谢谢支持!
点击领取更多详细资料
1. 初始化:
首先,需要进行 SDIO 初始化,包括时钟设置、GPIO 配置、DMA 配置、中断设置等。
```c
void SDIO_Initialize() {
// 1. 配置 SDIO 时钟源和分频因子
RCC->CFGR &= ~RCC_CFGR_PPRE2;
RCC->CFGR |= RCC_CFGR_PPRE2_DIV4;
SDIO->CLKCR |= CLKDIV;
// 2. 配置 SDIO 相关 GPIO 引脚
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;
// 配置引脚为复用模式
GPIOC->MODER &= ~(GPIO_MODER_MODE8 | GPIO_MODER_MODE9);
GPIOC->MODER |= (GPIO_MODER_MODE8_1 | GPIO_MODER_MODE9_1);
GPIOC->OSPEEDR |= (GPIO_OSPEEDR_OSPEED8 | GPIO_OSPEEDR_OSPEED9);
GPIOC->OTYPER |= (GPIO_OTYPER_OT8 | GPIO_OTYPER_OT9);
GPIOC->PUPDR |= (GPIO_PUPDR_PUPD8_0 | GPIO_PUPDR_PUPD9_0);
// 配置引脚为复用功能为 SDIO
GPIOC->AFR[1] = (0x22 << GPIO_AFRH_AFSEL8_Pos) | (0x22 << GPIO_AFRH_AFSEL9_Pos);
// 3. 配置 SDIO 控制器及 DMA
RCC->AHB1ENR |= RCC_AHB1ENR_SDIOEN;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
// 使能 SDIO 控制器时钟、DMA 传输、中断
SDIO->POWER |= SDMMC_POWER_PWRCTRL;
SDIO->DCTRL |= SDMMC_DCTRL_DMAEN;
SDIO->MASK |= SDMMC_MASK_RXDR | SDMMC_MASK_TXDR | SDMMC_MASK_DATAEND | SDMMC_MASK_DCRCFAIL | SDMMC_MASK_DTIMEOUT;
SDIO->ICR |= SDMMC_ICR_RXDRC | SDMMC_ICR_TXDRC | SDMMC_ICR_DATAENDC | SDMMC_ICR_DCRCFAILC | SDMMC_ICR_DTIMEOUTC;
// 4. 配置 DMA 流
DMA_Stream_TypeDef* dmaStream = DMA2_Stream3;
dmaStream->CR &= ~DMA_SxCR_EN;
dmaStream->CR = 0;
dmaStream->PAR = (uint32_t)&(SDIO->FIFO);
dmaStream->M0AR = (uint32_t)dataBuffer;
dmaStream->NDTR = bufferSize / 4;
dmaStream->CR = DMA_SxCR_CHSEL_2 | DMA_SxCR_PL_0 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 |
DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE | DMA_SxCR_TEIE;
dmaStream->FCR = DMA_SxFCR_DMDIS;
dmaStream->CR |= DMA_SxCR_EN;
NVIC_EnableIRQ(SDIO_IRQn);
}
```
2. 读取数据:
在读取数据时,首先发送读取命令,然后通过 DMA 传输数据到缓冲区。在 DMA 传输完成后进行相应的处理。
```c
void SDIO_ReadData(uint32_t blockAddr, uint8_t* buffer) {
uint32_t addr = blockAddr * blockSize;
// 1. 设置 DMA 相关参数
DMA_Stream_TypeDef* dmaStream = DMA2_Stream3;
dmaStream->CR &= ~DMA_SxCR_EN;
dmaStream->M0AR = (uint32_t)buffer;
dmaStream->NDTR = bufferSize / 4;
dmaStream->CR |= DMA_SxCR_EN;
// 2. 发送读取命令
SDIO->ARG = addr;
SDIO->CMD = CMD17 | SDMMC_CMD_CMDEN;
}
```
3. 写入数据:
在写入数据时,首先发送写入命令,然后通过 DMA 将数据从缓冲区传输到 SDIO 接口。在 DMA 传输完成后进行相应的处理。
```c
void SDIO_WriteData(uint32_t blockAddr, const uint8_t* buffer) {
uint32_t addr = blockAddr * blockSize;
// 1. 设置 DMA 相关参数
DMA_Stream_TypeDef* dmaStream = DMA2_Stream3;
dmaStream->CR &= ~DMA_SxCR_EN;
dmaStream->M0AR = (uint32_t)buffer;
dmaStream->NDTR = bufferSize / 4;
dmaStream->CR |= DMA_SxCR_EN;
// 2. 发送写入命令
SDIO->ARG = addr;
SDIO->CMD = CMD24 | SDMMC_CMD_CMDEN;
}
```
4. SDIO 中断处理函数:
在 SDIO 中断处理函数中,处理 DMA 传输完成和其他相关中断事件。
```c
void SDIO_IRQHandler() {
if (SDIO->STA & (SDMMC_STA_RXOVERR | SDMMC_STA_DCRCFAIL | SDMMC_STA_DTIMEOUT | SDMMC_STA_STBITERR)) {
// 处理错误情况...
SDIO->ICR |= SDMMC_ICR_RXOVERRC | SDMMC_ICR_DCRCFAILC | SDMMC_ICR_DTIMEOUTC | SDMMC_ICR_STBITERRC;
}
if (SDIO->STA & SDMMC_STA_DATAEND) {
// 数据传输完成...
SDIO->ICR |= SDMMC_ICR_DATAENDC;
}
}
```
以上是使用 STM32 的 SDIO 接口实现大容量存储器访问的基本框架。根据具体的应用需求和硬件环境,你可以进一步优化代码和添加适当的错误处理策略。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
获取更多嵌入式资料可点击链接进群领取,谢谢支持!
点击领取更多详细资料