【stm32f4 FreeRTOS】在FreeRTOS上 实现USB MSC(Mass Storage Class) Device 进行U盘读写

如有问题加QQ群交流:242629020 点击链接加入群聊【stm32-MCU认认真真交流群】:https://jq.qq.com/?_wv=1027&k=5n1AfYq
注意:本博客不推荐转载,如需转载请注明出处!
/**
********************* 2018年3月30日下午 13:17分  于北京  乐园路 ****************
* 工程文件夹名称:myProject_plus
* 使用的硬件平台:NUCLEO-F429ZIT6U
* keil-MDK版本:5.22
* STM32cubemx:4.24
* CubeMX支持包:STM32Cube FW_F4 V1.19.0
* 使用的操作系统:FreeRTOS
* 参考工程:STM32Cube_FW_F4_V1.19.0\Projects\STM324x9I_EVAL\Applications\USB_Host\MSC_RTOS
*************************************************************************************
* 工程包含以下功能:
* ①  printf映射到USART3 
* ②  移植好了USB MSC(Mass Storage Class) Device 
* ③  可对U盘进行读写操作
*
*************************************************************************************
* 工程状态:成功可用!!
*
*************************************************************************************
*/

       这次的移植过程很折腾,因为很多USB的例程并没有跑在操作系统上,然而我用的是FreeRTOS操作系统,并且所有的底层都由stm32cubemx配置,因此这资料就更少了,折腾了2天,直到今天上午的时候程序还一直处于阻塞状态,Debug 了无数次,在心态快要炸的时候,终于找到了 终于发现了问题所在,本次移植过程不易,所以要好好记录一下移植过程,做个记录,也顺便和大家分享,有需要用到的时候,能帮你们节省时间。因为我本人在开发过程中很依赖网络上的那些高质量博客,我受益于网络,自然也需要分享一些我自己的心得,这样就能构建一个良性循环。再小的力量也是贡献,我呼吁大家一起分享!!接下来进入正题。

本博客文字说明均在图片的上方。

先晒一下cubemx的引脚配置



//==========================================================

我使能了这些功能

① 将USB_OTG功能设置为host_only

{

注意:D+D-, 这两根数据线采用的是差分
电压的方式进行数据传输的。在

电压的方式进行数据传输的。在 USB 主机上, D- D+ 都是接了 15K 的电阻到地的,所以在没
有设备接入的时候,
D+ D- 均是低电平。而在 USB 设备中,如果是高速设备,则会在 D+ 上接
一个
1.5K 的电阻到 VCC ,而如果是低速设备,则会在 D- 上接一个 1.5K 的电阻到 VCC 。这样
当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速
设备。

}这段摘自正点原子 ->【STM32F429开发指南-HAL库版本_V1.1.pdf】-> 第五十八章 USB 读卡器 (Slave) 实验 。

所以在用这个功能前请先检查你的电路!

② 我的是NUCLEO-F429ZI板子,电路上已经配置好了VBUS(PG6)所以我勾选了VBUS功能。

③ 在USB HOST中选择Mass Storage Host Class(MSC)

④ 在FATFS中勾选USB Disk,这样就使能了FAT文件系统了。

⑤ 因为我用FreeRTOS,所以FreeRTOS肯定就要勾选上了!

⑥ Timebase source 选择TIM7,否则会有警告(不知道为什么,如果有人知道,请在评论区告诉我)


//=============================================================

时钟树

168M的主频,48M的USB_OTG


//====================================================================

FATFS & USB_HOST配置

参考微雪USB HOST教程配置的。http://www.waveshare.net/study/article-665-1.html

这里只贴了修改的地方,没修改的地方就不贴了。





//===========================================================

接下来配置比较重要的FreeRTOS

① 需要把信号量给打开,在Debug过程中,我看到fatfs的服务中会创建信号量。所以我就给他开了。

② 我这儿是开了7个任务,默认任务中运行着USB相关服务,防止死机,所以我瞎搞了一个400的堆栈大小

就这样,其他默认!



//=======================================================================

生成工程,和报告。

① 堆栈设置一下,我设置的是0x2000

② 勾选 生成独立的*.c *.h文件  这样生成的工程比较整齐



CubeMX端 配置结束。

//*******************************************************************************************************

接下来配置工程。

蓝色框框内是自动生成的,不需要修改,红色框框内的需要从别的地方移植过来,usb_host.c文件需要在里面添加代码。

① 新建USB_APP组

② 新建板级驱动STM32F4xx_Nucleo_144组

新建完组后就开始配置&移植代码

① 拷贝板级文件到工程,并添加到组

文件在:STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Drivers\BSP\STM32F4xx_Nucleo_144

② 拷贝usb应用代码到工程,并添加到USB_APP组

源代码位置:STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Projects\STM324x9I_EVAL\Applications\USB_Host\MSC_RTOS\Src


//==================================================================

拷贝完成后就开始修改代码进行适配了

① 新建一个usbh_app.h文件

       里面添加一些头文件和一些枚举的的定义。这些枚举定义是从参考工程中的main.h文件里面抄过来的。还有一些外部定义是在移植过程当中产生的。此.h文件在移植过程中起到很重要的链接作用,之后所要移植的file_operations.c 和explorer.c 中都需要#include它。


#ifndef __USBH_APP_H__
#define __USBH_APP_H__
#include "stm32f4xx_hal.h"
#include "stm32f4xx_nucleo_144.h"

#include "usbh_core.h"
#include "usbh_msc.h" 
#include "ff.h"
#include "ff_gen_drv.h"
#include "usbh_diskio.h"

