简介
最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。
STM32Cube配置
Pinout
只需要注意绿色部分的设定Clock配置
这里使用了最大的Clock,SDMMC1的时钟是48MHzFATFS配置
Freertos配置
这里增大了Heap size,使用了heap_4的内存管理方式。SD卡配置
在这里打开SD的全局中断,并使用DMA2的方式传输数据NVIC配置
SD的全局中断配置为5,DMA中断配置为6,5的优先级更高。工程配置
以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。
代码修改
- 初始化SD卡
我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。
/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{
BSP_SD_Init();
/* init code for FATFS */
MX_FATFS_Init();
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
MX_FATFS_Run();
vTaskDelay( 5000 );
}
/* USER CODE END StartDefaultTask */
}
- 添加DMA中断处理函数
stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
BSP_SD_WriteCpltCallback();
}
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
BSP_SD_ReadCpltCallback();
}
- 创建Queue
在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。
DSTATUS SD_initialize(BYTE lun)
{
osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);
return SD_CheckStatus(lun);
}
- 将Pin的配置改为上拉
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:
/*卡在这个循环中出不去*/
while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
{
if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
{
*(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
index++;
}
if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT)
{
return HAL_SD_ERROR_TIMEOUT;
}
}
后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
简单Fatfs应用
void StartDefaultTask(void const * argument)
{
BSP_SD_Init();
/* init code for FATFS */
MX_FATFS_Init();
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
/*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/
MX_FATFS_Run();
vTaskDelay( 5000 );
}
/* USER CODE END StartDefaultTask */
}
void MX_FATFS_Init(void)
{
/*## FatFS: Link the SD driver ###########################*/
retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
/* USER CODE BEGIN Init */
/* 在Init的时候挂载文件系统 */
if(f_mount(&SDFatFS, SDPath,0) != FR_OK)
{
while(1);
}
/* USER CODE END Init */
}
void MX_FATFS_Run(void)
{
UINT writeBytes;
/*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/
if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)
{
while(1);
}
if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
{
while(1);
}
if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)
{
while(1);
}
if(f_close(&SDFile) != FR_OK)
{
while(1);
}
}
- SD写入结果: