moyanming2013 发表于 2017-5-7 23:35:52

【NUCLEO-L496ZG评测】STM32CubeMX+内部RAM模拟U盘 USB DEVICE MSC的实现

本帖最后由 moyanming2013 于 2017-5-8 22:38 编辑

非常感谢STM32社区(https://www.stmcu.org.cn/)和STM32官网(http://www.stmcu.com.cn/)!本文需要首先完成《【NUCLEO-L496ZG评测】ST-LINK驱动+STM32CubeMX+MDK-ARM开发环境搭建及调试简单程序》中的内容。1.    STM32CubeMX配置新建一个工程:在“MCUSelector”标签中选择“STM32L496ZGTx”:“SYS”选择“Trace Asynchronous Sw”调试器:说明:如果不选择调试器,有时候MX生成的代码会把调试端口关闭,这里为了确保工程的完整性需要把调试器选进来,另外选进来调试器也不会占用额外的程序代码。如果关闭了调试端口的功能,下次烧录程序时就需要使用IAP的方式而不能使用SWD的方式烧录了。本开发板中,主MCU外接了一个外部的低速晶振(LSE),频率为32.768。如下图示:基本上来说,针对每个开发板上的MCU,都需要至少连接一个低速的外部晶振,该晶振满足低时钟、低功耗,但是它也只能提供部分的系统时钟来源。要想完成诸如USB设备和主机的使能,往往需要外部接一个高速晶振来使得USB可以得到一个48MHz的时钟。在有些场景下,额外的高速晶振提高了成本和PCB面积占用,更重要的是使能的高速晶振还是耗电大户,但又不得不开启它。L496内部有一个特殊的时钟源MSI,该时钟不需要高速晶振就可以灵活配置以满足各类时钟需要,包含系统时钟和USB时钟等。但可想而知MSI的精度比不上外部高速晶振。但如果系统有外部低速晶振,要想使得MSI时钟有更高的精度,启用该LSE时钟,MCU硬件会自动根据LSE矫正MSI的精度,使得MSI可以满足更高精度的USB时钟源,此时就可以无需外接HSE晶振了。“RCC”中选择“Low Speed Clock(LSE)->Crystal/Ceramic Resonator”:后面在配置时会看到MSI自动矫正自动使能了,不选择LSE则矫正不会使能。“USBOTG FS”中选择“Device_Only”:先添加PG8和PG7为“LPUART1”,然后在“LPUART1”中的“mode”选择“Asynchronous”。说明:如果新建工程时通过“Board Selector”选项选择的话,STM32CubeMX会自动添加一些配置以符合选择的Board的硬件布局,但截至目前(STM32CubeMX v4.20.1)该硬件布局给出的是错误的,包括与ST-LINK连接的串口号等。所以建议从MCU Selector开始一个STM32CubeMX工程,并手动配置各个部分,这也是针对自己PCB硬件时应该用的方法。添加中间件:选择“USB_DEVICE->Mass Storage Host Class”:点击“Clock Configuration”标签,选择“Yes”,让STM32CubeMX自动调整下时钟,如果不符合还可以自己手动调:确保时钟配置如下所示:选择“Configuration”选项卡,可以在RCC中看到MSI时钟精度自动矫正已经使能了,如果不添加LSE,此处是不能使能的:选择“LPUART1”,调整波特率为115200和8Bits字长:其它都保持默认即可。点击齿轮按钮(或Project->Settings菜单),调整工程选项,注意一定要增加堆和栈的大小,否则在加载USB设备时可能出现错误。说明:如果使用其它的IDE,则只需要修改Toolchain/IDE为目标IDE即可。在“CodeGenerator”中选择“Generate peripheral initialization as apair of ‘.c/.h’ files per”,可以使得外设分别有自己的头文件和源文件,点击“OK”按钮:STM32CubeMX会自动开始生成工程(如果没有开始生成则再次点击齿轮按钮即可),生成完成后,如果完成了MDK-ARM的安装或其它IDE的安装,点击“Open Project”即可自动开启MDK-ARM工程:2.    调试USB2.0 FS Device MSC工程需要自己添加部分代码,才能够完成USB Device MSC的RAM模拟U盘功能。STM32CubeMX基于HAL库生成了程序的框架,在该框架中我们只需要完成部分功能函数即可。在USB Device MSC程序中,为了能够让电脑发现通过MCU的RAM模拟的U盘,我们需要补充完成“usbd_storage_if.c”中的几个函数。这里给出最重要的读和写的函数说明,其它的具体见附件示例代码。static int8_tSTORAGE_Read_FS (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);STORAGE_Read_FS是读函数,它完成读RAM空间的功能,使得电脑在打开、格式化、读等任务时可以及时的返回数据给电脑。lun是分区号,我们只用1个分区,这里lun会是0;buf是要填充的区域,只需要根据分区号、扇区号和块数量来填充buf即可;blk_addr是扇区号,它的值形如0、1、2、3、4、5、6等,是告诉我们第几个扇区,而不是具体的地址值,需要注意不要看字面意思;blk_len是要读取的块数量,不是块的大小,需要注意这个不友好的字面意思。块的大小由STORAGE_BLK_SIZ提供,一般是512、1024、4096等值。具体实现如下图:说明:g_ramBuf是声明的一个大容量数组,既用它来模拟U盘。static int8_tSTORAGE_Write_FS (uint8_t lun, uint8_t *buf, uint32_t blk_addr,uint16_t blk_len);STORAGE_Write_FS的参数和STORAGE_Read_FS的参数意思基本一致,只是STORAGE_Write_FS函数的参数buf含有要写入RAM的数据。具体实现如下图:编译程序并启动调试,把g_ramBuf添加到Memory窗口,以便查看数据。点击运行,此时系统发现磁盘,并提示格式化,选择“格式化磁盘”,系统可以正确的完成格式化,我们可以看到g_ramBuf经过格式化后的前512字节的内容和格式化后的U盘如下图:g_ramBuf中的前512字节是FAT文件格式的扇区结构,具体可以参考相关文档。如果不想每次都让系统提示格式化,那么可以把这512字节作为字符串存入g_ramBuf的前512的位置即可。调试时需要通过2个micro USB分别接入CN1和CN14,CN1用来调试,CN14用来和电脑连接实现RAM模拟U盘的功能。如下图示:3.    总结本文详细介绍了如何使用STM32CubeMX新建一个USB Device MSC工程,同时,给出了如何提高MSI的精度,使得不需要额外高速晶振即可实现USB Device的操作。还实现了通过MCU内部的RAM模拟出一个U盘,如果把512字节的分区结构字符串事先存入,那么就可以不用每次提示格式化。后续通过该工程的延续,可以实现U盘升级固件的功能。该U盘升级固件不同于mbed方式的U盘固件升级,本方案不需要额外的调试器即可实现。4.    参考资料.【NUCLEO-L496ZG评测】STM32CubeMX+无晶振高精度USB2.0 FS OTG详细步骤https://www.stmcu.org.cn/module/forum/thread-611658-1-1.html.【NUCLEO-L496ZG评测】ST-LINK驱动+STM32CubeMX+MDK-ARM开发环境搭建https://www.stmcu.org.cn/module/forum/thread-611614-1-1.html


示例程序仅供参考!

feixiang20 发表于 2017-5-26 10:08:33


cougar444888 发表于 2018-6-23 09:13:25

谢谢,学习

g2004-148848 发表于 2018-8-17 00:01:24

楼主辛苦谢谢分享

jiaolingqi 发表于 2019-6-30 21:02:58

:D进来学习了

cqupt1950 发表于 2019-8-29 16:45:13

谢谢楼主,学习了

wangertan 发表于 2020-11-25 15:37:38

三年后,一个小白失败了:@

wangertan 发表于 2020-11-26 15:43:02

jiaolingqi 发表于 2019-6-30 21:02
进来学习了

哥们实现了吗
页: [1]
查看完整版本: 【NUCLEO-L496ZG评测】STM32CubeMX+内部RAM模拟U盘 USB DEVICE MSC的实现