typedef enum {
  MSC_DEMO_IDLE = 0,
  MSC_DEMO_WAIT,  
  MSC_DEMO_FILE_OPERATIONS,
  MSC_DEMO_EXPLORER,
  MSC_REENUMERATE,  
}MSC_Demo_State;

typedef struct _DemoStateMachine {
  __IO MSC_Demo_State state;
  __IO uint8_t        select;
}MSC_DEMO_StateMachine;

extern USBH_HandleTypeDef hUsbHostFS;
extern FATFS USBH_fatfs;
extern FIL MyFile;
extern USBH_HandleTypeDef hUSBHost;
FRESULT Explore_Disk(char *path, uint8_t recu_level);
void MSC_File_Operations(void);
void Toggle_Leds(void);
void Menu_Init(void);
void MSC_MenuProcess(void);

#endif

② 修改file_operations.c 文件

篇幅所限,这个文件的源代码我就不贴了,我会贴出工程下载地址。

https://download.csdn.net/download/mryarnell/10318238

这个文件中就只有一个函数,用来测试读写文件。

void MSC_File_Operations(void)

       ① 原工程中很多输出都是到LCD屏的,因为我的板子上没有LCD接口,所以我就把LCD输出都改成了printf输出。

       ② 然后包含一下我们自己创建的usb_app.h文件就可以了。

③ 修改explorer.c 文件

    和修改file_operations.c 文件一样。

      ① 把LCD输出改成printf输出。

      ② 然后包含一下我们自己创建的usb_app.h文件就可以了。

④ 修改usb_host.c文件

    修改里面的static void USBH_UserProcess  (USBH_HandleTypeDef *phost, uint8_t id)函数

      原本这里面的switch,case是空走的,没有执行任何操作。这里面的代码是参照参考工程main.c->static void USBH_UserProcess 函数添加的。这个函数会在USBH_Init初始化的时候被调用,并进行挂载U盘。

static void USBH_UserProcess  (USBH_HandleTypeDef *phost, uint8_t id)
{
  /* USER CODE BEGIN CALL_BACK_1 */
  switch(id)
  {
  case HOST_USER_SELECT_CONFIGURATION:
  break;

  case HOST_USER_DISCONNECTION:
  Appli_state = APPLICATION_DISCONNECT;
	if (FATFS_UnLinkDriver(USBDISKPath) == 0)
	{
	  if(f_mount(NULL, "", 0) != FR_OK)
	  {
		  HAL_GPIO_WritePin(LD3_GPIO_Port,LD3_Pin,GPIO_PIN_SET);
		//printf("ERROR : Cannot DeInitialize FatFs! \r\n");
	  }
	}
  break;

  case HOST_USER_CLASS_ACTIVE:
  Appli_state = APPLICATION_READY;
  break;

  case HOST_USER_CONNECTION:
  Appli_state = APPLICATION_START;
  if (FATFS_LinkDriver(&USBH_Driver, USBDISKPath) == 0)
  {
    if (f_mount(&USBH_fatfs, "", 0) != FR_OK)
    {
		HAL_GPIO_WritePin(LD3_GPIO_Port,LD3_Pin,GPIO_PIN_SET);
      //printf("ERROR : Cannot Initialize FatFs! \r\n");
    }
  }
  break;

  default:
  break;
  }
  /* USER CODE END CALL_BACK_1 */
}

⑤ 修改FreeRTOS文件

在默认任务中添加2行。

要注意的是进行文件操作前,需要延时一段时间,因为U盘挂载需要时间,我这里是延时了2s

void StartDefaultTask(void const * argument)
{
  /* init code for USB_HOST */
  MX_USB_HOST_Init();

  /* init code for FATFS */
  MX_FATFS_Init();

  /* USER CODE BEGIN StartDefaultTask */
    osDelay(2000);
	MSC_File_Operations();
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

最后一个最重要的地方,是我2天下来的精华。大哭

       经过无数次的dubug,我一直卡在f_mount函数中,也就说是只要我一执行这个函数,单片机就直接死机,期间把电子论坛的半壁江山都光过来了,国内外的论坛来来回回进进出出的求索,都最终无果。唯一让我搜寻到有用的一条线索就是让我找到了存在与cube库中的相应例程。

      debug的结果让我非常奇怪,我的程序竟然在创建一个信号量的时候死机了??创建信号量的时候死机微笑 敢信吗?所以我就去把关于信号量的配置,全部使能了。我自己创建了一个信号量都完全 莫门忒!!所以对此问题我又debug......等等各种尝试,最后还好我机灵的去看了看参考工程中的_FS_REENTRANT 的值是什么,结果我发现参考工程中这个值为0,而我的这个值为1 。。心理默骂cubeMX,干嘛给老子设置成1?参考工程中这语句就根本没有进行编译,所以我就把这个_FS_REENTRANT的值改成了0   .然后就大吉大利,程序不死机了!我看到了希望,心态不炸了!!奋斗

  

ff.c的3279行。

敲黑板!       现在告诉你解决方法:

       请你找到一个叫ffconf.h的文件!

把275行_FS_REENTRANT 的值由1 改成0  然后执行f_mount的时候就 不会死机了。

注意:本博客不推荐转载,如需转载请注明出处!

源代码下载链接:https://download.csdn.net/download/mryarnell/10318238

STM32CubeMX配置报告下载链接:https://download.csdn.net/download/mryarnell/10318776

如有问题加QQ群交流:242629020 点击链接加入群聊【stm32-MCU认认真真交流群】:https://jq.qq.com/?_wv=1027&k=5n1AfYq

猜你喜欢

转载自blog.csdn.net/MrYarnell/article/details/79756319