历史上的今天
返回首页

历史上的今天

今天是:2024年11月02日(星期六)

2020年11月02日 | STM32, Flash DFU芯片,内部flash,代码升级

2020-11-02 来源:eefocus

这次要讲讲如何用USB升级单片机代码。以前曾经做过串口升级,网络升级,升级的基本原理都类似,只不过升级的工具不同罢了,串口升级当然是用串口了,网络升级用的是TCP/IP,USB升级当然用的是USB了。下面就来讲讲USB升级的实现。


修改部分部分都在USB_User组里:

STM32 Internal Flash DFU芯片内部flash代码升级 - ziye334 - ziye334的博客我们一个一个文件讲过来。


首先讲讲hw_config.c,这个文件跟之前工程差不多。由于演示的需要,我们在这个文件里初始化一个按键引脚,并定义按键读取函数,该按键决定代码是否升级,如果程序一开始,该按键按下,则进入升级模式,否则跳转到升级程序代码处:

/*******************************************************************************

* Function Name  : DFU_Button_Config.

* Description    : 配置DFU模式选择按键.

* Input          : None.

* Output         : None.

* Return         : None.

*******************************************************************************/

void DFU_Button_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DFU, ENABLE);


  /* 配置DFU按键*/

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

  GPIO_InitStructure.GPIO_Pin = DFU_ENTER_PIN;

  GPIO_Init(DFU_ENTER, &GPIO_InitStructure);

}


/*******************************************************************************

* Function Name  : DFU_Button_Read.

* Description    : 读取DFU按键是否按下

* Input          : None.

* Output         : None.

* Return         : 返回0:按键按下;1:按键没有按下

*******************************************************************************/

uint8_t DFU_Button_Read (void)

{

  return GPIO_ReadInputDataBit(DFU_ENTER, DFU_ENTER_PIN);

}


usb_desc.c这个文件自然要修改的,USB的功能属性等全在这里定义。首先必须关注下设备描述度符,这里有一点需要强调,就是厂商ID域的值必须为0483,否则电脑不识别USB,产品ID可以自定义。

/* USB标准设备描述符*/

uint8_t DFU_DeviceDescriptor[DFU_SIZ_DEVICE_DESC] =

{

    0x12,                       /*bLength:长度,设备描述符的长度为18字节*/

    USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType:类型,设备描述符的编号是0x01*/

    0x00,                       /*bcdUSB:所使用的USB版本为2.0*/

    0x02,

    0x00,                       /*bDeviceClass:设备所使用的类代码*/

    0x00,                       /*bDeviceSubClass:设备所使用的子类代码*/

    0x00,                       /*bDeviceProtocol:设备所使用的协议*/

    0x40,                       /*bMaxPacketSize:最大包长度为64字节*/

    0x83,                       /*idVendor:厂商ID为0x1234*/

    0x04,

    0x11,                       /*idProduct:产品ID为0x1010*/

    0xDF,

    0x00,                       /*bcdDevice:设备的版本号为2.00*/

    0x02,

    1,                          /*iManufacturer:厂商字符串的索引*/

    2,                          /*iProduct:产品字符串的索引*/

    3,                          /*iSerialNumber:设备的序列号字符串索引*/

    0x01                        /*bNumConfiguration:设备有1种配置*/

}; /* DFU设备描述符 */


接下去是配置描述符集合,配置描述符不需要修改。但之后的接口描述符的 bNumEndpoints域(该接口所使用的端点数)需要设置成0,因为USB DFU值需要端点0,不不需要其他的端点;接口描述符的bInterfaceClass(该接口所使用的类)域的值为0xFE,表示使用DFU类接口;接口描述符的bInterfaceSubClass(该接口所用的子类)设置成0x01,表示boot用途;接口描述符的nInterfaceProtocol设置成0x2,即DFU模式;最后还要设置接口字符串描述符的索引值为4。接下去是DFU功能描述符,这里设置bmAttribute域USB的属性为0x0B(具体意义看下面代码);DetachTimeOut(超时时间)设置成0XFF,表示超时时间为255ms;接下去设置TransferSize:(传输的长度)为0x400,注意这里是用两字节小端模式表示。

