221 lines
5.7 KiB
C
221 lines
5.7 KiB
C
#include "sdmmc_sdcard.h"
|
||
#include "string.h"
|
||
#include "delay.h"
|
||
//////////////////////////////////////////////////////////////////////////////////
|
||
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
|
||
//ALIENTEK STM32H7开发板
|
||
//SD卡驱动代码
|
||
//正点原子@ALIENTEK
|
||
//技术论坛:www.openedv.com
|
||
//创建日期:2017/8/15
|
||
//版本:V1.0
|
||
//版权所有,盗版必究。
|
||
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
|
||
//All rights reserved
|
||
//////////////////////////////////////////////////////////////////////////////////
|
||
|
||
SD_HandleTypeDef SDCARD_Handler; //SD卡句柄
|
||
HAL_SD_CardInfoTypeDef SDCardInfo; //SD卡信息结构体
|
||
DMA_HandleTypeDef SDTxDMAHandler,SDRxDMAHandler; //SD卡DMA发送和接收句柄
|
||
|
||
//如果使用DMA的话下面两个变量用来标记SD卡读写是否完成
|
||
static volatile u8 SDCardWriteStatus=0,SDCardReadStatus=0;
|
||
|
||
//SD_ReadDisk/SD_WriteDisk函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候,
|
||
//需要用到该数组,确保数据缓存区地址是4字节对齐的.
|
||
__align(4) u8 SDIO_DATA_BUFFER[512];
|
||
|
||
//SD卡初始化,SDMMC频率为200MHz,SD卡最大频率25MHz
|
||
//返回值:0 初始化正确;其他值,初始化错误
|
||
u8 SD_Init(void)
|
||
{
|
||
u8 SD_Error;
|
||
|
||
//初始化时的时钟不能大于400KHZ
|
||
SDCARD_Handler.Instance=SDMMC1;
|
||
SDCARD_Handler.Init.ClockEdge=SDMMC_CLOCK_EDGE_RISING; //上升沿
|
||
SDCARD_Handler.Init.ClockPowerSave=SDMMC_CLOCK_POWER_SAVE_DISABLE; //空闲时不关闭时钟电源
|
||
SDCARD_Handler.Init.BusWide=SDMMC_BUS_WIDE_4B; //4位数据线
|
||
SDCARD_Handler.Init.HardwareFlowControl=SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;//关闭硬件流控
|
||
SDCARD_Handler.Init.ClockDiv=SDMMC_NSpeed_CLK_DIV; //SD传输时钟频率最大25MHZ
|
||
|
||
SD_Error=HAL_SD_Init(&SDCARD_Handler);
|
||
if(SD_Error!=HAL_OK) return 1;
|
||
|
||
//获取SD卡信息
|
||
HAL_SD_GetCardInfo(&SDCARD_Handler,&SDCardInfo);
|
||
return 0;
|
||
}
|
||
|
||
//SDMMC底层驱动,时钟使能,引脚配置,DMA配置
|
||
//此函数会被HAL_SD_Init()调用
|
||
//hsd:SD卡句柄
|
||
void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
|
||
{
|
||
GPIO_InitTypeDef GPIO_Initure;
|
||
|
||
__HAL_RCC_SDMMC1_CLK_ENABLE(); //使能SDMMC1时钟
|
||
__HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟
|
||
__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
|
||
|
||
//PC8,9,10,11,12
|
||
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_FREQ_VERY_HIGH; //高速
|
||
GPIO_Initure.Alternate=GPIO_AF12_SDIO1; //复用为SDIO
|
||
HAL_GPIO_Init(GPIOC,&GPIO_Initure); //初始化
|
||
|
||
//PD2
|
||
GPIO_Initure.Pin=GPIO_PIN_2;
|
||
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中断
|
||
#endif
|
||
}
|
||
|
||
//得到卡信息
|
||
//cardinfo:卡信息存储区
|
||
//返回值:错误状态
|
||
u8 SD_GetCardInfo(HAL_SD_CardInfoTypeDef *cardinfo)
|
||
{
|
||
u8 sta;
|
||
sta=HAL_SD_GetCardInfo(&SDCARD_Handler,cardinfo);
|
||
return sta;
|
||
}
|
||
|
||
//判断SD卡是否可以传输(读写)数据
|
||
//返回值:SD_TRANSFER_OK 传输完成,可以继续下一次传输
|
||
// SD_TRANSFER_BUSY SD卡正忙,不可以进行下一次传输
|
||
u8 SD_GetCardState(void)
|
||
{
|
||
return((HAL_SD_GetCardState(&SDCARD_Handler)==HAL_SD_CARD_TRANSFER )?SD_TRANSFER_OK:SD_TRANSFER_BUSY);
|
||
}
|
||
|
||
#if (SD_DMA_MODE==1) //DMA模式
|
||
|
||
//读SD卡
|
||
//buf:读数据缓存区
|
||
//sector:扇区地址
|
||
//cnt:扇区个数
|
||
//返回值:错误状态;0,正常;其他,错误代码;
|
||
u8 SD_ReadDisk(u8* buf,u32 sector,u32 cnt)
|
||
{
|
||
u8 sta=HAL_ERROR;
|
||
SDCardReadStatus=0;
|
||
|
||
if(HAL_SD_ReadBlocks_DMA(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt)==HAL_OK)
|
||
{
|
||
while(SDCardReadStatus==0){}; //等待读完成
|
||
|
||
SDCardReadStatus=0;
|
||
while(SD_GetCardState()){}; //等待SD卡空闲
|
||
sta=HAL_OK;
|
||
}
|
||
|
||
return sta;
|
||
}
|
||
|
||
//写SD卡
|
||
//buf:写数据缓存区
|
||
//sector:扇区地址
|
||
//cnt:扇区个数
|
||
//返回值:错误状态;0,正常;其他,错误代码;
|
||
u8 SD_WriteDisk(u8 *buf,u32 sector,u32 cnt)
|
||
{
|
||
u8 sta=HAL_ERROR;
|
||
|
||
SDCardWriteStatus=0;
|
||
|
||
if(HAL_SD_WriteBlocks_DMA(&SDCARD_Handler,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt)==HAL_OK)
|
||
{
|
||
while(SDCardWriteStatus==0){}; //等待写完成
|
||
|
||
SDCardWriteStatus=0;
|
||
while(SD_GetCardState()){}; //等待SD卡空闲
|
||
sta=HAL_OK;
|
||
}
|
||
|
||
return sta;
|
||
}
|
||
|
||
//SDMMC1中断服务函数
|
||
void SDMMC1_IRQHandler(void)
|
||
{
|
||
HAL_SD_IRQHandler(&SDCARD_Handler);
|
||
}
|
||
|
||
//SDMMC1写完成回调函数
|
||
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
|
||
{
|
||
SDCardWriteStatus=1; //标记写完成
|
||
}
|
||
|
||
//SDMMC1读完成回调函数
|
||
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
|
||
{
|
||
SDCardReadStatus=1; //标记读完成
|
||
}
|
||
|
||
#else //轮训模式
|
||
|
||
//读SD卡
|
||
//buf:读数据缓存区
|
||
//sector:扇区地址
|
||
//cnt:扇区个数
|
||
//返回值:错误状态;0,正常;其他,错误代码;
|
||
u8 SD_ReadDisk(u8* buf,u32 sector,u32 cnt)
|
||
{
|
||
u8 sta=HAL_OK;
|
||
u32 timeout=SD_TIMEOUT;
|
||
long long lsector=sector;
|
||
INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
|
||
sta=HAL_SD_ReadBlocks(&SDCARD_Handler, (uint8_t*)buf,lsector,cnt,SD_TIMEOUT);//多个sector的读操作
|
||
|
||
//等待SD卡读完
|
||
while(SD_GetCardState()!=SD_TRANSFER_OK)
|
||
{
|
||
if(timeout-- == 0)
|
||
{
|
||
sta=SD_TRANSFER_BUSY;
|
||
break;
|
||
}
|
||
}
|
||
INTX_ENABLE();//开启总中断
|
||
return sta;
|
||
}
|
||
|
||
|
||
//写SD卡
|
||
//buf:写数据缓存区
|
||
//sector:扇区地址
|
||
//cnt:扇区个数
|
||
//返回值:错误状态;0,正常;其他,错误代码;
|
||
u8 SD_WriteDisk(u8 *buf,u32 sector,u32 cnt)
|
||
{
|
||
u8 sta=HAL_OK;
|
||
u32 timeout=SD_TIMEOUT;
|
||
long long lsector=sector;
|
||
INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
|
||
sta=HAL_SD_WriteBlocks(&SDCARD_Handler,(uint8_t*)buf,lsector,cnt,SD_TIMEOUT);//多个sector的写操作
|
||
|
||
//等待SD卡写完
|
||
while(SD_GetCardState()!=SD_TRANSFER_OK)
|
||
{
|
||
if(timeout-- == 0)
|
||
{
|
||
sta=SD_TRANSFER_BUSY;
|
||
break;
|
||
}
|
||
}
|
||
INTX_ENABLE();//开启总中断
|
||
return sta;
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
|