首页 > 其他分享 >STM32CubeMX教程30 USB_DEVICE - MSC外设_读卡器

STM32CubeMX教程30 USB_DEVICE - MSC外设_读卡器

时间:2024-01-31 10:47:43浏览次数:36  
标签:CODE HAL USB 30 STM32CubeMX USBD 外设 SD

1、准备材料

正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0

keil µVision5 IDE(MDK-Arm

ST-LINK/V2驱动

野火DAP仿真器

XCOM V2.6串口助手

2、实验目标

使用STM32CubeMX软件配置STM32F407开发板USB_OTG_FS为工作在Mass Storage Class(大容量存储类)模式下的USB_DEVICE(USB从机),使其作为SD卡读卡器在Windows系统文件资源管理器中直接对SD卡进行读写操作

3、实验流程

3.0、前提知识

关于USB的相关知识请读者阅读STM32CubeMX教程29 USB_HOST - 使用FatFs文件系统读写U盘实验“3、USB概述”小节内容,USB_SALVE 从机接口硬件原理图请读者阅读其“4.0、前提知识”小节内容

当USB工作在USB_DEVICE时可以将其模式配置为以下6种模式中的任何一种,本实验只会介绍其中的大容量存储设备,其他的一概不涉及,具体的6种模式如下图所述

将USB设备接口配置工作在Mass Storage Class模式下,主要是为了将没有USB接口的大容量的存储设备(eg:SD卡)通过该接口,利用USB连接与USB主机之间建立联系,然后便可以通过USB主机对该大容量存储设备进行控制

对于USB_OTG_FS工作在任意USB外设模式下来说,在CubeMX中一般需要对Configuration下Parameter Settings、Device Descriptor 和User Constants三个参数页面参数进行配置(虽然这些参数一般无需修改,保持默认即可)

其中Parameter Settings 选项卡下的参数会根据不同的外设工作模式出现对应该外设的一些重要参数设置,不同外设出现的参数不尽相同

Device Descriptor 选项卡下的参数则较为固定,不同外设之间往往只会改变Device Descriptor FS下的参数,该选项卡下的所有参数主要用于描述该USB外设,正因为其参数则较为固定,因此这里笔者直接列出了各个参数的含义,在之后的其他外设实验中便不再重复说明,具体含义如下图所示

User Constants 选项卡主要用于设定一些用户需要的常量参数,增加之后会以宏定义的形式出现在main.h文件中

在完成该实验之后读者也可以验证下设备描述符中内容和Windwos中读取到的USB设备描述符是否一致

右键单击弹出的U盘驱动器,单击属性,双击硬件选项卡中的STM Product USB Device,在弹出的页面中单击详细信息,最后在属性里面找到父系,可以在下面找到设备描述中的VID和PID,将其转换为十进制之后发现和我们设定值一致,具体如下图所示

3.1、CubeMX相关配置

3.1.0、工程基本配置

打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示

开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示

详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立

3.1.1、时钟树配置

将时钟树中48MHz时钟配置为48MHz,也即将Main PLL(主锁相环)的Q参数调节为7,其他HCLK、PCLK1和PCLK2时钟仍然设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置

本实验需要需要初始化USART1作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信

另外由于需要通过SDIO读写SD卡,USB_OTG_FS工作在从机模式下,因此还需要配置SDIO和USB_OTG_FS

单击Pinout & Configuration页面左边功能分类栏目中Connectivity/SDIO,将其模式配置为4位宽总线SD卡,在下方参数配置Configuration/Parameter Settings中将参数 SDIOCLK clock divide factor 配置为4即可,具体参数含义请读者阅读STM32CubeMX教程27 SDIO - 读写SD卡实验内容,具体配置如下图所示

单击Pinout & Configuration页面左边功能分类栏目中Connectivity/USB_OTG_FS,将其模式配置为仅从机(Device_Only),其他所有参数保持默认即可,具体配置如下图所示

单击Pinout & Configuration页面左边功能分类栏目中Middleware and Software Packs/USB DEVICE,将其模式配置为Mass Storage Class(大容量存储类),其他所有参数保持默认即可,具体配置如下图所示

USBD_MAX_NUM_INTERFACES (支持的最大接口数):可选1 ~ 255,不应超过可用内存的总大小

USBD_MAX_NUM_CONFIGURATION (支持的最大配置数):可选1 ~ 255,不应超过可用内存的总大小

USBD_MAX_STR_DESC_SIZ (字符串描述符的最大大小) :可选1 bytes ~ 64 Kbytes,用于设定Device Descriptor页面中对该USB设备的一些描述字符串最大长度

USBD_SELF_POWERED (启用自供电) :可选Enable、Disable,此处选择Enable表示USB设备有自己的电源供应,不需要从USB总线上获取电力

USBD_DEBUG_LEVEL (USBD调试级别):可选0、1、2、3,具体调试级别如下所示

  1. 0 : No debug message is shown
  2. 1 : only User message are shown
  3. 2 : User + Error messages are shown
  4. 3 : All message and interal debug message are shown

MSC_MEDIA_PACKET (媒体I/O缓冲区大小):可选1 bytes ~ 32 Kbytes,在USB大容量存储设备中,数据传输通常是以数据包为单位进行的,该宏定义了每个数据包的大小

3.1.3、外设中断配置

当在Middleware and SoftwarePacks中配置了USB_DEVICE的模式不为Disable时,便会自动开启USB_OTG的全局中断,且不可关闭,用户配置合适的中断优先级即可,具体配置如下图所示

3.2、生成代码

3.2.0、配置Project Manager页面

单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示

详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节

3.2.1、设初始化调用流程

打开生成的工程,观察目录结构,由于启用了USB_DEVICE,因此在工程目录种增加了USB设备库文件目录USB_Device_Library,在USB_DEVICE/Target目录下增加了usbd_conf.c参数配置文件,在USB_DEVICE/App目录下增加了usb_device.c初始化文件、usbd_desc.c描述文件和usbd_storage_if.c外设接口文件

其中USB_Device_Library目录下所有文件、usbd_conf.c、usbd_desc.c和usb_device.c几个文件均不需要在生成的工程代码中做任何修改,用户唯一需要修改的是在usbd_storage_if.c外设接口文件中实现的大容量存储设备的接口函数,如下图所示为USB_DEVICE工作在Mass Storage Class下生成工程文件目录

究竟是在哪里将需要我们在usbd_storage_if.c外设接口文件中重新实现的接口函数与USBD实例化对象联系起来的呢?

在 usb_device.c 文件中只有MX_USB_DEVICE_Init()一个函数,该函数体内执行了四个函数对USB_DEVICE进行了初始化和启动操作

其中通过调用USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_Storage_Interface_fops_FS)函数,将一个USBD_StorageTypeDef类型的结构体与USBD实例化对象联系了起来,该USBD_StorageTypeDef类型的结构体中包含的正是usbd_storage_if.c外设接口文件中的所有接口函数指针