/* USB配置描述符集合(配置、接口、端点、类、厂商)(Configuration, Interface, Endpoint, Class, Vendor */

uint8_t DFU_ConfigDescriptor[DFU_SIZ_CONFIG_DESC] =

{

    0x09,   /*bLength:长度,设备字符串的长度为9字节*/

    USB_CONFIGURATION_DESCRIPTOR_TYPE, /*bDescriptorType:类型,配置描述符的类型编号为0x2*/

    DFU_SIZ_CONFIG_DESC,     /*wTotalLength:配置描述符的总长度为41字节*/    

    0x00,

    0x01,         /*bNumInterfaces:配置所支持的接口数量1个*/

    0x01,         /*bConfigurationValue:该配置的值*/

    0x00,         /*iConfiguration:该配置的字符串的索引值,该值为0表示没有字符串*/              

    0xC0,         /* bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒

D7:保留必须为1,D6:是否自供电,D5:是否支持远程唤醒,D4~D0:保留设置为0*/

    0x32,         /*从总线上获得的最大电流为100mA */

//    0x96,         /*MaxPower:设备需要从总线上获取多少电流,单位为2mA,0x96表示300mA*/



/****** Descriptor of DFU interface 0 Alternate setting 0***********/

    0x09,         /*bLength:长度,接口描述符的长度为9字节 */

    USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType:接口描述符的类型为0x4 */

    0x00,         /*bInterfaceNumber:该接口的编号*/

    0x00,         /*bAlternateSetting:该接口的备用编号 */

    0x00,         /*bNumEndpoints:该接口所使用的端点数*/

    0xFE,         /*bInterfaceClass该接口所使用的类为 DFU*/

    0x01,         /*bInterfaceSubClass:该接口所用的子类 1=BOOT, 0=no boot */

    0x02,         /*nInterfaceProtocol :DFU模式*/


    4,   /* iInterface:接口字符串描述符的索引 */


    /******************** DFU功能描述符********************/

    0x09,   /*blength:DFU描述符的长度为9字节*/

    0x21,   /*功能描述符的类型为0x21*/

    0x0B,   /*bmAttribute


                                             bitCanDnload             = 1      (bit 0) 下载性能

                                             bitCanUpload             = 1      (bit 1) 上传性能

                                             bitManifestationTolerant = 0      (bit 2) 设备在心事阶段后是否可通过USB通讯

                                             bitWillDetach            = 1      (bit 3) 接收到DFU_DETACH命令时会进行总线detach-attac

                                             Reserved                          (bit4-6) 保留

                                             bitAcceleratedST         = 0      (bit 7)  该为置1,设备将会上传速度增加到4096字节/命令*/

    0xFF,   /*DetachTimeOut:超时时间 255 ms*/

    0x00,

    wTransferSizeB0,

    wTransferSizeB1,          /* TransferSize:传输的长度为1024 Byte*/

    0x1A,                     /* bcdDFUVersion:DFU协议版本*/

    0x01

}; 


接下去的语言字符串描述符、厂商字符串描述符、产品字符串描述符、序列号字符串描述符都不详细介绍了。

/* 语言ID描述符 */

uint8_t DFU_StringLangId[DFU_SIZ_STRING_LANGID] =

{

    DFU_SIZ_STRING_LANGID,    /*bLength:本描述符的长度为4字节*/

    USB_STRING_DESCRIPTOR_TYPE,     /*bDescriptorType:字符串描述符的类型为0x03*/

    0x09,     /*bString:语言ID为0x0409,表示美式英语*/

    0x04

}; /* LangID = 0x0409: U.S. English*/


/*厂商字符串描述符*/

uint8_t DFU_StringVendor[DFU_SIZ_STRING_VENDOR] =

{

    DFU_SIZ_STRING_VENDOR, /*bLength:厂商字符串描述符的长度*/

    USB_STRING_DESCRIPTOR_TYPE,  /*bDescriptorType:字符串描述符的类型为0x03*/

    'B' , 0, 'y', 0, ':' , 0, 'z' , 0, 'i', 0, 'y', 0,'e', 0,'3', 0, '3', 0, '4', 0 /*自定义*/

};


