使用STM32的SDIO接口实现大容量存储器访问

在使用 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视而不见

代码获取、问题探讨及文章转载可私信。

 ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

获取更多嵌入式资料可点击链接进群领取,谢谢支持!

点击领取更多详细资料

你可能感兴趣的:(stm32,单片机,嵌入式硬件)