精华内容
下载资源
问答
  • Upgrade_V15.728.0.133.exe用于升级博惟芯片的U盘固件。使用前需要点击附加档案路径来添加固件路径。可恢复原始容量,由于功能上比较单一,不能量产启动盘等功能,不能修复U盘,只能升级U盘的目的。使用后如果无法...
  • u盘固件 朗科

    2013-06-28 18:39:55
    u盘固件,适合优盘固件损坏,修复优盘无法识别 或者空间
  • 我的小U盘固件

    2013-07-19 19:49:09
    U盘固件不错UT165V1.65V1.65.17.0.exe
  • U盘固件程序設計論文

    2012-07-12 14:06:59
    文章為湖南某大學某同學的畢業論文,中間介紹到USB的枚舉,個人覺得蠻好的,與大家分享一下!
  • stm32f芯片的u盘固件

    2012-03-27 14:57:58
    使用stm32f103编写的u盘固件程序
  • 自己做的小U盘,采用ATMEGA16 + CH375 + AT24C256,包括CH375的USB协议处理部分、海量存储协议处理部分以及EEPROM读写部分。程序注释非常详尽,非常适合初学者学习使用。程序是一个Avrstudio工程,使用的是GCC编译器...
  • stm32模拟U盘更新固件,bootload大小为11k,带app固件加密检查,配套PC端加密软件。完全源码共享,请支持山木智能
  • U盘固件开发成为过去

    千次阅读 2008-12-25 10:08:00
    当你准备开发U盘固件时,是否心里面仍然不踏实,让这些成为过去吧。 今年年初的时候,在驱动开发上发贴《在ARM7上使用D12开发U盘的详尽技术报告》(用书名号中的字符查找,可以找到)。其中详尽地介绍了我在ARM7...
    当你准备开发U盘的固件时,是否心里面仍然不踏实,让这些成为过去吧。 
    

     

    今年年初的时候,在驱动开发上发贴《在ARM7上使用D12开发U盘的详尽技术报告》(用书名号中的字符查找,可以找到)。其中详尽地介绍了我在ARM7上用D12开发U盘的过程,以及所涉及到的方方面面的知识。得到了一些朋友的肯定和鼓励。从中我也体会到了帮助别人的快乐。

     

    后来忙于别的,不经常上驱动了,但偶尔看一下仍然有许多人遇到U盘开发中的各种各样的问题,心里觉得十分不快。因为看到还有许多人仍然在为已经不存在什么问题的内容所折磨,看到我们的技术开发者仍然处于一种单干的状态,技术交流的模式和通道仍然不畅......别人做过的工作,我们完全可以用一种合理的方式拿过来为已所用,而把精力放在更多未知的问题上的。

     

    后来再做U盘文件系统(即在固件中创建文件,在PC上可以读取)、USB Host(可以读写U盘)的过程中,也碰到过一些问题,在向别人征询时,有一些朋友很爽快,愿意交换彼此的源码,有一些网友则是有所保留,可能每个人都忙,别人也没有时间解答所有问题。感觉就是得到的帮助往往是模糊的,往往还隔层纸

     

    在驱动上发贴,总会被淹没,因此,我有一个想法,成立一个邮件组,正在做U盘碰到问题,或是准备做U盘的朋友,请给我发邮件。frank_wang@263.net,主题注明“U盘开发”字样,我会将这些邮件收集到一个邮件组中,以后大家有什么问题,我可以抄送到所有人的邮件中,大家回信的时候,也可以回复全部,让大家共享信息。并且,我们一段时间将问题整理一次,放到驱动开发网上,作为大家的参考。我也可以考虑把Bulk Only和SCSI命令集响应部分的源码以合理的方式提供给大家,并乐意解答其中的问题。

     

    总之,我的愿望是,所有中国人,想做U盘的,让这个都不再是问题,让我们把精力放在其他更多更重要的事情上,让我们的整体水平更上层楼。我愿意为我这个愿望做些什么。同时,我也愿意跟大家交流我曾经做过的一些项目内容,比如文件系统读写,Usb-Host控制U盘等等。

     

    USB固件编程之一:固件编程的工作内容

    USB固件编程可以用以下语句来精练地进行描述:

     

    Device的固件编程,要搞定的是那几个端点。端点多少和配置情况受所用的Device芯片决定,具体可以看芯片资料。芯片一般提供一个中断信号,与单片机接口时,只要端点接受到数据,或发送数据成功后,便后产生中断,在固件里面,只要对些中断进行响应即可。

     

    当Device接收到数据时,对这些数据进行分析处理(端点0遵守标准的数据格式,其他端点受端点类型的不同,有不同的数据格式),一般来说,这些数据是主机对设备发出的请求,设备只要响应主机的这些请求即可。Device芯片发送完数据后也会产生中断,这个中断信号告诉与之接口的单片机,可以继续发送后续的数据。

     

    USB固件,好比一个有“妻管炎”的男人,而主机,则好是一个女管家。一般来说,主机让干啥就干啥,所以,USB固件程序的结构一般是基于中断处理的。平时,主程序做完必要的初始化工作后,就什么事也不做了,等待USB中断的产生,中断产生后,根据中断状态对相应的端点读取数据,或是向相应的端点发送数据。这一点是USB通讯协议的主-从模式先天决定的。但让人不可思议的是,这还有点象是母系氏族时期,因为,一个USB总线上,只能有一个主机,可以有多个设备,整个USB总线上通讯的协议和处理,发起与中止,基本上是主机控制的。因此,固件编程中,只要满足了主机的要求,就万事大吉了,可以确保自己的氏族中的应有地位。

     

    U盘固件编程之二:固件编程的几个主要部分

     

    在整个U盘固件中,程序从功能模块上分成两个部分:USB协议的处理和对Flash的读写.

     

    USB协议的处理又分成两个方面.

    一是端点0的配置过程.所有USB设备在插入USB端口时,主机都通过地址0与设备的端口0进行通讯。在这个过程中,主机发出一系列得到描述符的请求,通过这些请求,主机得到所有感兴趣的设备的描述符,从而知道设备的情况,然后通过Set Address为设备设置一个唯一的地址,配置过程完成以后,主机就通过为设备所设定的地址与设备通讯,而不再是使用默认地址0.配置地址后,可能还要获取一次描述符,然后设置配置(Set Configuration),之后便完成了对新插入USB总线的设备的配置过程。

     

    二是其他端点的数据通讯过程。在配置阶段中,主机已经知道了设备的端点的使用情况,以后,便可以通过这些端点来进行特定传输方式的通讯了。对于U盘来说,有两种传输方式,BULK ONLY和CBI方式,一般使用Bulk Only较多。这种传输方式要使用特定的Bulk端点,然后还要为其选择一种命令集。比如UFI或SCSI,因为Bulk端点的数据没有特定的数据格式,因此,需要使用某种命令集,来约定所传数据的格式。对于U盘固件编程来讲,就是要处理BULK端点的各种数据通讯。

     

    除了对各个相关的端点的USB协议的处理,剩下的就是FLASH的读写问题。这里存在两个层面的问题。

    一是解决Flash读写的问题,就是说你使用的Flash,先要实现成功的读写和擦除,这部分内容,是比较成熟的,一般都使用三星公司出的K9FXX08系列的,有16M(2808),32M(5608),64M(1208),138M(1G08)。它们的封装一致,只需要软件编程中稍做修改,便可以进行适应于另一种容量的存储器。

     

    第二个层面的问题,就是在U盘通讯过程中的问题了。NAND型的Flash有个特点,不可随机存取,擦除操作一次对16K的内容进行。所以,在U盘响应过程中,不可避免要对数据进行缓存。如果你的U盘方案中有较宽裕的RAM(超过16K),这个问题变得简单,只需要开一个16K的数组,把数据存到这16K中,最后再写入Flash即可。否则,在缓冲上面是要花一些功夫的。最基本的思路是用Flash的另外一个Block做缓冲空间。

     

    但这种方式会引发下列问题:1、速度;2、Flash的那个用来做缓存的块将比别的块使用频度大幅上升,磨损最严重,最先坏,这影响整个Flash的寿命。在实际处理中,引入了一系列的折中方案,比如,对Write命令所写的Block号进行判断,如果是整个的数据Block,则直接擦除原有内容,将数据写入。再如,对于非整个Block的数据进行缓冲,而对于整个Block的读写,不缓冲直接写入。再就是对于前面文件分配表、目录项所在的Block进行缓冲,等等。经过这些处理,可以尽可能地提高Write的速度。

     

    U盘固件编程之三:合理的USB通讯调试方法和思路是成功的关键

     

    在介绍更多细节内容之前,我不得不谈谈我对USB调试方法的理解。

     

    USB通讯过程是一个动态的过程,是不太好使用硬件仿真器来设断点调试的,因为每一次USB的传输过程,都有时效要求,等待时间过长,通讯过程也就中止了。但也不排除可以巧妙地使用断点仿真的方法进行调试。但个人认为,使用串口辅助编程过程,却是一种经济有效的方法。

     

    所谓用串口辅助调试过程,也就是在固件代码中加入类似于Printf的语句,向串口输出一些信息。这些信息可以是几个字符(如A、B、C),或是某个变量或寄存器的值。程序运行到此处时,便会输出这些信息,借此,便可以知道:1、程序是否运行到此处;2、运行到此处时相应变量或寄存器值。这不就是硬件仿真调试的功能么?

     

    如果想使用这种方式来调试,在硬件上必须增加一个RS232串口电平转换芯片,而且所使用的MCU得要有串口,并且,一般要自己编写Printf函数的实现方式。这个翻翻串口控制方面的书籍,很容易就可以搞定。

     

    串口调试的方法,还可以推广到其他的单片机应用中,在简单系统中,它基本可以替代掉硬件仿真器,降低开发者的门槛和投资。

     

    在USB通讯过程中,有两个阶段,一是通过端点0完成对设备的配置,在此阶段,把从USB端点得到的数据输出到串口,就对通讯所处的阶段一目了然了。一旦完成配置阶段,Bus Hound便可以粉墨登场了,因为此时,Bus Hound中已经可以看到设备了,看到设备后,便可以选择设备,对主机与此设备间的通讯数据进行分析和监视。

     

    串口调试和Bus Hound这两种手段配合使用,可以使USB通讯过程的调试更加容易。比如,刚开始时,端点0的数据量本来就少,因此,使用串口调试比较方便。而对于Bulk端点的数据传送过程,再使用串口就不太方便了,因为数据量大,串口输出的数据太多,延时会比较严重,影响USB通讯过程,所以改用BUS HOUND来监视USB总线上的数据。这个时候很有趣的一件事情是,Bus Hound在PC机上,而串口实际上在单片机端。所以,利用这两种手段,里应外合,有助于我们确定一方发时另一方收的数据是否正确。比如,单片机上发出的一组数,将其输出到串口,然后看看Bus Hound上是否收到的是这些数,如果正确,则说明硬件通讯过程没有问题,如果不正确,则说明通讯的某一方有问题,进一步可以定位此问题,排除之。

     

    正确的调试思路,将使调试过程事半功倍。

     

    比如,在调试端点0 的配置过程时,可以先用Switch...Case语句建立对于端点0的数据的分支响应,对照标准请求的数据格式,可以得到什么情况下是Get Device Descriptor,什么时候是Get Configuration Descriptor,每个分支处理时对应一个函数,在这个函数里向串口标志信息。这个工作完成以后,便一个一个地来处理请求,处理完一个后,主机会自动进入下一个阶段,这时,通过串口可以看到相应的状态,按步就班地一个一个处理余下的请求,即可完成端点0的设备配置过程的固件程序的编写。

     

    对于Bulk端点也是一样,先建立程序框架,然后再一个一个地处理请求。这种自上而下,逐步求精的思路并不稀奇,在USB调试过程中十分受用。最忌一上来就处理请求,不讲求结构,不讲求代码的条理性,最后可能弄得自己都是一头雾水。

     

    U盘固件编程之四:玩转你的端点

     

    接上面hewx,我来谈谈端点的问题。

     

    前面提到过,端点是由USB设备端的接口芯片决定的。你选择了什么样的芯片,那么端点的配置情况属性就已经决定了,你只能使用将就这些特定的情况。这些端点的配置,具体要参考你所使用的接口芯片的芯片资料,比如说,端点0当然都为控制端点,其MaxPacketSize可能为8,16,32,64;端点1可能是Bulk-In端点,2是Bulk-Out端点,其字长也有可能是8,16,32,64,但一般是64。其他端点可能有同步端点,或者同一端点既可被配置成同步传输方式,也可以工作在Bulk传输方式下,等等,不一而足。

     

    USB协议精妙之处就在于枚举过程。主机最初发过来的包,一定是8个字符长的。所以,你的端点的MaxPacketSize至少必须是8,能满足与主机之间最基本的通讯过程。对于主机的第一个请求Get Device Descriptor,你也只用回复8个字符就OK了,因为主机在第一次只对这8个字符感兴趣,在后面逐渐的获取描述符的过程中,主机逐渐得到设备使用那些端点,每个端点的最大字长(这些内容在Endpoint Descriptor中,通过Configuration Descriptor提供)是多少,等等,总之,通过枚举,主机便知道你的端点的情况了,以后就会用这些端点来与设备进行通讯。

     

    对于Hewx的问题,我想是你在Endpoint Descriptor中没有正确进行端点的设置,因为,如果进行了正确的端点配置,主机是会自动通过Bulk端点来发Inquiry命令的,而不会从你说的Endpoint1(16B)来发送这一信息。而且,主机会自动对要发送的信息进行分割,每次以不高于相应端点的MaxPacketSize长度来发送。

     

    除了描述符中要给出正确的端点描述符的描述,有些时候在芯片中也需要设备相应的控制位,在决定你要使用哪些及如何使用这些端点,这个也得根据具体的芯片资料来设置。

     

    U盘固件编程之四:玩转你的端点(增补)

     

    对于某种设备来说,需要使用到的端点是固定的。比如说,Mass Storage设备吧,就只需要用到一个Bulk-In端点和一个Bulk-Out端点。而不需要几个此类端点。至于到底需要几个端点,完全需要根据有关协议中的说明进行,描述符也据此进行提供,而不是没有根据地在描述符中提供许多端点。

     

    至于哪些端点可以做何种方式来使用,这也要看接口芯片的资料,比如,很可能,有的端点只能用作同步方式,那你就不要勉强将其用作批量方式,控制端点就只能用作控制传输方式,就不能为同步方式......搞清楚这个概念,在固件编程中才好正确地提供描述符。

     

    整个U盘所涉及的内容有如下一些:

    控制传输和批量传输的传输过程

    <SPAN lang=EN-US style="FONT-SIZE

    展开全文
  • U盘固件开发指南

    千次阅读 2007-07-09 23:46:00
    U盘固件开发成为过去 当你准备开发U盘的固件时,是否心里面仍然不踏实,让这些成为过去吧。 今年年初的时候,在驱动开发上发贴《在ARM7上使用D12开发U盘的详尽技术报告》(用书名号中的字符查找,可以找到)。其中...
    让U盘固件开发成为过去

     

    当你准备开发U盘的固件时,是否心里面仍然不踏实,让这些成为过去吧。

    今年年初的时候,在驱动开发上发贴《在ARM7上使用D12开发U盘的详尽技术报告》(用书名号中的字符查找,可以找到)。其中详尽地介绍了我在ARM7 上用D12开发U盘的过程,以及所涉及到的方方面面的知识。得到了一些朋友的肯定和鼓励。从中我也体会到了帮助别人的快乐。

    后来忙于别的,不经常上驱动了,但偶尔看一下仍然有许多人遇到U盘开发中的各种各样的问题,心里觉得十分不快。因为看到还有许多人仍然在为已经不存在什么问题的内容所折磨,看到我们的技术开发者仍然处于一种单干的状态,技术交流的模式和通道仍然不畅......别人做过的工作,我们完全可以用一种合理的方式拿过来为已所用,而把精力放在更多未知的问题上的。

    后来再做U盘文件系统(即在固件中创建文件,在PC上可以读取)、USB&nbspHost(可以读写U盘)的过程中,也碰到过一些问题,在向别人征询时,有一些朋友很爽快,愿意交换彼此的源码,有一些网友则是有所保留,可能每个人都忙,别人也没有时间解答所有问题。感觉就是得到的帮助往往是模糊的,往往还隔层纸

    在驱动上发贴,总会被淹没,因此,我有一个想法,成立一个邮件组,正在做U盘碰到问题,或是准备做U盘的朋友,请给我发邮件。 frank_wang@263.net,主题注明“U盘开发”字样,我会将这些邮件收集到一个邮件组中,以后大家有什么问题,我可以抄送到所有人的邮件中,大家回信的时候,也可以回复全部,让大家共享信息。并且,我们一段时间将问题整理一次,放到驱动开发网上,作为大家的参考。我也可以考虑把 Bulk&nbspOnly和SCSI命令集响应部分的源码以合理的方式提供给大家,并乐意解答其中的问题。

    总之,我的愿望是,所有中国人,想做U盘的,让这个都不再是问题,让我们把精力放在其他更多更重要的事情上,让我们的整体水平更上层楼。我愿意为我这个愿望做些什么。同时,我也愿意跟大家交流我曾经做过的一些项目内容,比如文件系统读写,Usb-Host控制U盘等等。

    我真切地感受到初学一个东西时的感受。其实这些东西并不难,只要有一些时间,都可以搞出来,但我们有必要每个人都去花相当可观的时间么!没有必要。

    我们有时需要挑战自己,挑战我们自己的观念和心态。我希望自己可以做一个尝试。

    USB固件编程之一:固件编程的工作内容
    USB固件编程可以用以下语句来精练地进行描述:

    Device的固件编程,要搞定的是那几个端点。端点多少和配置情况受所用的Device芯片决定,具体可以看芯片资料。芯片一般提供一个中断信号,与单片机接口时,只要端点接受到数据,或发送数据成功后,便后产生中断,在固件里面,只要对些中断进行响应即可。

    当Device接收到数据时,对这些数据进行分析处理(端点0遵守标准的数据格式,其他端点受端点类型的不同,有不同的数据格式),一般来说,这些数据是主机对设备发出的请求,设备只要响应主机的这些请求即可。Device芯片发送完数据后也会产生中断,这个中断信号告诉与之接口的单片机,可以继续发送后续的数据。

    USB固件,好比一个有“妻管炎”的男人,而主机,则好是一个女管家。一般来说,主机让干啥就干啥,所以,USB固件程序的结构一般是基于中断处理的。平时,主程序做完必要的初始化工作后,就什么事也不做了,等待USB中断的产生,中断产生后,根据中断状态对相应的端点读取数据,或是向相应的端点发送数据。这一点是USB通讯协议的主-从模式先天决定的。但让人不可思议的是,这还有点象是母系氏族时期,因为,一个USB总线上,只能有一个主机,可以有多个设备,整个USB总线上通讯的协议和处理,发起与中止,基本上是主机控制的。因此,固件编程中,只要满足了主机的要求,就万事大吉了,可以确保自己的氏族中的应有地位。

    U盘固件编程之二:固件编程的几个主要部分

    在整个U盘固件中,程序从功能模块上分成两个部分:USB协议的处理和对Flash的读写.

    USB协议的处理又分成两个方面.
    一是端点0的配置过程.所有USB设备在插入USB端口时,主机都通过地址0与设备的端口0进行通讯。在这个过程中,主机发出一系列得到描述符的请求,通过这些请求,主机得到所有感兴趣的设备的描述符,从而知道设备的情况,然后通过Set&nbspAddress为设备设置一个唯一的地址,配置过程完成以后,主机就通过为设备所设定的地址与设备通讯,而不再是使用默认地址0.配置地址后,可能还要获取一次描述符,然后设置配置(Set& nbspConfiguration),之后便完成了对新插入USB总线的设备的配置过程。

    二是其他端点的数据通讯过程。在配置阶段中,主机已经知道了设备的端点的使用情况,以后,便可以通过这些端点来进行特定传输方式的通讯了。对于U盘来说,有两种传输方式,BULK&nbspONLY和CBI方式,一般使用Bulk&nbspOnly较多。这种传输方式要使用特定的Bulk 端点,然后还要为其选择一种命令集。比如UFI或SCSI,因为Bulk端点的数据没有特定的数据格式,因此,需要使用某种命令集,来约定所传数据的格式。对于U盘固件编程来讲,就是要处理BULK端点的各种数据通讯。

    除了对各个相关的端点的USB协议的处理,剩下的就是FLASH的读写问题。这里存在两个层面的问题。
    一是解决Flash读写的问题,就是说你使用的Flash,先要实现成功的读写和擦除,这部分内容,是比较成熟的,一般都使用三星公司出的K9FXX08 系列的,有16M(2808),32M(5608),64M(1208),138M(1G08)。它们的封装一致,只需要软件编程中稍做修改,便可以进行适应于另一种容量的存储器。

    第二个层面的问题,就是在U盘通讯过程中的问题了。NAND型的Flash有个特点,不可随机存取,擦除操作一次对16K的内容进行。所以,在U盘响应过程中,不可避免要对数据进行缓存。如果你的U盘方案中有较宽裕的RAM(超过16K),这个问题变得简单,只需要开一个16K的数组,把数据存到这16K 中,最后再写入Flash即可。否则,在缓冲上面是要花一些功夫的。最基本的思路是用Flash的另外一个Block做缓冲空间。

    但这种方式会引发下列问题:1、速度;2、Flash的那个用来做缓存的块将比别的块使用频度大幅上升,磨损最严重,最先坏,这影响整个Flash的寿命。在实际处理中,引入了一系列的折中方案,比如,对Write命令所写的Block号进行判断,如果是整个的数据Block,则直接擦除原有内容,将数据写入。再如,对于非整个Block的数据进行缓冲,而对于整个Block的读写,不缓冲直接写入。再就是对于前面文件分配表、目录项所在的Block进行缓冲,等等。经过这些处理,可以尽可能地提高Write的速度。

    U盘固件编程之三:合理的USB通讯调试方法和思路是成功的关键

    在介绍更多细节内容之前,我不得不谈谈我对USB调试方法的理解。

    USB通讯过程是一个动态的过程,是不太好使用硬件仿真器来设断点调试的,因为每一次USB的传输过程,都有时效要求,等待时间过长,通讯过程也就中止了。但也不排除可以巧妙地使用断点仿真的方法进行调试。但个人认为,使用串口辅助编程过程,却是一种经济有效的方法。

    所谓用串口辅助调试过程,也就是在固件代码中加入类似于Printf的语句,向串口输出一些信息。这些信息可以是几个字符(如A、B、C),或是某个变量或寄存器的值。程序运行到此处时,便会输出这些信息,借此,便可以知道:1、程序是否运行到此处;2、运行到此处时相应变量或寄存器值。这不就是硬件仿真调试的功能么?

    如果想使用这种方式来调试,在硬件上必须增加一个RS232串口电平转换芯片,而且所使用的MCU得要有串口,并且,一般要自己编写Printf函数的实现方式。这个翻翻串口控制方面的书籍,很容易就可以搞定。

    串口调试的方法,还可以推广到其他的单片机应用中,在简单系统中,它基本可以替代掉硬件仿真器,降低开发者的门槛和投资。

    在USB通讯过程中,有两个阶段,一是通过端点0完成对设备的配置,在此阶段,把从USB端点得到的数据输出到串口,就对通讯所处的阶段一目了然了。一旦完成配置阶段,Bus&nbspHound便可以粉墨登场了,因为此时,Bus&nbspHound中已经可以看到设备了,看到设备后,便可以选择设备,对主机与此设备间的通讯数据进行分析和监视。

    串口调试和Bus&nbspHound这两种手段配合使用,可以使USB通讯过程的调试更加容易。比如,刚开始时,端点0的数据量本来就少,因此,使用串口调试比较方便。而对于Bulk端点的数据传送过程,再使用串口就不太方便了,因为数据量大,串口输出的数据太多,延时会比较严重,影响USB 通讯过程,所以改用BUS&nbspHOUND来监视USB总线上的数据。这个时候很有趣的一件事情是,Bus&nbspHound在 PC机上,而串口实际上在单片机端。所以,利用这两种手段,里应外合,有助于我们确定一方发时另一方收的数据是否正确。比如,单片机上发出的一组数,将其输出到串口,然后看看Bus&nbspHound上是否收到的是这些数,如果正确,则说明硬件通讯过程没有问题,如果不正确,则说明通讯的某一方有问题,进一步可以定位此问题,排除之。

    正确的调试思路,将使调试过程事半功倍。

    比如,在调试端点0 的配置过程时,可以先用Switch...Case语句建立对于端点0的数据的分支响应,对照标准请求的数据格式,可以得到什么情况下是Get&nbspDevice&nbspDescriptor,什么时候是Get& nbspConfiguration&nbspDescriptor,每个分支处理时对应一个函数,在这个函数里向串口标志信息。这个工作完成以后,便一个一个地来处理请求,处理完一个后,主机会自动进入下一个阶段,这时,通过串口可以看到相应的状态,按步就班地一个一个处理余下的请求,即可完成端点0的设备配置过程的固件程序的编写。

    对于Bulk端点也是一样,先建立程序框架,然后再一个一个地处理请求。这种自上而下,逐步求精的思路并不稀奇,在USB调试过程中十分受用。最忌一上来就处理请求,不讲求结构,不讲求代码的条理性,最后可能弄得自己都是一头雾水。

    补充建议:在能够使用BusHound之前,使用USBCheck工具,可以逐条、逐项、随意反复地调试端点0的各项数据和设置。感觉很方便。

    U盘固件编程之四:玩转你的端点

    接上面hewx,我来谈谈端点的问题。

    前面提到过,端点是由USB设备端的接口芯片决定的。你选择了什么样的芯片,那么端点的配置情况属性就已经决定了,你只能使用将就这些特定的情况。这些端点的配置,具体要参考你所使用的接口芯片的芯片资料,比如说,端点0当然都为控制端点,其MaxPacketSize可能为8,16,32,64;端点1 可能是Bulk-In端点,2是Bulk-Out端点,其字长也有可能是8,16,32,64,但一般是64。其他端点可能有同步端点,或者同一端点既可被配置成同步传输方式,也可以工作在Bulk传输方式下,等等,不一而足。

    USB协议精妙之处就在于枚举过程。主机最初发过来的包,一定是8个字符长的。所以,你的端点的MaxPacketSize至少必须是8,能满足与主机之间最基本的通讯过程。对于主机的第一个请求Get&nbspDevice&nbspDescriptor,你也只用回复8个字符就OK 了,因为主机在第一次只对这8个字符感兴趣,在后面逐渐的获取描述符的过程中,主机逐渐得到设备使用那些端点,每个端点的最大字长(这些内容在 Endpoint&nbspDescriptor中,通过Configuration&nbspDescriptor提供)是多少,等等,总之,通过枚举,主机便知道你的端点的情况了,以后就会用这些端点来与设备进行通讯。

    对于Hewx的问题,我想是你在Endpoint&nbspDescriptor中没有正确进行端点的设置,因为,如果进行了正确的端点配置,主机是会自动通过Bulk端点来发Inquiry命令的,而不会从你说的Endpoint1(16B)来发送这一信息。而且,主机会自动对要发送的信息进行分割,每次以不高于相应端点的MaxPacketSize长度来发送。

    除了描述符中要给出正确的端点描述符的描述,有些时候在芯片中也需要设备相应的控制位,在决定你要使用哪些及如何使用这些端点,这个也得根据具体的芯片资料来设置。

    U盘固件编程之四:玩转你的端点(增补)

    对于某种设备来说,需要使用到的端点是固定的。比如说,Mass&nbspStorage设备吧,就只需要用到一个Bulk-In端点和一个 Bulk-Out端点。而不需要几个此类端点。至于到底需要几个端点,完全需要根据有关协议中的说明进行,描述符也据此进行提供,而不是没有根据地在描述符中提供许多端点。

    至于哪些端点可以做何种方式来使用,这也要看接口芯片的资料,比如,很可能,有的端点只能用作同步方式,那你就不要勉强将其用作批量方式,控制端点就只能用作控制传输方式,就不能为同步方式......搞清楚这个概念,在固件编程中才好正确地提供描述符。

    整个U盘所涉及的内容有如下一些:
    控制传输和批量传输的传输过程
    Read和Write之前的命令响应
    文件系统
    Read命令和WRite命令的响应
    容量与格式化
    速度问题
    其他问题

    先不忙说文件系统吧。我的思路是,接下来讲讲在做U盘的过程中常见的两种传输方式:控制传输和批量传输的事务处理过程。因为我们经常在处理控制端点的传输或Bulk端点的传输时,有些朋友常碰到“主机没有反应了”这样的问题,知道这两种传输方式的几个阶段,可以对传输过程更加了解,知道主机为什么会没有反应,是因为固件中没有正确响应,还是因为别的因素。

    PPS文档,最后面有USB&nbspU盘的源码流程图!这下大家应该满意了吧,由于后面去西藏,直到八月底回来,所以后面暂时不方便上网了。

     
    展开全文
  • U盘内容出现乱码,而且无法读写,用这个工具进行格式化后,可行。如果有需要,可以试试,推荐使用。
  • 金士顿官方U盘专修工具,修复金士顿品牌的U盘,非常保险、安全。
  • U盘烧录工具Win32DiskImager,用于烧录U盘系统,U盘文件。小巧干净,无需安装,解压就能用。无广告无弹窗,绿色健康
  • 若量产失败或刷错固件,请以所附之固件与烧錄文件重刷,即可救回U盘具体方法:必要时应短接,让电脑重新认出U盘;而后以3.16重刷固件,再重新量产即可。.............................................................
  • 惠普 u盘 修复

    2018-12-10 21:43:09
    惠普 u盘 修复工具,用于修复惠普u盘的工具,写保护修复,亲测可用
  • 我收集的USB-MSC类资料,学习U盘固件开发的好资料(另需参考USB2.0规范)。 压缩包内容: MSC_BOT、UFI、SCSI等英文规范; 以及U盘固件开发、SCSI接口介绍等中文资料。
  • 夏科U盘量产工具.zip

    2020-07-25 15:59:15
    夏科U盘量产工具 32G 非常好的一款工具,可以拯救夏科U盘出现的问题,快速量产,成功率高
  • U盘坏了后找他们售后发给我的修复工具
  • 通过u盘升级stm32固件

    2020-09-22 16:24:40
    基于stm32和RT-thread操作系统,可以通过usb进行OTA固件升级,非常方便,具体的效果可以阅读我发布的博客(RT-thread应用讲解——U盘远程升级(OTA))。
  • STM32 HAL库 基于U盘模式升级固件 - IAP

    千次阅读 2021-01-29 16:41:47
    做电子产品,如果不支持固件升级,后期可能带来维护成分非常巨大,为了降低后期维护成本,引入固件升级功能是基本条件。网上这些资料一抓一大把,我这里直接说怎么使用,具体原理, 大家伙自行网上查找资料科普,...

    目录

    概述

    一、STM32CUBEMX配置

    二、编码

    1)bootloader工程

    2)  app工程


    概述

         做电子产品,如果不支持固件升级,后期可能带来维护成本非常巨大,为了降低后期维护成本,引入固件升级功能是基本条件。网上这些资料一抓一大把,我这里直接说怎么使用,具体原理,大家伙自行网上查找资料科普,本篇文章基本都是基于这位大佬的无私分享,链接,在此本人分享一种,将APP的bin文件复制到U盘里,进行固件升级方式。比起ST官网介绍的DFU模式还要便捷,无需第三方上位机,无需安装任何驱动,方可对产品固件升级。

    ST官网例程(AN4657-STM32Cube_IAP_using_UART)链接 

    同时,也可以在ST官网搜索栏中输入:“IAP”关键字搜索即可,如下所示。

    有两种方法:

    1)通过一个KEY触发是否跳转;

    2)通过检测USB拔插状态,来识别,跳转app或者是bootloader模式,当USB拔出时,重新上电,检测到3s时,会出现跳转到app

    固件升级需要分两部分:bootloader +  app 

    由上图可知,STM32 内置的 Flash 被分成了两个部分,分别用来保存 Bootloader 和 Application 程序,这里有两个有两个 FLASH 起始地址 0x8000000 和 0x8008000:

    为什么是 0x8000000 这个地址呢?而不是其他地址呢?这是由 M3 内核硬件上的设计就已经这么做了,人为设计好了,可以参考 M3 内核权威指南;

    0x8008000 这个地址则是由我们自己来设置,这个地址的范围必须在 0x8000000 和 0x8020000 之间,所以一般根据 Bootloader 程序的最终大小,在这范围之间取一个比较合理的值即可。如下图所示;

    注:本文使用的STM32F103CBT6,属于中等大小 Flash,128K = 0x20000,所以地址范围是 0x8000000~0x8020000;

    bootloader启动流程,查阅STM32官网资料得知,如下

    由上图可知:

    在bootloader工程中的main.c文件做了跳转地址校验:

    本文中 ApplicationAddress = 0x8000000;那么*(__IO uint32_t*)APP_ADDR)则是这个地址中所保存的值,由表格一可以知道,程序起始地址的第一个向量地址保存的栈顶的,因此,地址 0x800_0000 和 0x800_8000 中保存的值都是指向栈顶,如下图所示;

    栈是在 RAM 上分配,因此 RAM 的有效范围要做一个检测,栈顶地址和 0x2FFE0000 做与运算可以推算出,要校验的 RAM 范围是 0x2000_0000—0x2001_FFFF,所以 RAM 大小是 128K,官方 DEMO 默认使用 HD 高密度系列,所以是 128K,本文是 CBT6,20K 的 RAM,则需要改成 0x2FFFB000:

    计算方式:20K = 20*1024= 0x5000,0x2FFF_FFFF - (0x5000 - 1) = 0x2FFF_B000

    硬件平台:STM32F103CBT6

    编码平台IDE:keil V5.29

    一、STM32CUBEMX配置

    (注:只要看USB功能配置即可,LED只是方便观察,KEY是用于区分升级与不升级切换作用。)

    以上关于STM32CubeMX配置介绍完毕,接下来介绍编码步骤。

    二、编码

    1)bootloader工程

    把开源源码下载来,分别把fat32.c、fat32.h、btldr_config.h 文件添加到本工程即可。

    在此,只需要关注:main.c、usbd_storage_if.c文件

    usbd_storage_if.c文件

    /* USER CODE BEGIN INCLUDE */
    #include "fat32.h"
    /* USER CODE END INCLUDE */
    .
    .
    .
    .
    /* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
    static void _STORAGE_ReadBlocks(uint32_t *buf, uint64_t readAddr, uint32_t blockSize, uint32_t numOfBlocks)
    {
      uint32_t iBlock;
      uint8_t* buf8 = (uint8_t*)buf;
      
      for(iBlock=0; iBlock<numOfBlocks; iBlock++)
      {
        fat32_read(buf8, (uint32_t)readAddr);
        readAddr += blockSize;
        buf8 += blockSize;
      }
    }
    
    static void _STORAGE_WriteBlocks(uint32_t *buf, uint64_t writeAddr, uint32_t blockSize, uint32_t numOfBlocks)
    {
      uint32_t iBlock;
      uint8_t* buf8 = (uint8_t*)buf;
      
      for(iBlock=0; iBlock<numOfBlocks; iBlock++)
      {
        fat32_write(buf8, (uint32_t)writeAddr);
        writeAddr += blockSize;
        buf8 += blockSize;
      }
    }
    /* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
    
    .
    .
    .
    /**
      * @brief  .
      * @param  lun: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
      /* USER CODE BEGIN 6 */
    	_STORAGE_ReadBlocks((uint32_t *)buf, (uint64_t)(blk_addr * STORAGE_BLK_SIZ), STORAGE_BLK_SIZ, blk_len);
      return (USBD_OK);
      /* USER CODE END 6 */
    }
    
    /**
      * @brief  .
      * @param  lun: .
      * @retval USBD_OK if all operations are OK else USBD_FAIL
      */
    int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
      /* USER CODE BEGIN 7 */
    	_STORAGE_WriteBlocks((uint32_t *)buf, (uint64_t)(blk_addr * STORAGE_BLK_SIZ), STORAGE_BLK_SIZ, blk_len);
      return (USBD_OK);
      /* USER CODE END 7 */
    }
    

    这里补充一下,直接使用STM32CubeMx生成U盘模式,如果U盘里没有任何文件,接上PC端会提示,格式化该U盘,想解决这个问题,只需在U盘添加一下文件即可,按照上面代码所示,同时把代码的bin文件备份一份在U盘中。

    烧录bootloader程序后,需要一条杜邦线把PA0拉低,然后再使用USB数据线连接最小系统板,才能在PC中看到识别U盘。

    如下所示:

     

    main.c文件

    /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
      * All rights reserved.</center></h2>
      *
      * This software component is licensed by ST under Ultimate Liberty license
      * SLA0044, the "License"; You may not use this file except in compliance with
      * the License. You may obtain a copy of the License at:
      *                             www.st.com/SLA0044
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    #include "usart.h"
    #include "usb_device.h"
    #include "gpio.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "btldr_config.h"
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    extern USBD_HandleTypeDef hUsbDeviceFS;
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    
    /* USER CODE BEGIN PV */
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    int fputc(int ch, FILE* FILE)
    {
        HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
        return ch;
    }
    
    bool is_appcode_exist()
    {
      uint32_t *mem = (uint32_t*)APP_ADDR;
      
      if ((mem[0] == 0x00000000 || mem[0] == 0xFFFFFFFF) && \
          (mem[1] == 0x00000000 || mem[1] == 0xFFFFFFFF) && \
          (mem[2] == 0x00000000 || mem[2] == 0xFFFFFFFF) && \
          (mem[3] == 0x00000000 || mem[3] == 0xFFFFFFFF))
      {
        return false;
      }
      else
      {
        return true;
      }
    }
    
    
    static void JumpToApp(void)
    {
        typedef  void (*pFunction)(void);
        static pFunction JumpToApplication;
        static uint32_t JumpAddress;
    
        /* Test if user code is programmed starting from USBD_DFU_APP_DEFAULT_ADD * address */
        if (((*(__IO uint32_t *) APP_ADDR) & 0x2FFE0000) == 0x20000000)
        {
            /* Jump to user application */
            JumpAddress = *(__IO uint32_t *) (APP_ADDR + 4u);
    			  //HAL_DeInit();
            JumpToApplication = (pFunction) JumpAddress;
    
            /* Initialize user application's Stack Pointer */
            __set_MSP((*(__IO uint32_t *) APP_ADDR));
            JumpToApplication();
        }
    }
    
    bool is_button_down()
    {
      return (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET);
    }
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
      /* USER CODE BEGIN 1 */
    	uint8_t usb_current_state = 0;
    	uint8_t usb_input_state = 0;
        uint32_t overTime = 0;
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
    
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_USART1_UART_Init();
      MX_USB_DEVICE_Init();
      /* USER CODE BEGIN 2 */
    	printf("heihei !!!\r\n");
    
    #if 0
    	if(!is_appcode_exist() || is_button_down())
      {
        MX_USB_DEVICE_Init();		//注意,这里初始化,上面就要注释掉才行。
    		printf("Jump failed, USB firmware upgrade mode!!!\r\n");
        while(1)
        {
        }
      }
      else
      {
    		printf("Jump succeed!!!\r\n");
        JumpToApp();
      }
    #endif
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    #if	1		
    		if(hUsbDeviceFS.dev_state != usb_current_state){
    			if(hUsbDeviceFS.dev_state== USBD_STATE_CONFIGURED){
    				usb_input_state = 1;
    				printf("usb is connected!!!\r\n");
    			}else if(hUsbDeviceFS.dev_state== USBD_STATE_SUSPENDED){
    				printf("usb Disconnect!!!\r\n");
    			}else{
    				//
    			}
    			usb_current_state = hUsbDeviceFS.dev_state;
    	  }
     
    	  // 
    	  if(overTime++ > 3000){
    			// 
    			if(usb_input_state == 0 && (is_appcode_exist() == 1)){
    				printf("---system run -app\r\n");
    				JumpToApp();
    				printf("---system run -app error!!!!\r\n");
    			}
    	  }
    	  HAL_Delay(1000);
          HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    #endif			
    
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }
    
    /**
      * @brief System Clock Configuration
      * @retval None
      */
    void SystemClock_Config(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
      RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    
      /** Initializes the RCC Oscillators according to the specified parameters
      * in the RCC_OscInitTypeDef structure.
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
      RCC_OscInitStruct.HSIState = RCC_HSI_ON;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
      RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
      RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
      {
        Error_Handler();
      }
      /** Initializes the CPU, AHB and APB buses clocks
      */
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
      {
        Error_Handler();
      }
      PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
      PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
      if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /* USER CODE BEGIN 4 */
    
    /* USER CODE END 4 */
    
    /**
      * @brief  This function is executed in case of error occurrence.
      * @retval None
      */
    void Error_Handler(void)
    {
      /* USER CODE BEGIN Error_Handler_Debug */
      /* User can add his own implementation to report the HAL error return state */
    
      /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef  USE_FULL_ASSERT
    /**
      * @brief  Reports the name of the source file and the source line number
      *         where the assert_param error has occurred.
      * @param  file: pointer to the source file name
      * @param  line: assert_param error line source number
      * @retval None
      */
    void assert_failed(uint8_t *file, uint32_t line)
    {
      /* USER CODE BEGIN 6 */
      /* User can add his own implementation to report the file name and line number,
         tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
      /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */
    
    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
    

    2)  app工程

    该工程STM32CubeMX配置基本跟BootLoder一样,只是使用了LED与串口功能。

    main.c文件

    /* USER CODE BEGIN Header */
    /**
      ******************************************************************************
      * @file           : main.c
      * @brief          : Main program body
      ******************************************************************************
      * @attention
      *
      * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
      * All rights reserved.</center></h2>
      *
      * This software component is licensed by ST under BSD 3-Clause license,
      * the "License"; You may not use this file except in compliance with the
      * License. You may obtain a copy of the License at:
      *                        opensource.org/licenses/BSD-3-Clause
      *
      ******************************************************************************
      */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    #include "usart.h"
    #include "gpio.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    
    /* USER CODE BEGIN PV */
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    int fputc(int ch, FILE* FILE)
    {
        HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
        return ch;
    }
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
      /* USER CODE BEGIN 1 */
    
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
    	SCB->VTOR = FLASH_BASE | 0x8000;
      __ASM("CPSIE I");//
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_USART1_UART_Init();
      /* USER CODE BEGIN 2 */
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    		printf("runing app!!! \r\n");
    		HAL_Delay(500);
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }
    
    /**
      * @brief System Clock Configuration
      * @retval None
      */
    void SystemClock_Config(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
      /** Initializes the RCC Oscillators according to the specified parameters
      * in the RCC_OscInitTypeDef structure.
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
      RCC_OscInitStruct.HSIState = RCC_HSI_ON;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
      RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
      RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
      {
        Error_Handler();
      }
      /** Initializes the CPU, AHB and APB buses clocks
      */
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /* USER CODE BEGIN 4 */
    
    /* USER CODE END 4 */
    
    /**
      * @brief  This function is executed in case of error occurrence.
      * @retval None
      */
    void Error_Handler(void)
    {
      /* USER CODE BEGIN Error_Handler_Debug */
      /* User can add his own implementation to report the HAL error return state */
    
      /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef  USE_FULL_ASSERT
    /**
      * @brief  Reports the name of the source file and the source line number
      *         where the assert_param error has occurred.
      * @param  file: pointer to the source file name
      * @param  line: assert_param error line source number
      * @retval None
      */
    void assert_failed(uint8_t *file, uint32_t line)
    {
      /* USER CODE BEGIN 6 */
      /* User can add his own implementation to report the file name and line number,
         tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
      /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */
    
    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
    

    需要生成.bin文件

    fromelf.exe --bin --output=.\out\@L.bin !L

    以上步骤,只需编译,无需使用ST-Link下载,生成.bin文件如下:

    烧录固件顺序,先烧录bootloader,再使用拷贝文件方式进行固件升级。操作如下:

    运行结果:

    该文章源码:链接

    参考文章:链接

    (注:csdn下载的源码需要更改以下地方)

    总结:在此做下笔录,方便后期参阅,同时也给嵌入式一些同仁们参考吧!加油!!!

    展开全文
  • STM32 IAP 固件升级设计/U盘升级固件

    千次阅读 2016-08-23 14:38:00
    源:STM32 IAP 固件升级设计/U盘升级固件 固件升级的基本思路是: 将stm32 的flash划分为两个区域:  1.Bootloader区:存放bootloader的代码,bootloader代码完成的主要功能就是,判断外部条件,如果需要更新固件...

    源:STM32 IAP 固件升级设计/U盘升级固件

    固件升级的基本思路是: 将stm32 的flash划分为两个区域:

              1.Bootloader区:存放bootloader的代码,bootloader代码完成的主要功能就是,判断外部条件,如果需要更新固件,则从指定位置(外接的U盘?板子上的外置存储器如 SD卡,NandFlash等)读取bin文件,然后写入到stm32 Flash的APP区,完成后跳转到APP区执行更新过的代码; 如果不需要更新,则直接跳转到APP区执行主程序代码。

              2.APP区:存放应用程序代码,就是我们产品的固件了。

     

    目做了两个升级方式,都是USB的:

              一个是USB host:开机进boot,boot检测是否有U盘插入,U盘中是否包含APP的bin文件,包含则更新并跳转到APP;           一个是USB device:在APP区,做了usb device的代码,将板上的nandflash作为U盘的存储器,通过USB线链接PC,则PC显示U盘,将APP的bin文件复制到U盘里,并设置一个标志文件,下次开机进boot会判断nandfalash里是否有需要更新的固件,如果有,则将nandflash里存放的APPbin文件写入stm32 flash的APP区,完成更新后跳转。

     

    bootloader代码要点:

     

    1. 需要包含USB Host和 nandflash以及  fatfs文件系统的驱动代码。(这部分是需要仔细研究做好的,就不多说了)

     

    2.关于Bootloader区: 我使用stm32f429,bootlaoder代码编译下来有50K左右,所以使用flash 0x80000000  ~ 0x8000FFFF这块共64K的区域,注意Bootloader代码一定要从 flash的起始地址0x80000000开始,这样一开机就首先运行boot程序。

    具体在keil 中的设置是   target中设置好flash的起始地址和size; debug中settings,flash选择1M的(我的429是1Mflash)然后在下面的开始和结束地址中输入正确地址;

     

    3.关于APP区: 使用剩下的0x80010000~0x800FFFFF 区域,keil具体设置和2一样。

     

    4.关于读取并写入bin文件到flash:  如上面所说,这个比较灵活,可以从外部U盘中读取bin文件到 内存buf然后写入flash,也可以从板上已有的外设存储器读取bin文件到内存buf然后写入flash,具体代码可以参考官方固件库中的例子。

     

    5.关于跳转: 可以看到官方代码

     

    pFunction Jump_To_Application;

    uint32_t JumpAddress;

     

    JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);

    Jump_To_Application = (pFunction) JumpAddress;

    /* Initialize user application's Stack Pointer */

     __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);

    Jump_To_Application();

    具体分析可以看网上别人的详细解释,这里我遇到的问题是:经常跳转之后就直接死机,可能有以下几种情况:

    1. APP代码main函数中第一句必须要

     NVIC_SetVectorTable (NVIC_VectTab_FLASH, 0x10000);

    __enable_irq();

    将向量表偏移地址设置为我们的0x10000;

     

    2.关于中断,可能跳转之前,某些外设中断是开启的,跳转之后,中断产生了,但是APP代码中没有处理对应该中断的中断处理函数,所以就直接死机了;

    对应网上的一些方法是  跳转之前,关闭所有中断:  __disable_irq();

    在APP中偏移地址设置完毕后,再次开启所有中断:    __enable_irq();

    有些人发现跳入APP之后,很多中断都不响应了,可能就是跳转之前,关了中断但是APP中没有再次开启。

    我一开始这样用,每次从U盘更新完固件之后跳转就死机了,从nandflash跳转就不会有问题,参考了一些网上的资料,

    推测可能还是 __disable_irq()没有把USB中断关闭,或者关闭之后,USB的某个中断仍旧是置位的,APP中再次开启中断后,直接寻找USB中断服务程序,找不到就死机了。

    这里为了更加稳妥,我决定在跳转之前,将所有boot中用到的外设都关闭,但是只用了一句

    NVIC_DisableIRQ(OTG_FS_IRQn);

    之后,就一切OK了。

     

    但是建议大家在写boot的时候,跳转之前还是把所有用到的外设时钟关闭,中断也禁止。

    展开全文
  • U盘固件开发成为过去[文章纪念] 作者:frank_wang 当你准备开发U盘的固件时,是否心里面仍然不踏实,让这些成为过去吧。 今年年初的时候,在驱动开发上发贴《在ARM7上使用D12开发U盘的详尽技术报告》。其中详尽...
  • 一款适合于大多数U盘量产的一个工具,U盘不能被格式化了或者不能读写数据了,可以用量产工具进行量产,另外还有一个U盘芯片查看工具,可以查看到大多数U盘适合哪种量产工具。
  • U盘固件开发成为过去 2004年5月15日 作者:frank_wang  当你准备开发U盘的固件时,是否心里面仍然不踏实,让这些成为过去吧。今年年初的时候,在驱动开发上发贴《在ARM7上使用D12开发U盘的...
  • U盘量产失败(烧入固件失败、低格失败等)的终极解决方案--原理、操作方法、亲自实践的个人心得。U盘在刷写固件失败或者量产低格失败之后,量产工具就不能正常识别U盘,此时其它任何低格工具都是无效的,电脑也是...
  • 量产U盘用的.请注意是 金士顿 DT101 的U盘哦!不要找错了
  • * 此资源主要解决 打开dell官网 并且下载速度过慢问题,以方便大家 * 此Bios 操作时一定的看相关说明! * 如有疑惑,进入Dell官网查看...
  • 16G金士顿U盘(PS2251-50)主控的量产工具,本版本包含可刷的各个版本固件.可设置分区数量,制作U盘启动盘、低级格式化等。包含固件:BN50V313M- 8K.BIN BN50V3122KM-2@4k.BIN FW50FF01V30524M-2@4k.BIN FW50FF01V...
  • U盘专用修复工具,特别是东芝U盘

    热门讨论 2009-05-10 22:01:53
    U盘专用修复工具,特别是东芝U盘 ,我用了好多工具都没修复,用这个搞好了,所以拿出来共享了
  • NS1081芯片U盘量产工具MPTool 1.4.8带固件教程和电路图
  • 最近收拾房间,偶然找出一个坏的U盘。这个U盘是我16年买的,容量8G,忆捷牌。买回来一个月,仅使用了两次,就出现故障,没法用了。之后就一直仍在抽屉里。正好最近休假,就想着能不能让它起死回生。查了相关资料,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,312
精华内容 2,124
关键字:

u盘固件