如何使用CubeMx制作一个基于SD卡的文件系统工程(2)
2017-01-03 20:21
756 查看
本文是原文http://blog.csdn.net/flydream0/article/details/52777923的补充。
原文并没有考虑SD卡拔插问题,且SDIO没有使用DMA,本文作为补充,将示例如何改善这两方面的问题。
即保持CubeMx自动生成的原样即可,并不需要增加任何其他内容。
关键实在main中的while循环中检测SD卡的拔插:
如上代码,循环检测SD卡的插入状态,一旦发现状态有变化,则进行相应操作,比如挂载文件系统,或者卸载文件系统。
函数f_mount为实际操作挂载文件系统的函数,有3个输入参数,最后那个参数为0,表示先不挂载,等到fopen时再挂载,为1时,则表示立即挂载,在这个函数内部会使用check_fs函数去检查是否为FAT32文件系统,如果是,在挂载成功,否则失败。
当然这里可以立即挂载,但是你若不断拔插SD卡,还是有一定的概率会出意外,比如后续fopen失败。因此,这里第3个参数使用0,不马上挂载,而是等到真正读取文件时才执行挂载文件系统。
f_mout的第3个参数在这里没有意义,在这个f_mount函数内部会忽略它。
图1 SDIO的DMA设置
其次需要注意地是,SDIO的几个中断优先级设置:
图2 SDIO的DMA设置
这里SDIO global inerrupt的中断优先级不能比DMA的优先级高,否则会出现DMA回调死等的情况。
最后就是对接了:
在sd_diskio.c文件中,找到SD_read函数,将BSP_SD_ReadBlocks函数改为BSP_SD_ReadBlocks_DMA函数:
同样,写函数也相应地修改,使用带DMA函数:
需要注意地是,sd_diskio.c这个文件每次cubeMx生成代码时都会重新覆盖它,默认是使用非DMA方式的。
另附上附件: http://download.csdn.net/detail/flydream0/9728000
原文并没有考虑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
相关文章推荐
- 如何使用CubeMx制作一个基于SD卡的文件系统工程
- 如何制作一个读取U盘文件系统的工程
- 基于 eclipse 的 android 工程如何使用 jar 文件
- 电脑使用小技巧--如何把一个文件(夹)变成一个隐藏受系统保护的系统文件(夹)!
- 如何制作和使用Jffs2文件系统
- 基于busybox制作mini2440根文件系统及使用nfs挂载
- 使用CubeMx制作一个SD卡作为存储空间的U盘
- 基于FATFS文件系统使用SDIO的4线模式在SD卡上写入数据(一)
- 如何使用Ghost制作系统镜像文件
- 如何制作和使用Jffs2文件系统
- Django(博客系统):基于pycharm如何一个django工程下创建多个app
- 如何在 Linux 上使用 SSHfs 挂载一个远程文件系统
- 如何在 Linux 上使用 SSHfs 挂载一个远程文件系统
- 嵌入应用:如何制作和使用Jffs2文件系统 (zhuan)
- 如何制作和使用Jffs2文件系统
- 如何把BOOTLOADER,内核,文件系统,制作成一个文件
- 基于 eclipse 的 android 工程如何使用 jar 文件
- 如何制作一个通用的多系统安装U盘五(制作主配置文件)
- 如何用busybox制作一个自己文件系统
- 如何替换一个当前正被系统使用的系统文件?