/*产品的字符串描述符*/

uint8_t DFU_StringProduct[DFU_SIZ_STRING_PRODUCT] =

{

    DFU_SIZ_STRING_PRODUCT,   /* bLength:产品的字符串描述符*/

    USB_STRING_DESCRIPTOR_TYPE,     /* bDescriptorType:字符串描述符的类型为0x03*/

    'z', 0, 'i', 0, 'y', 0, 'e', 0, '3', 0, '3', 0 ,'4',0/*自定义*/

};


/*产品序列号的字符串描述符*/

uint8_t DFU_StringSerial[DFU_SIZ_STRING_SERIAL] =

{

    DFU_SIZ_STRING_SERIAL,    /* bLength:产品序列号*/

    USB_STRING_DESCRIPTOR_TYPE,     /* bDescriptorType:字符串描述符的类型为0x03*/

    '1', 0, '2', 0, '3', 0,'4', 0,'5', 0, '6', 0, '7', 0 /*自定义*/

};


重点介绍的是接口字符串描述符,这个字符串描述符定义了升级的硬件信息,如下是我们的接口描述符:

/*接口字符串描述符*/

uint8_t DFU_StringInterface0[DFU_SIZ_STRING_INTERFACE0] =

  {

    DFU_SIZ_STRING_INTERFACE0,

    0x03,

    // Interface 0: "@Internal Flash   /0x08000000/12*001Ka,500*001Kg"

    '@', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'n', 0, 'a', 0, 'l', 0,  /* 18 */

    ' ', 0, 'F', 0, 'l', 0, 'a', 0, 's', 0, 'h', 0, ' ', 0, ' ', 0, /* 16 */

推荐阅读

史海拾趣

Hitron公司的发展小趣事

机顶盒,全称为数字视频变换盒,是连接电视机与外部信号源的重要设备,具有高度的专业性和广泛的科普意义。作为信息家电的一员,机顶盒不仅实现了数模转换,让用户能够在模拟电视上观看数字电视节目,还通过接入互联网,极大地丰富了电视节目的选择,提升了观看体验。

从广义上讲,机顶盒涵盖了从模拟频道增补器到现代的数字卫星机顶盒(DVB-S)、数字地面机顶盒(DVB-T)、有线电视数字机顶盒(DVB-C)以及IPTV机顶盒等多种类型。这些机顶盒不仅接收来自有线电缆、卫星天线、宽带网络及地面广播的信号,还提供了电子节目指南、网页浏览等增值服务,使电视机成为了一个能够与用户进行互动的智能终端。

在技术层面,机顶盒的工作原理可概括为接收、解码和显示三个步骤。它首先通过内置的调谐器接收数字电视信号,随后由内部的解码器将信号转换成电视可识别的视频和音频流,最终通过电视机呈现给用户。随着技术的不断进步,机顶盒已能支持高清、甚至4K超高清视频播放,为用户带来更为细腻的画面和震撼的音效。

未来,机顶盒市场将继续保持稳定增长态势,技术创新与智能化将成为重要的发展方向。高清化、超高清化、人工智能及云计算等技术的应用,将使机顶盒不仅限于基本的电视信号接收与解码功能,而是向智能化、多功能化方向迈进,为用户提供更加便捷、智能的生活体验。

百蓉(ECE)公司的发展小趣事

面对智能制造的浪潮,百蓉公司积极拥抱变革。他们引进了先进的自动化设备,对生产线进行了全面升级,实现了从手工制造向智能制造的转变。这一转型不仅提高了生产效率,还大幅提升了产品质量和产品的一致性,使得百蓉的产品在市场上更具竞争力。

Charcroft Electronics Ltd公司的发展小趣事

随着产品线的不断丰富和技术实力的提升,Charcroft Electronics Ltd公司开始积极拓展国内外市场。公司加强与国际知名企业的合作,通过参加国际电子展会、举办技术研讨会等方式,提升品牌知名度和影响力。同时,公司还针对不同地区的市场需求,推出定制化的产品和服务,进一步巩固和扩大市场份额。

台湾町洋(dinkle)公司的发展小趣事

町洋始终坚守品质至上的原则,从原材料采购到生产流程再到成品检验,每一个环节都严格把关。这种对品质的执着追求使得町洋的产品在市场上享有极高的声誉。客户对町洋产品的信任和认可也成为了公司最宝贵的财富。

格莱尔(GLE)公司的发展小趣事

深圳市格莱尔电子有限公司成立于2005年,初期专注于电感产品的研发与生产。在创始人及团队的共同努力下,公司迅速在行业内崭露头角。随着技术的不断积累和市场需求的扩大,格莱尔逐渐扩大生产规模,并于2012年在湖北投资建厂,自建两座工厂,厂房面积达2万平方米,员工人数增长至500人。这一系列的举措不仅提升了公司的生产能力,也为其后续的发展奠定了坚实的基础。

ELPIDA公司的发展小趣事

在成立初期,ELPIDA凭借其强大的技术实力和规模效应,迅速在全球DRAM市场中占据了重要地位。公司不断推出创新产品,扩大市场份额,成为行业内的重要参与者。然而,随着市场竞争的加剧和技术的快速变化,ELPIDA也面临着巨大的挑战。

问答坊 | AI 解惑

USB摄像头图纸

USB摄像头图纸 [ 本帖最后由 西门 于 2009-5-13 19:37 编辑 ]…

查看全部问答>

Wince环境下地图的问题

Wince环境下导入地图用什么控件,还是根本不需要用什么控件,还有显示地图有哪些基本操作呢?麻烦了~…

查看全部问答>

功能强劲的程序编辑器SourceInsight-v3.50.0050

功能强劲的程序编辑器SourceInsight-v3.50.0050 Source Insight是一个功能强劲的程序编辑器,他内置对C/C++,Java和x86汇编语言程序的解析;有自己的动态数据库在你编程时提供有用的文本提示,包括有关的函数,宏,参数等! 如今最好用的语言编辑 ...…

查看全部问答>

ZwSetInformationFile问题

NTSTATUS CoreyDDKDriverControl(IN PDEVICE_OBJECT pDevObj,                                                 &nb ...…

查看全部问答>

SQL Mobile 在Wince5.0 Arm下的安装问题 (SQL CE 3.0)

我在WinCE5.0 ARM的系统安装SQL Mobile 安装过程如下: 复制 * NETCFv2.wce5.armv4i.cab * sqlce30.wce5.armv4i.CAB * sqlce30.dev.ENU.wce5.armv4i.CAB * sqlce30.repl.wce5.armv4i.CAB 到WinCE5.0中,然后分别安装,都提示安装成功。 安 ...…

查看全部问答>

哪个朋友帮我忙??我十万火急,,吃饭不下

现在生产线的工装设备又老又慢,,,,要搞个新的东西出来,,哪个帮我建议下,,要测试的东西如附件…

查看全部问答>

互联系列USB库例程何时出

                                 现在USB-OTG-FS库也不会用,水平太哇。不知道什么时候会有例程出来…

查看全部问答>

“驯服”振荡—电容性负载问题

在TI E2E社区中发现了几篇不错的文章,特意翻译过来分享给大家,其中Bruce Trump系列关于放大器有很好的见解,特此供大家学习和参考。 此篇是连载文章,欲知更多精彩内容,请查看我的其他分享! 摘要:鉴于反馈通路中相移(或者称作延迟)引起 ...…

查看全部问答>

CCS无法烧写程序

CCS调试过程中“cannot load from non-primitive location”是什么原因 …

查看全部问答>

【LPC54100】第一周-分享部分原理图和blink跑起

本帖最后由 shower.xu 于 2015-3-24 00:05 编辑 几经破折,今天板子才拿到手,结果发现不是之前的那块板子,只有重新搜集资料。 找了半天,基本是大家的各种吐槽,算了吧万事总有开头,花了一晚上时间测量了几个外设的脚位接口,修改了之前板子 ...…

查看全部问答>