3.2.2、外设中断调用流程

未使用外设任何中断

3.2.3、添加其他必要代码

STM32CubeMX工程生成工程代码后,读者应注意手动修改MX_SDIO_SD_Init()函数中SD卡数据总线宽度从默认的4位手动修改为1位,否则SD卡将初始化失败

根据上面的描述,唯一需要用户修改的地方是usbd_storage_if.c文件中的7个函数,与W25Q128芯片移植FatFs时类似,读者可以参考STM32CubeMX教程26 FatFs 文件系统 - W25Q128读写实验“3.2、生成代码“小节内容,如下所示为重新实现后的七个函数源代码

/*usbd_storage_if.c*/

/*初始化函数无需修改,因为SD卡初始化在SDIO初始化函数中已完成*/
int8_t STORAGE_Init_FS(uint8_t lun)
{
  /* USER CODE BEGIN 2 */
 UNUSED(lun);

  return (USBD_OK);
  /* USER CODE END 2 */
}

/*获取存储介质容量*/
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */
	HAL_SD_CardInfoTypeDef cardInfo;
	//使用SDIO库函数
	HAL_StatusTypeDef res = HAL_SD_GetCardInfo(&hsd, &cardInfo);
	if(res == HAL_OK)
	{
		*block_num  = cardInfo.BlockNbr;    //块的个数
		*block_size = cardInfo.BlockSize;   //块大小=512字节
	}
	else
	{
		*block_num  = STORAGE_BLK_NBR;	    //0x10000
		*block_size = STORAGE_BLK_SIZ;      //块大小=512字节
	}
	
	return (USBD_OK);
  /* USER CODE END 3 */
}

/*返回存储介质是否准备好,无需修改*/
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
  /* USER CODE BEGIN 4 */
  UNUSED(lun);

  return (USBD_OK);
  /* USER CODE END 4 */
}

/*返回存储介质是否写保护,,无需修改*/
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
  /* USER CODE BEGIN 5 */
  UNUSED(lun);

  return (USBD_OK);
  /* USER CODE END 5 */
}

/*读取存储介质*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
	//读取超时时间10000ms
	uint32_t Timeout = 10000;  
	HAL_StatusTypeDef res = HAL_OK;
	res = HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, Timeout);
	HAL_SD_CardStateTypeDef status = HAL_SD_CARD_RECEIVING;
	
	if(res == HAL_OK)
	{
		//等待传输完成
		while(status != HAL_SD_CARD_TRANSFER)   
			status = HAL_SD_GetCardState(&hsd);
		return (USBD_OK);
	}
	else
		return (USBD_FAIL);
  /* USER CODE END 6 */
}

/*向存储介质写入数据*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */
	//写入超时时间10000ms
	uint32_t Timeout = 10000;   
	HAL_StatusTypeDef res = HAL_OK;
	res = HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, Timeout);
	HAL_SD_CardStateTypeDef status = HAL_SD_CARD_SENDING;
	
	if (res == HAL_OK)
	{
		//等待传输完成
		while(status != HAL_SD_CARD_TRANSFER)   
			status = HAL_SD_GetCardState(&hsd);
		return (USBD_OK);
	}
	else
		return (USBD_FAIL);
  /* USER CODE END 7 */
}

