STM32CubeMX+FreeRTOS+FatFs+SD卡的调试心得

  由于本人的习惯,新接触的东西一般先找个简单的历程实现一些简单的功能,然后再在此基础上展开,所以调试参考了众多前辈的文章,在此表示感谢,如果有需要注明出处的地方,请联系我。
  由于项目需要使用ARM实现一些数据转发等功能,考虑可能需要记录日志,于是计划项目采用STM32作为主控,原因考虑有以下:
1. STM32是目前资源比较多的ARM。简单的入门可以参考wei xue的教程。
2.价格也比较便宜,很多核心板可以用。
3.开发难度适中,对于之前从裸机(不带系统)或者51上手的人来说,st提供了stm32cubemx这个配置和代码生成工具,极大的简化了配置的过程。
4.集成了FreeRTOS,麻雀虽小,五脏俱全,量级较轻,bug比较可控。
......总之对于拿来入门和基本的使用是比较够的。

进入正题。
本次使用的芯片是STM32F407ZGT,接口为SDIO 4线,普通的TF卡。初始代码全部由STM32CubeMx生成,CubeMx为4.25.1固件cube版本为V1.0,目前CubeMx里面Middleware显示FatFS版本为R0.12c,FreeRTOS版本为9.0.0。使用和谐版MDK作为代码工具。系统的配置可参考weixue,不过用rtos的时候会稍有区别。
然而不得不说,CubeMX的坑还是不少的,其中影响到使用的有以下内容,特此作为记录:

1. 如使用了FreeRTOS,会要求强制使用DMA模板的Fatfs,所以打开DMA通道,开中断,以及开SDIO中断是必须的。

STM32CubeMX+FreeRTOS+FatFs+SD卡的调试心得_第1张图片

2. 生成代码直接编译会报个错,Bad operand types(UnDefOT, Constant) for operator( 之类的,定位到
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY 这一句,然后定位到
configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY<<(8- configPRIO_BITS) ) 这一句,然后定位到
#define configPRIO_BITS         __NVIC_PRIO_BITS 再定位到
configPRIO_BITS 这个定义,(实际是在 stm32F407xx.里面,不同的arm不一样)
#define __NVIC_PRIO_BITS          4U,这儿应该是#define __NVIC_PRIO_BITS 4,才行。
经确认除了目前这种配置外,开启其他外设配置(如IIC或者SPI)等,也会有概率出现这种问题,应该是cubeMX的bug。

3. 生成Fatfs之后,SDIO和fatfs的初始化是这样的,在main里面先初始化SDIO,然后开系统StartDefaultTask线程,此时再初始化Fatfs。所以将FatFS连接到SDIO的代码是在StartDefaultTask中的调用MX_FATFS_Init(),其中以下语句将文件系统连接至SDIO硬件:
retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
以后所有的操作都要使用SDPath这个全局变量作为句柄,如挂载(需要用户自己添加):
retSD=f_mount(&SDFatFS,SDPath,1);可以得到 对应的SDFatFS作为文件操作空间,如建立文件:
retSD = f_open(&SDFile, filename, FA_CREATE_ALWAYS | FA_WRITE);即在当前操作空间创建文件获取到文件句柄SDFile。后面即可写入或关闭文件。
然而使用自动生成的代码的问题就是f_mount(或者其他读写操作的时候),会卡很久,然后返回retSD的状态为0x01(fs_disk_err),原因就是fatfs调用底层读写SD卡接口的时候出错了,经网上各位前辈指点,原因在于:
生成的代码中sd_diskio.c中,void BSP_SD_ReadCpltCallback(void)和void BSP_SD_WriteCpltCallback(void)作为系统读写完成的回调函数(实际上是通过写入消息队列要求系统调度给fatfs的作为SD卡读写完成的标志的),然后并不正确的是,在这个文件前面函数HAL_SD_IRQHandler中,调用的名称却是HAL_SD_TxCpltCallback(hsd)(以读取为例子,写入函数也是对应的),而此函数在当前版本中为 __weak void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd),即未被用户定义的函数,默认什么事情都不做。所以需要将HAL_SD_IRQHandler调用的函数修改为BSP_SD_ReadCpltCallback(void)或者,将其内容修改为BSP_SD_ReadCpltCallback(void)中进行的队列操作,或者直接将BSP_SD_ReadCpltCallback(void)修改HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)等,(对写入操作也是如此)。然后就OK了。当然,在以前的版本中,ST似乎是意识到这个问题的,但是由于版本控制比较混乱,后面其他代码改了之后此处并未修改,ST在此处实际是有注释的:
/* USER CODE BEGIN callbackSection */
/* can be used to modify / following code or add new code */
/* USER CODE END callbackSection */
/**
  * @brief Tx Transfer completed callbacks
  * @param hsd: SD handle
  * @retval None
  */
 /*
   ===============================================================================
    Select the correct function signature depending on your platform.
    please refer to the file "stm32xxxx_eval_sd.h" to verify the correct function   

prototype  ===============================================================================

大意就是此处是要根据实际情况该的,可能会有错误哦。然后版本更替之后stm32xxxx_eval_sd.h"已经没有这个文件了。

上述三个坑填完之后,基本的读写测试就可以OK啦。





你可能感兴趣的:(心得)