//----------------------------------------------------------------- // 程序描述: // SD卡驱动程序 // 作 者: 凌智电子 // 开始日期: 2018-08-04 // 完成日期: 2018-08-04 // 修改日期: // 当前版本: V1.0 // 历史版本: // - V1.0: (2018-08-04) SD卡初始化和读写 // 调试工具: 凌智STM32F429+CycloneIV电子系统设计开发板、LZE_ST_LINK2 // 说 明: // //----------------------------------------------------------------- //----------------------------------------------------------------- // 头文件包含 //----------------------------------------------------------------- #include "sdio.h" #include "string.h" //----------------------------------------------------------------- SD_HandleTypeDef SDCARD_Handler; // SD卡句柄 HAL_SD_CardInfoTypedef SDCardInfo; // SD卡信息结构体 DMA_HandleTypeDef SDTxDMAHandler,SDRxDMAHandler; // SD卡DMA发送和接收句柄 // SD_ReadDisk/SD_WriteDisk函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候, // 需要用到该数组,确保数据缓存区地址是4字节对齐的. __align(4) u8 SDIO_DATA_BUFFER[512]; //----------------------------------------------------------------- // u8 SD_Init(void) //----------------------------------------------------------------- // // 函数功能: SD卡初始化 // 入口参数: 无 // 返 回 值: 0 初始化正确;其他值,初始化错误 // 注意事项: 无 // //----------------------------------------------------------------- u8 SD_Init(void) { u8 SD_Error; // 初始化时的时钟不能大于400KHZ SDCARD_Handler.Instance=SDIO; SDCARD_Handler.Init.ClockEdge=SDIO_CLOCK_EDGE_RISING; // 上升沿 SDCARD_Handler.Init.ClockBypass=SDIO_CLOCK_BYPASS_DISABLE; // 不使用bypass模式,直接用HCLK进行分频得到SDIO_CK SDCARD_Handler.Init.ClockPowerSave=SDIO_CLOCK_POWER_SAVE_DISABLE; // 空闲时不关闭时钟电源 SDCARD_Handler.Init.BusWide=SDIO_BUS_WIDE_1B; // 1位数据线 SDCARD_Handler.Init.HardwareFlowControl=SDIO_HARDWARE_FLOW_CONTROL_DISABLE; // 关闭硬件流控 SDCARD_Handler.Init.ClockDiv=SDIO_TRANSFER_CLK_DIV; // SD传输时钟频率最大25MHZ SD_Error=HAL_SD_Init(&SDCARD_Handler,&SDCardInfo); if(SD_Error!=SD_OK) return 1; SD_Error=HAL_SD_WideBusOperation_Config(&SDCARD_Handler,SDIO_BUS_WIDE_4B); // 使能宽总线模式 if(SD_Error!=SD_OK) return 2; return 0; } //----------------------------------------------------------------- // void HAL_SD_MspInit(SD_HandleTypeDef *hsd) //----------------------------------------------------------------- // // 函数功能: SDMMC底层驱动,时钟使能,引脚配置,DMA配置 // 入口参数: SD_HandleTypeDef *hsd:SD卡句柄 // 返 回 值: 无 // 注意事项: 此函数会被HAL_SD_Init()调用 // //----------------------------------------------------------------- void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { DMA_HandleTypeDef TxDMAHandler,RxDMAHandler; GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_SDIO_CLK_ENABLE(); // 使能SDIO时钟 __HAL_RCC_DMA2_CLK_ENABLE(); // 使能DMA2时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); // 使能GPIOC时钟 __HAL_RCC_GPIOD_CLK_ENABLE(); // 使能GPIOD时钟 // PC8->SDIO_D0, PC9->SDIO_D1, PC10->SDIO_D2, PC11->SDIO_D3, PC12->SDIO_CK GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12; GPIO_Initure.Mode=GPIO_MODE_AF_PP; // 推挽复用 GPIO_Initure.Pull=GPIO_PULLUP; // 上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; // 高速 GPIO_Initure.Alternate=GPIO_AF12_SDIO; // 复用为SDIO HAL_GPIO_Init(GPIOC,&GPIO_Initure); // 初始化 GPIO_Initure.Pin=GPIO_PIN_2; // PD2->SDIO_CMD HAL_GPIO_Init(GPIOD,&GPIO_Initure); // 初始化 #if (SD_DMA_MODE==1) // 使用DMA模式 HAL_NVIC_SetPriority(SDMMC1_IRQn,2,0); // 配置SDMMC1中断,抢占优先级2,子优先级0 HAL_NVIC_EnableIRQ(SDMMC1_IRQn); // 使能SDMMC1中断 // 配置发送DMA SDRxDMAHandler.Instance=DMA2_Stream3; SDRxDMAHandler.Init.Channel=DMA_CHANNEL_4; SDRxDMAHandler.Init.Direction=DMA_PERIPH_TO_MEMORY; SDRxDMAHandler.Init.PeriphInc=DMA_PINC_DISABLE; SDRxDMAHandler.Init.MemInc=DMA_MINC_ENABLE; SDRxDMAHandler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD; SDRxDMAHandler.Init.MemDataAlignment=DMA_MDATAALIGN_WORD; SDRxDMAHandler.Init.Mode=DMA_PFCTRL; SDRxDMAHandler.Init.Priority=DMA_PRIORITY_VERY_HIGH; SDRxDMAHandler.Init.FIFOMode=DMA_FIFOMODE_ENABLE; SDRxDMAHandler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL; SDRxDMAHandler.Init.MemBurst=DMA_MBURST_INC4; SDRxDMAHandler.Init.PeriphBurst=DMA_PBURST_INC4; __HAL_LINKDMA(hsd, hdmarx, SDRxDMAHandler); // 将接收DMA和SD卡的发送DMA连接起来 HAL_DMA_DeInit(&SDRxDMAHandler); HAL_DMA_Init(&SDRxDMAHandler); // 初始化接收DMA // 配置接收DMA SDTxDMAHandler.Instance=DMA2_Stream6; SDTxDMAHandler.Init.Channel=DMA_CHANNEL_4; SDTxDMAHandler.Init.Direction=DMA_MEMORY_TO_PERIPH; SDTxDMAHandler.Init.PeriphInc=DMA_PINC_DISABLE; SDTxDMAHandler.Init.MemInc=DMA_MINC_ENABLE; SDTxDMAHandler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD; SDTxDMAHandler.Init.MemDataAlignment=DMA_MDATAALIGN_WORD; SDTxDMAHandler.Init.Mode=DMA_PFCTRL; SDTxDMAHandler.Init.Priority=DMA_PRIORITY_VERY_HIGH; SDTxDMAHandler.Init.FIFOMode=DMA_FIFOMODE_ENABLE; SDTxDMAHandler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL; SDTxDMAHandler.Init.MemBurst=DMA_MBURST_INC4; SDTxDMAHandler.Init.PeriphBurst=DMA_PBURST_INC4; __HAL_LINKDMA(hsd, hdmatx, SDTxDMAHandler);// 将发送DMA和SD卡的发送DMA连接起来 HAL_DMA_DeInit(&SDTxDMAHandler); HAL_DMA_Init(&SDTxDMAHandler); // 初始化发送DMA HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 3, 0); // 接收DMA中断优先级 HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 3, 0); // 发送DMA中断优先级 HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); #endif } //----------------------------------------------------------------- // u8 SD_GetCardInfo(HAL_SD_CardInfoTypedef *cardinfo) //----------------------------------------------------------------- // // 函数功能: 得到卡信息 // 入口参数: HAL_SD_CardInfoTypedef *cardinfo:卡信息存储区 // 返 回 值: 错误状态 // 注意事项: 无 // //----------------------------------------------------------------- u8 SD_GetCardInfo(HAL_SD_CardInfoTypedef *cardinfo) { u8 sta; sta=HAL_SD_Get_CardInfo(&SDCARD_Handler,cardinfo); return sta; } #if (SD_DMA_MODE==1) // DMA模式 //----------------------------------------------------------------- // u8 SD_ReadBlocks_DMA(uint32_t *buf,uint64_t sector,uint32_t blocksize,uint32_t cnt) //----------------------------------------------------------------- // // 函数功能: 通过DMA读取SD卡一个扇区 // 入口参数: uint32_t *buf:读数据缓存区 // uint64_t sector:扇区地址 // uint32_t blocksize:扇区大小(一般都是512字节) // uint32_t cnt:扇区个数 // 返 回 值: 错误状态;0,正常;其他,错误代码; // 注意事项: 无 // //----------------------------------------------------------------- u8 SD_ReadBlocks_DMA(uint32_t *buf,uint64_t sector,uint32_t blocksize,uint32_t cnt) { u8 err=0; err=HAL_SD_ReadBlocks_DMA(&SDCARD_Handler,buf,sector,blocksize,cnt); // 通过DMA读取SD卡一个扇区 if(err==0)// 读取成功 err=HAL_SD_CheckReadOperation(&SDCARD_Handler,(uint32_t)SD_TIMEOUT);// 等待读取完成 return err; } //----------------------------------------------------------------- // u8 SD_ReadBlocks_DMA(uint32_t *buf,uint64_t sector,uint32_t blocksize,uint32_t cnt) //----------------------------------------------------------------- // // 函数功能: 写SD卡 // 入口参数: uint32_t *buf:写数据缓存区 // uint64_t sector:扇区地址 // uint32_t blocksize:扇区大小(一般都是512字节) // uint32_t cnt:扇区个数 // 返 回 值: 错误状态;0,正常;其他,错误代码; // 注意事项: 无 // //----------------------------------------------------------------- u8 SD_WriteBlocks_DMA(uint32_t *buf,uint64_t sector,uint32_t blocksize,uint32_t cnt) { u8 err=0; err=HAL_SD_WriteBlocks_DMA(&SDCARD_Handler,buf,sector,blocksize,cnt); // 通过DMA写SD卡一个扇区 if(err==0)// 写成功 err=HAL_SD_CheckWriteOperation(&SDCARD_Handler,(uint32_t)SD_TIMEOUT); // 等待读取完成/ return err; } //----------------------------------------------------------------- // u8 SD_ReadDisk(u8* buf,u32 sector,u32 cnt) //----------------------------------------------------------------- // // 函数功能: 读SD卡 // 入口参数: u8* buf:读数据缓存区 // u32 sector:扇区地址 // uu32 cnt:扇区个数 // 返 回 值: 错误状态;0,正常;其他,错误代码; // 注意事项: 无 // //----------------------------------------------------------------- u8 SD_ReadDisk(u8* buf,u32 sector,u32 cnt) { u8 sta=SD_OK; long long lsector=sector; u8 n; if(SDCardInfo.CardType!=STD_CAPACITY_SD_CARD_V1_1) lsector<<=9; if((u32)buf%4!=0) { for(n=0;n