/*返回最大支持LUN数量,无需修改*/
int8_t STORAGE_GetMaxLun_FS(void)
{
  /* USER CODE BEGIN 8 */
  return (STORAGE_LUN_NBR - 1);
  /* USER CODE END 8 */
}

4、烧录验证

烧录程序,开发板上电后,使用USB线将Windows电脑与开发板上的USB_SLAVE接口连接,连接成功后电脑上会弹出与U盘插入时一致的弹窗(第一次可能会自动安装驱动,稍微等待等待),之后就可以在文件资源管理器中找到新的可用卷

单击打开该卷便可以像操作U盘一样对开发板上插入的SD卡进行文件管理,如下图所示笔者的SD卡里还保存着之前实验所写入的信息,读者可以自行尝试写入或删除文件

读者还可以自己将本实验与STM32CubeMX教程28 SDIO - 使用FatFs文件系统读写SD卡实验结合来验证使用FatFs读写SD卡操作是否真正成功,笔者通过开发板上的KEY0按键删除了原本写入SD卡中的test.txt文件,复位开发板重新识别SD卡之后,在Windwos资源管理器里查看发现test.txt文件确实被删除了,具体操作如下图所示

5、常用函数

请阅读STM32CubeMX教程28 SDIO - 使用FatFs文件系统读写SD卡实验“7、常用函数”小节

参考资料

STM32Cube高效开发教程(高级篇)

标签:CODE,HAL,USB,30,STM32CubeMX,USBD,外设,SD
From: https://www.cnblogs.com/lc-guo/p/17985801

相关文章

  • 【2024-01-30】回南天气
    20:00打开你们的窗子吧,打开你们的板门吧,让我进去,让我进去,进到你们的小屋里。我带着金黄的花束,我带着林间的香气,我带着亮光和温暖,我带着满身的露水。快起来,快起来,快从枕头里抬起头来,睁开你的被睫毛盖着的眼,让你的眼看见我的到来。让你们的心像小小的木板房,打开它们的关闭了很久的......
  • 2024-01-30 闲话
    Abstract杨卓凡说垃圾话往往是进行“带有某种目的的表达”,但是你的狗叫是完全融入了生活的方方面面。——Yubai本文将是随机observation。Introduction总结一下寒假半个月的一些想法和对一些事情分析的记录。你要是因为要素察觉而看到一半蚌埠住了,我觉得这也是能理解的;你......
  • 2024/1/30 scala、Flink
    scala的模式匹配:很强大,也很难记住。和java相比,代码简洁了,但是熟练难度却上去了。 各种花里胡哨的模式匹配。还有很多至简原则。无疑是给新手带来了很多的麻烦。 这个scala给人的印象是:java?python?js?的集大成者???......
  • 2024.1.30做题纪要
    [bzoj3569]DZYLovesChineseII第一眼:这和线性基有什么关系。。。第二眼:这到底跟线性基有什么关系???对于一个图,我们先想建树,然后加返祖边。我们考虑一下对于一个点什么情况才会出现不连通的情况???当连接这个点的树边和跨过这个点的非树边都断开时不连通。那我们怎么判断是不是都......
  • 20240130
    A.01矩形枚举上下界,two-pointers//Author:xiaruize//#pragmaGCCoptimize("-ofast")#include<bits/stdc++.h>usingnamespacestd;//#defineintlonglong#defineullunsignedlonglong#defineALL(a)(a).begin(),(a).end()#definepbpush_ba......
  • 1.30
    今天主要就是打博客了,也是有不小收获的,也是将之前存在一些疑惑和不理解的地方解决了。打的时候也不是很容易,想办法解释为什么这么理解的过程也是大大加深了自己对其的理解。\(wps\)用来画图感觉挺不错的,\(linux\)没有画图,\(windows\)那个破画图也相当难用。借助图来理解还......
  • 24.1.30(读后感)
    第三章软件工程师的成长3.1个人能力的衡量与发展①软件工程包括了开发、运用、维护软件的过程中的很多技术、做法、习惯和思想。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”,软件开发流程的目的是为了提高软件开发、运营和维护的效率,以及提升用户满意度......
  • 1.30闲话
    听说明天有唐氏模拟赛,据说有\(tarjan\)推歌:普通Disco/洛天依,言和byilem呃呃呃我打算进行一个主席树和多项式的双开,同时写主席树和多项式因为我主席树有点遇到了瓶颈,先学学数学看看,到时候一起写\(wkh2008\):开辟第二战场多项式基础多项式是什么(初一知识点)形如下面的......
  • 闲话1.30
    haosen不在的第二天,想她......
  • 30岁以上的程序员该何去何从?最高年薪160万,只看技术不看年龄
    最近关于“大龄程序员”的话题,又被推上热搜!30岁后程序员应该何去何从?有网友发帖说:我刚毕业在百度,后来在阿里呆了几年,现在快35岁了,失业一年也没有重新找到工作!然后就有网友反驳:不要制造恐慌,自己30岁投简历都能过,一个人不能代表全部,机会永远是留给有能力的人的。出现这种情况的......