提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

前言一、USB概述二、STM32F4相关硬件介绍三、RT-Thread配置usb_device1.RT-Thread Setting设置2.board.h的4步实现SDIO配置第一步:已经在“**1.RT-Thread Setting设置**”中实现了。第二步:定义与sdio相关的宏(如上图):第三步:将您的sdio初始化函数从stm32cubemx生成的stm32xxxx_hal_msp.c复制到board.c文件的末尾:第四步:修改stm32xxxx_hal_config.h文件以支持sdio外围设备。定义与外围设备相关的宏。第五步:配置设备文件系统或其他应用程序

3.board.h的5步实现USB_DEVICE配置第一步:已经在“**1.RT-Thread Setting设置**”中实现了。第二步:定义与usb设备相关的宏:第三步:将您的usb设备初始化函数从stm32cubemx生成的stm32xxxx_hal_msp.c复制到board.c文件中:第四步:在STM32CubeMX生成的SystemClock_config()中配置usb外设时钟,并替换drv_clk.c中的SystemClock_config()函数。【!!!这里需要注意的是:USB OTG FS需要特定的时钟48MHz(来自于特定 PLL 输出 (PLL48CLK) )】第五步:修改您的stm32xxxx_hal_config.h文件以支持usb设备外围设备。定义与外围设备相关的宏

四、遇到的问题和解决方法问题1:disk open error问题2:串口打印乱码问题3:配置成功后一些未定义的错误问题4:串口无反应的情况问题5:用来ENV工具配置时,遇到的bug是文件操作指令无法运行,list_device无内容调试时遇到的问题:

五、实验结果总结

前言

作为新入门的嵌入式选手,基于项目需要最近在学习RT-Thread操作系统,鉴于自己健忘的记性,打算记录下来后面好回顾学习。 今天要总结的是RT-Thread-基于usb device用SD卡实现U盘功能(读卡器功能),参考了很多大神的博文,站在大神的高度进行内容重复和汇总,算是督促自己学习进步的手段之一吧,如有错误请大家及时指出,感谢!

提示:以下是本篇文章正文内容,如有错误请评论或私信指出哈

一、USB概述

USB(Universal Serial Bus)是一种支持热插拔的通用串行总线。在 USB 1.0和 USB 1.1 版本中,只支持 1.5Mb/s 的低速(low-speed)模式和 12Mb/s 的全速(full-speed)模式,在 USB 2.0 中,又加入了480Mb/s 的高速模式,USB 3.0(super speed),传输速率最大5Gbps。

STM32F407 自带的 USB 符合 USB2.0 规范,且探索者 STM32F4 开发板没有外扩高速 PHY 芯片,仅支持 USB OTG FS(FS,即全速,12Mbps)。在主机模式下,OTG FS 支持全速(FS,12Mb/s)和低速(LS,1.5 Mb/s)收发器,而从机模式下则仅支持全速(FS,12 Mb/s)收发器。OTG FS 同时支持 HNP 和 SRP。

标准 USB 共四根线组成,除 VCC/GND 外,另外为 D+和 D-,这两根数据线采用的是差分电压的方式进行数据传输的。在 USB 主机上,D-和 D+都是接了 15K 的电阻到地的,所以在没有设备接入的时候,D+、D-均是低电平。而在 USB 设备中,如果是高速设备,则会在 D+上接一个 1.5K 的电阻到 VCC,而如果是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC。这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。

在 USB 体系中又包括 USB Host(主机)和USB Device(设备)

USB Host: 任何USB系统中只有一个主机。 主机系统的USB接口被称为主机控制器。 主机控制器可以以硬件,固件或软件的组合来实现。 根集线器集成在主机系统内以提供一个或多个连接点。USB Device USB Device 可以分为 USB Hub 和 USB Function。 USB Hub 提供了一种低成本、低复杂度的 USB接口扩展方法。Hub 的上行端口面向 HOST,下行端口面向设备(Hub 或功能设备)。在下行端口上,Hub 提供了设备连接检测和设备移除检测的能力,并给各下行端口供电。Hub 可以单独使能各下行端口。不同端口可以工作在不同的速度等级(高速/全速/低速)。 USB Function 能够通过总线传输或接收数据或控制信息的设备,在 USB2.0 标准中,别称为 Class。

本文主要是基于正点原子STM32F407ZG开发板,给出了 USB Device 读写 SD卡建立的U 盘的配置和使用示例。

二、STM32F4相关硬件介绍

USB 座没有直接连接到 STM32F4 上面,而是通过 P11 转接,所以我们 需要通过跳线帽将 PA11 和 PA12 分别连接到 D-和 D+ 不过这个 MiniUSB 座和 USB-A 座(USB_HOST)是共用 D+和 D-的,所以他们不能同时使用。这个在使用的时候,要特别注意!!本实验测试时,USB_HOST 不能插入任何 USB 设备!

三、RT-Thread配置usb_device

1.RT-Thread Setting设置

需要打开虚拟文件系统和SDIO,使用SDIO作为USB设备来实现。 打开“使用USB设备”,配置使能为大容量存储设备”Enable to use device as Mass Storage device“,需要注意的是“设置MSC类磁盘名”时要对应!!!默认为flash0,改为了sd0。

2.board.h的4步实现SDIO配置

第一步:已经在“1.RT-Thread Setting设置”中实现了。

第二步:定义与sdio相关的宏(如上图):

例如:#define BSP_USING_SDIO——board.h

第三步:将您的sdio初始化函数从stm32cubemx生成的stm32xxxx_hal_msp.c复制到board.c文件的末尾:

(注:打开CubeMx Settings,设置完成后生成代码,在工程中的cubemx文件夹中找到stm32xxxx_hal_msp.c文件,获得相应初始化函数) 例如: void HAL_SD_MspInit(SD_HandleTypeDef hsd)

void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

if(sdHandle->Instance==SDIO)

{

/* USER CODE BEGIN SDIO_MspInit 0 */

/* USER CODE END SDIO_MspInit 0 */

/* SDIO clock enable */

__HAL_RCC_SDIO_CLK_ENABLE();

__HAL_RCC_GPIOC_CLK_ENABLE();

__HAL_RCC_GPIOD_CLK_ENABLE();

/**SDIO GPIO Configuration

PC8 ------> SDIO_D0

PC9 ------> SDIO_D1

PC10 ------> SDIO_D2

PC11 ------> SDIO_D3

PC12 ------> SDIO_CK

PD2 ------> SDIO_CMD

*/

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_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_2;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;

HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

/* SDIO interrupt Init */

HAL_NVIC_SetPriority(SDIO_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(SDIO_IRQn);

/* USER CODE BEGIN SDIO_MspInit 1 */

/* USER CODE END SDIO_MspInit 1 */

}

}

第四步:修改stm32xxxx_hal_config.h文件以支持sdio外围设备。定义与外围设备相关的宏。

*例如: #define HAL_SD_MODULE_ENABLED

第五步:配置设备文件系统或其他应用程序

前2个步骤开启文件系统的时候就已经被调用了。 第3步:如果是使用SDIO,会在程序中自动初始化注册为块设备,则也不需要编写,如果是使用SPI则需要编写注册块设备语句。 第4、5步的程序编写,先格式化,然后再挂载块设备到DFS目录上,之后就可以开始验证工作了。

代码如下(示例):

void mnt_init(void)

{

rt_thread_mdelay(100);//这段延时必须加上,系统上电过程中存在延时,否则会出现先挂载后注册块设备sd0的情况

//mkfs("elm","sd0");//挂在前需格式化

rt_device_t dev=RT_NULL;

dev=rt_device_find("sd0");

if(dev != RT_NULL)

{

if(dfs_mount("sd0","/","elm",0,0)==0) //挂载文件系统,参数:块设备名称、挂载目录、文件系统类型、读写标志、私有数据0

{

rt_kprintf("dfs mount success\r\n");

}

else

{

rt_kprintf("dfs mount failed\r\n");

dfs_mkfs("elm","sd0");//若挂载失败,则格式化

}

}

}

INIT_ENV_EXPORT(mnt_init); //自动初始化

3.board.h的5步实现USB_DEVICE配置

第一步:已经在“1.RT-Thread Setting设置”中实现了。

第二步:定义与usb设备相关的宏:

例如:#define BSP_USING_USBDEVICE——board.h

第三步:将您的usb设备初始化函数从stm32cubemx生成的stm32xxxx_hal_msp.c复制到board.c文件中:

例如: void HAL_PCD_MspInit(PCD_HandleTypeDef hpcd)

void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

if(pcdHandle->Instance==USB_OTG_FS)

{

/* USER CODE BEGIN USB_OTG_FS_MspInit 0 */

/* USER CODE END USB_OTG_FS_MspInit 0 */

__HAL_RCC_GPIOA_CLK_ENABLE();

/**USB_OTG_FS GPIO Configuration

PA11 ------> USB_OTG_FS_DM

PA12 ------> USB_OTG_FS_DP

*/

GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* USB_OTG_FS clock enable */

__HAL_RCC_USB_OTG_FS_CLK_ENABLE();

/* USB_OTG_FS interrupt Init */

HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(OTG_FS_IRQn);

/* USER CODE BEGIN USB_OTG_FS_MspInit 1 */

/* USER CODE END USB_OTG_FS_MspInit 1 */

}

}

第四步:在STM32CubeMX生成的SystemClock_config()中配置usb外设时钟,并替换drv_clk.c中的SystemClock_config()函数。【!!!这里需要注意的是:USB OTG FS需要特定的时钟48MHz(来自于特定 PLL 输出 (PLL48CLK) )】

第五步:修改您的stm32xxxx_hal_config.h文件以支持usb设备外围设备。定义与外围设备相关的宏

例如:#define HAL_PCD_MODULE_ENABLED

四、遇到的问题和解决方法

问题1:disk open error

通过第三部分已完成了配置流程,但在我实际实验中,遇到了报错:“disk open error”。 通过搜索发现问题在mstorage.c文件下rt_device_open(data->disk, RT_DEVICE_OFLAG_RDWR) != RT_EOK出现了报错。 通过一顿查找,发现了和我们有相似问题的博文链接 问题是:块设备的访问问题,只允许被打开一次!! 解决方法参考了上述博文,可具体点上面链接查看。 我采用的方法是:usb mstorage.c 的_function_enable函数那里在open前先做判断,如果已经open了,则不需要再open了:

if ((data->disk->flag & RT_DEVICE_FLAG_STANDALONE) &&(!(data->disk->open_flag & RT_DEVICE_OFLAG_OPEN)))

{

if(rt_device_open(data->disk, RT_DEVICE_OFLAG_RDWR) != RT_EOK)

{

rt_kprintf("disk open error\n");

return -RT_ERROR;

}

}

问题2:串口打印乱码

问题是CubeMX配置时时钟配错了,我所用的板子的晶振是8M,这类问题的排查可根据打印数据的长度来排查。

问题3:配置成功后一些未定义的错误

需要依据具体情况来补充。

问题4:串口无反应的情况

在使用cubeMX配置后,串口需要重新配置。

问题5:用来ENV工具配置时,遇到的bug是文件操作指令无法运行,list_device无内容

问题在于SD卡第一次未初始化,需要调用: dfs_mkfs(“elm”,“sd0”);//若挂载失败,则格式化

调试时遇到的问题:

晶振方面RT-Thread版本方面时钟方面 如遇到SDIO和USB无法正常运行的情况,可考虑这三个方面的原因。

五、实验结果

编译无错后,烧录程序,连接串口list_device可以看到sd0,usb device。

插入MiniUSB 座到电脑后,此时SD卡能被识别,相当于U盘,类似读卡器的功能就实现了。

总结

其实是一个简单的配置,但还是遇到了很多问题。主要参考了一些博文、rt-thread参考文档和STM32开发指南,算是对自己学习的一种总结吧,希望坚持下去,感谢各位大神们多多指点。

文章链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。