提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言一、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开发指南,算是对自己学习的一种总结吧,希望坚持下去,感谢各位大神们多多指点。
文章链接
发表评论