您的位置:首页 > 其它

如何使用CubeMx制作一个基于SD卡的文件系统工程(2)

2017-01-03 20:21 756 查看
本文是原文http://blog.csdn.net/flydream0/article/details/52777923的补充。

原文并没有考虑SD卡拔插问题,且SDIO没有使用DMA,本文作为补充,将示例如何改善这两方面的问题。

1 SD卡拔插检测

FATFS文件系统初始化得修改下:

void MX_FATFS_Init(void)
{
/*## FatFS: Link the SD driver ###########################*/
retSD = FATFS_LinkDriver(&SD_Driver, SD_Path);

/* USER CODE BEGIN Init */
/* additional user code for init */

/* USER CODE END Init */
}


即保持CubeMx自动生成的原样即可,并不需要增加任何其他内容。

关键实在main中的while循环中检测SD卡的拔插:

while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
curSdCardStatus =BSP_SD_IsDetected();
if(curSdCardStatus !=preSdCardStatus)
{
switch(curSdCardStatus)
{
case SD_PRESENT:
BSP_SD_Init();
MountFat32FileSystemImmeditely();
break;
case SD_NOT_PRESENT:
UnmountFilesystem();
//FATFS_UnLinkDriver("0:/");
break;
}
preSdCardStatus =curSdCardStatus;
}
//      HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
//      HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
//      HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin);
//      HAL_GPIO_TogglePin(LED4_GPIO_Port,LED4_Pin);
//      HAL_Delay(200);
}


如上代码,循环检测SD卡的插入状态,一旦发现状态有变化,则进行相应操作,比如挂载文件系统,或者卸载文件系统。

挂载文件系统

static int  MountFat32FileSystem(void)
{
FRESULT ret ;

ret =f_mount(&SDFatFs, "0:/", 0);
if(ret!= FR_OK)
{
if(ret ==FR_DISK_ERR)
{
//              if(f_mkfs((TCHAR const*)SD_Path, 0, 0) != FR_OK)        //format the SDCard with FAT32 filesystem
//              {
//                  /* FatFs Format Error */
//                  Error_Handler();
//              }
}
else
{
Error_Handler();
}
}

return 0;
}


函数f_mount为实际操作挂载文件系统的函数,有3个输入参数,最后那个参数为0,表示先不挂载,等到fopen时再挂载,为1时,则表示立即挂载,在这个函数内部会使用check_fs函数去检查是否为FAT32文件系统,如果是,在挂载成功,否则失败。

当然这里可以立即挂载,但是你若不断拔插SD卡,还是有一定的概率会出意外,比如后续fopen失败。因此,这里第3个参数使用0,不马上挂载,而是等到真正读取文件时才执行挂载文件系统。

文件系统卸载

static int UnmountFilesystem(void)
{
FRESULT ret;
ret =f_mount(NULL, "0:/", 0);

return ret;
}


f_mout的第3个参数在这里没有意义,在这个f_mount函数内部会忽略它。

文件测试

相比之前的代码,文件测试我们将其改在按键回调函数中进行:

void FileTest(void)
{
FRESULT res;
uint32_t byteswritten, bytesread;                     /* File write/read counts */
uint8_t wtext[] = "This is STM32 working with FatFs"; /* File write buffer */
uint8_t rtext[100];

if(f_open(&MyFile, "0:/STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
{
/* 'STM32.TXT' file Open for write Error */
Error_Handler();
}
else
{
res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);
if((byteswritten == 0) || (res != FR_OK))
{
/* 'STM32.TXT' file Write or EOF Error */
Error_Handler();
}
else
{
f_close(&MyFile);

/*##-7- Open the text file object with read access ###############*/
if(f_open(&MyFile, "0:/STM32.TXT", FA_READ) != FR_OK)
{
/* 'STM32.TXT' file Open for read Error */
Error_Handler();
}
else
{
res = f_read(&MyFile, rtext, sizeof(rtext), (UINT*)&bytesread);

if((bytesread == 0) || (res != FR_OK))
{
/* 'STM32.TXT' file Read or EOF Error */
Error_Handler();
}
else
{
f_close(&MyFile);

/*##-10- Compare read data with the expected data ############*/
if((bytesread != byteswritten))
{
/* Read data is different from the expected data */
Error_Handler();
}
else
{
/* Success of the demo: no error occurrence */
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
}
}
}
}
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin ==GPIO_PIN_15)
{
if(BSP_SD_IsDetected() ==SD_PRESENT)
{
FileTest();
}
}
}


2 SDIO使用DMA来操作

要增加DMA,首先得在CubeMx中为SDIO分别为Tx和RX增加DMA:



图1 SDIO的DMA设置

其次需要注意地是,SDIO的几个中断优先级设置:



图2 SDIO的DMA设置

这里SDIO global inerrupt的中断优先级不能比DMA的优先级高,否则会出现DMA回调死等的情况。

最后就是对接了:

在sd_diskio.c文件中,找到SD_read函数,将BSP_SD_ReadBlocks函数改为BSP_SD_ReadBlocks_DMA函数:

DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
DRESULT res = RES_OK;

if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
(uint64_t) (sector * BLOCK_SIZE),
BLOCK_SIZE,
count) != MSD_OK)
{
res = RES_ERROR;
}

return res;
}


同样,写函数也相应地修改,使用带DMA函数:

DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
DRESULT res = RES_OK;

if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
(uint64_t)(sector * BLOCK_SIZE),
BLOCK_SIZE, count) != MSD_OK)
{
res = RES_ERROR;
}

return res;
}


需要注意地是,sd_diskio.c这个文件每次cubeMx生成代码时都会重新覆盖它,默认是使用非DMA方式的。

3 结论:

这里的关键是那个中断优先级,SDIO global中断(4)必须比DMA中断优先级高(5),否则程序会卡在DMA中断里。

另附上附件: http://download.csdn.net/detail/flydream0/9728000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: