蓝牙给升级单片机升级_lanya给单片机升级源码 - CSDN
  • 原来“给单片机烧写程序”的实质就是把“编译”好的“程序二进制文件”复制到芯片的flash中,和从电脑传电影到MP4播放器上是相似的原理。只不过现在这个“电影”是 “程序二进制文件”,而单片机就是这个“二进制...

    听到这个"需求"的第一反应“这是开玩笑吧”。我是是一个普通的码农,怎么可能开发出了那么复杂的东西。
    带着一头冷汗,开始查资料中…
    原来如此,有一种下载程序的方式叫做“IAP”。 悬着的心终于放了下来。
    原来“给单片机烧写程序”的实质就是把“编译”好的“程序二进制文件”复制到芯片的flash中,和从电脑传电影到MP4播放器上是相似的原理。只不过现在这个“电影”是 “程序二进制文件”,而单片机就是这个“二进制程序”的“播放器”。

    一、前言(需求背景)

    需求背景就是“远程更新硬件设备的芯片程序(固件)”。在开发硬件设备的时候,一般使用专用“烧写器”给芯片烧写程序。从而完成芯片应用程序编码和调试工作。在硬件设备研发完成,正式生产出产品并卖给客户后。如果需要更新硬件程序怎么办。难道也要给用户邮寄一个烧写器和程序文件?一个批次的产品都需要更新,你能邮寄的过来吗?这期间会消耗多少成本。这是要赔本的节奏呀。因此,你需要一个“更新固件”的功能。“更新固件”这个词,对于爱鼓捣智能设备的兄台应该很熟悉吧。注意,使用网络或GPRS远程升级固件的时候,这项技术被称为“OTA升级”。

    二、实现“更新固件”的原理

    “更新固件”从技术角度来看,本质上是“芯片自己给自己更新(烧写)程序”。没错就是自己给自己更新程序,听起来有点吓人,万一芯片学会了自己给自己迭代升级程序,就像生物进化一样,一步一步的进化,最终出现“智慧思想”怎么办。如果你看过“终结者”就会知道:“没办法,拦是拦不住的”。因此,就会出现“硅基生物”代替“碳基生物”的地球(如果你看过刘慈欣的著作你就会明白我要表达的意思)。

    芯片自己更新程序的原理是:芯片中是可以存放多个“程序”的。就和你的手机可以同时安装“支付宝”和“微信”是一个道理。而实现芯片自己更新“程序”的原理就是,烧写在芯片中的其中一个“程序”可以更新芯片中的另一个“程序”。把可以更新其他程序的“程序”叫做“Bootloader”,把被更新的“程序”叫做“App”。(当然从原理上来说芯片上的多个程序是可以实现互相更新的。只是现实中很少有这样的需求)。更详细的实现细节,请阅读13.2~13.5章节。

    二、STM32单片机支持的几种“烧写”方式说明

    1. stm32单片机有三种启动方式
      启动方式由芯片上的两个管脚BOOT0和BOOT1来决定:
    引脚配置 启动模式 程序储存位置 支持的下载模式 备注
    BOOT1=x BOOT0=0 从用户闪存启动 Flash SWD/JTAG 单片机正常运行所使用的模式,在此模式,可以直接用专用烧写器下载程序
    BOOT1=0 BOOT0=1 从系统存储器启动 Flash ISP 从芯片自带的bootloader(ISP程序)下载程序,下载完需要切换引脚为“BOOT1=x BOOT0=0 ”并复位芯片,才能运行程序。
    BOOT1=1 BOOT0=1 从内置SRAM启动 SRAM ISP 调试模式,下载到芯片的代码存放在内存中,从而加快下载速度,避免写Flash。由于程序储存在内存中,因此掉电会丢失程序
    1. Stm32所支持的烧写方式
    • SWD/JTAG
      两种标准的“烧写器”编程接口(协议),支持这些编程接口的烧写器有:JLINK、ULINK、ST-LINK

    • ISP(In System Programing,在系统中编程)
      使用固化在芯片内部的bootloder更新应用程序的一种方式。需要芯片硬件支持(阅读芯片手册)。一般使用串口下载程序,常用的下载工具软件有:国产的FlyMcu 和 stm公司官方提供的Flash Loader Demonstrator。注意,烧写的时候,需要配置芯片的Boot引脚,烧写完成之后,再修配置回来才能运行程序。

    • IAP(In applicating Programing,在应用编程),是一种除基本芯片烧录方法之外的一种巧妙程序烧写方式。
      实现IAP下载程序,需要芯片保持在“从闪存启动模式”。其实现原理为:把flash 划分为2个部分,一个部分用于放置“更新其他程序的bootloader”,另一部分放置普通的应用程序。其中bootloder放置在芯片“上电”自动运行的位置(即用烧写器烧写普通程序的位置)。而普通的应用程序被放置在flash偏后面的 扇区中。至此你会有以下几个疑问,下面分别解答。手机自动更新系统,其实就是使用了IAP的原理。(其实电脑操作系统和手机操作系统都有bootloader,只不过用在电脑系统上,被叫做“Windows Boot Manager”)。

    1. bootloader到底是什么?烧写程序是怎么做到的?
      bootloader起始就是一个普通的单片机应用程序,但他的功能是,从芯片外界读取“应用程序的bin文件”并把这个文件放置到芯片Flash的指定位置。就完成了“应用程序的烧写”。

    2. 有了bootloader之后,芯片程序怎样启动?
      现在被烧写好的“应用程序”没有放置到单片机上电运行的位置,那么应用程序怎么启动呢。答案是,芯片上电,默认会运行bootloader这个程序,而bootloader这个程序可以判断是否存在可用的App,如果存在则把当前程序运行的“pc指针”指向放置应用程序的flash地址(在此之前,重新指定新的“中断向量表”和“堆栈”的地址)即可让应用程序跑起来。是的,使用IAP方式后,以后芯片每次上电都走这样一个启动流程。

    四、实现IAP有哪几种方式,分别说明

    提到IAP的实现方式,那可多了去了。可以说只要能实现“数据传输”,就可以用来开发IAP升级固件的功能。以下把常用常见的方式加以详细说明:

    1. U盘
      Bootloader需要读取U盘的文件系统,从U盘读取固件文件并写在Flash的指定位置。从而完成程序更新。
      最常见的IAP实现方式,也最方便。只要把固件放置到U盘,然后插入机器,启动机器即可自动更新应用程序。一般智能硬件,采用设备本身模拟U盘的功能,当你把智能硬件使用USB数据线连接到电脑上之后,电脑上会弹出一个类似U盘的磁盘,你只需把固件文件(bin文件)复制粘贴到这个磁盘中即可。然后断开USB连接线,重启或重新给智能硬件通电,智能设备就会自动更新固件。缺点:要做的支持市面上的所有U盘很难。

    2. 串口(RS232/RS485)
      Bootloader需要实现串口通信,使用串口通道接收固件文件并写在Flash的指定位置。从而完成程序更新。
      这个也是常用的更新固件方式。使用硬件设备的的“串口通信线”即可完成芯片固件更新。需要配合相应的上位机软件来实现。使用体验比较好,使用起来也比较稳定。(本文一开始说描述的需求,就是指这种实现方式)

    3. 网络TCP
      Bootloader需要实现网络通信,使用网络通道接收固件文件并写在Flash的指定位置。从而完成程序更新。
      常用于实现远程自动更新。比如放置在野外的智能设备,通过4G网络定期查看是否有更新,如果有则通过网络下载固件并自动更新。

    4. 蓝牙
      Bootloader需要实现蓝牙通信,使用蓝牙通道接收固件文件并写在Flash的指定位置。从而完成程序更新。
      常用于便携式设备的更新。因为一般的便携式设备都是使用蓝牙通信。所以只能用蓝牙来更新固件。
      比如:智能手表,蓝牙耳机,蓝牙鼠标,蓝牙xx

    5. CAN总线(主丛电路板方式)
      常用于更新大型机器中的某一块电路板上芯片的程序。主电路板有文件系统,可以储存其他电路板上芯片的固件文件。大型设备内部,电路板与电路板之间常使用CAN总线通信。因此要更新机器内某个电路板的程序,可以通过“主从电路板”的方式,线把固件文件先传输到主电路板芯片中,然后主电路板芯片通过CAN总线给目标电路板更新程序。

    五、IAP升级固件中的“加密”说明

    1. 为什么要加密
      当你的机器硬件出现问题的时候,你需要把固件文件发给用户,让用户使用“U盘”或串口来升级程序。这个时候相当于把你的程序可执行文件暴露了,如果让想“复制”你设备的人拿到手,他可乐开了花了。他只需要自己写个bootloader就能借用你这个“可执行文件”来生产一模一样的设备了。你怎么办,只能走法律途径了。所以你不加密固件,相当于“鼓励别人犯罪”。
    2. 怎么加密
      再bootloader中作修改。专门编写一个加密软件,来加密你要发给用户的“固件”。然后你自己机器中的bootloader加入对应的解密代码。bootloader从U盘或串口拿到“固件”文件先解密,然后在写到Flash中即可。至于用哪个加密算法,这里没有推荐(需求明确了还怕没有解决方案嘛.)。

    六、IAP升级固件中的“压缩”说明

    1. 为啥要压缩固件
      因为大呗!普通Stm32的应用程序,编译出来的Bin文件大小在20K~100K之间。咦,不大呀,怎么说大呢?
      是不大,但是看对于什么通信方式来说。
      对于U盘更新固件方式,几百K是小意思。如果对于网络方式呢。一般都是给远程网络设备更新固件,用的是流量。而物联网卡的流量很有限,伤不起呀。其次,看你对速度有没有要求。比如你用蓝牙来更新固件。更新速度的瓶颈是在传输速度上。而速度是无法提高的,只能通过减小固件体积来达到提高更新速度的效果。

    2. 怎样压缩与解压缩固件
      使用电脑软件来实现对固件的压缩。bootloader只要负责解压即可。推荐的芯片可用压缩算法有:zlib、miniLZO

    展开全文
  • STM32+IAP方案 实现网络升级应用固件

    千次阅读 2018-08-26 22:28:56
    关注了这个概念有些日子了,这段时间总算有机会实战==网络升级应用固件,这里记录下遇到的问题,及解决方案。  原理与网上流传的串口作为传输手段 一致;不同之处,无非我这里使用了网络设备传输。==(lwip)TFTP...

    关注了这个概念有些日子了,这段时间总算有机会实战==网络升级应用固件,这里记录下遇到的问题,及解决方案。 
    原理与网上流传的串口作为传输手段 一致;不同之处,无非我这里使用了网络设备传输。==(lwip)TFTP客户端的应用. 
    参考: 
    IAR环境下STM32+IAP方案的实现 
    STM32浅谈之IAP.pdf 
    基于IAP和Keil MDK的远程升级设计 
    keil MDK中如何生成*.bin格式的文件


    概况:

    • 什么是IAP,为什么要IAP
    • 可实现的原理
    • 实现过程
    • 细节及实现 
      以上基本都可以从【IAR环境下STM32+IAP方案的实现】中找到答案。这里只是贴图,醒目: 
      IAP框架布局: 
      这里写图片描述
      STM32F103ZET6的启动方式有三种:内置FLASH启动、内置SRAM启动、系统存储器ROM启动,通过BOOT0和BOOT1引脚的设置可以选择从哪中方式启动,这里选择内置的FLASH启动。其FLASH的地址为0x08000000—0x0807ffff,共512KB,这些都能从芯片数据手册中直接得到。而这里首要的一个问题是中断的问题。正常情况下发生中断的过程为:发生中断(中断请求),到中断向量表查找中断函数入口地址,跳转到中断函数,执行中断函数,中断返回。也就是说在STM32的内置的Flash中有一个中断向量表来存放各个中断服务函数的入口地址,内置Flash的分配情况大致如下图2-1。 
      这里写图片描述 
      这里写图片描述 
      这里写图片描述
      这里写图片描述
      在内置的Flash里面添加一个BootLoader程序,BootLoader程序和user application各有一个中断向量表,假设BootLoader程序占用的空间为N+M字节,则程序的走向应该如图2-2所示(借用网友的原图并做改动,其中虚线部分为原图步骤④⑤的走向,本人改为指向灰色部分)。 
      这里写图片描述 
      上电初始程序依然从0x08000004处取出复位中断向量地址,执行复位中断函数后跳转到IAP的main(标号①所示),在IAP的main函数执行完成后强制跳转到0x08000004+N+M处(标号②所示),最后跳转到新的main函数中来(标号③所示),当发生中断请求后,程序跳转到新的中断向量表中取出新的中断函数入口地址,再跳转到新的中断服务函数中执行(标号④⑤所示),执行完中断函数后再返回到main函数中来(标号⑥所示)。 
      对于步骤④⑤,网友认为是:“在main执行的过程中,如果CPU得到一个中断请求,PC指针仍强制跳转到地址0x08000004中断向量表处,而不是新的中断向量表,如图标号④所示,程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示”。我对此的理解是:“当发生中断后,程序从0x08000004(旧)处的中断向量表中得到相应的中断服务函数入口地址,继而跳转到相应的中断服务程序”。但是旧的中断向量列表里边存放的是IAP程序中断函数的入口地址,它是如何得到user程序中断函数的入口地址呢?所以我觉得此种说法是错误的。“当发生中断时PC指针强制会跳转到0x08000004处”这种说法并没有错,只是忽略了后续的一些知识要点而导致这个说法出现矛盾。 
      对于步骤④⑤我认为的是,在main函数的执行过程中,如果CPU得到一个中断请求,PC指针本来应该跳转到0x08000004处的中断向量表,由于我们设置了中断向量表偏移量为N+M,因此PC指针被强制跳转到0x08000004+N+M处的中断向量表中得到相应的中断函数地址(待求证),再跳转到相应新的中断服务函数,执行结束后返回到main函数中来。

    IAP流程描述:

    1、IAP的bootloader引导程序

    IAP在应用中编程,可以拓展成远程网络更新应用固件。 
    片内的flash,至少划分成2个分区,对应至少两个完整的程序; 
    低地址分区端推荐放入IAP程序==bootloader引导程序(这里边的手段可以是串口、网络等不同的方式),高地址分区端推荐烧写app固件。 
    关键点提及: 
    IAP程序中,当满足跳转条件(被触发)时,执行跳转代码到app应用固件程序,跳转代码流程: 
    至少需要设定跳转目的地的app应用固件 栈顶指针,:

    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*) USER_FLASH_FIRST_PAGE_ADDRESS);
    • 1
    • 2

    其中,app应用固件的分区地址:

    #define USER_FLASH_FIRST_PAGE_ADDRESS 0x08009000
    • 1

    2、app应用固件

    需要两处的更改,不然错误未知 
    IROM设置如图: 
    这里写图片描述 
    中断向量表偏移: 
    这里写图片描述

    NVIC_SetVectorTable(NVIC_VectTab_FLASH,VectorTable_Offset);
    • 1

    其中:

    #define NVIC_VectTab_FLASH           ((uint32_t)0x08000000)
    #define VectorTable_Offset  0x9000 
    • 1
    • 2

    查错:

    如果做了上边的工作,IAP依然无法顺利执行跳转至app应用程序,可以查看.map和.bin文件,确定是否如实的改变的中断向量表的偏移和栈顶指针,如图: 
    这里写图片描述
    .bin文件: 
    这里写图片描述 
    可以看到,主栈顶MSP地址=0x2000C8C8、reset_handler地址=0x08009189 
    如此,才能生效,否则,可能原因: 
    修改后的向量表偏移,在之后的程序中,又再次被还原,通过如下的函数:

    void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
    void SystemInit (void);
    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
    • 1
    • 2
    • 3

    附:

    1、如需要.hex文件转.bin,参见上边的文章 
    当然,就算使用.hex文件,同样可以升级,只是需要修改IAP中判定已经升级的文件是否有效,文件条件部分的代码,

    if(((*(__IO uint32_t*)USER_FLASH_FIRST_PAGE_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    • 1

    2、地址偏移后的app应用程序,是否能够独立的运行? 
    不能,理由: 
    这里写图片描述
    可知,开机上电并不能够找到我们指定的偏移后的向量表。

    展开全文
  • 基于蓝牙的STM32 IAP在线升级

    千次阅读 2018-12-12 23:10:37
    流程解释: 产品的最新程序放在云端的服务器上,并将程序更新的提醒通过手机APP推送用户,当用户点击程序更新时,APP将程序下载至手机上,并通过蓝牙传输到STM32上,这时单片机解析到的指令为程序更新,便触发IAP...

    最近开发的一个小项目需要支持蓝牙在线升级,今天便详细地了解一番。蓝牙在线升级的方式,流程如图
    在这里插入图片描述
    流程解释: 产品的最新程序放在云端的服务器上,并将程序更新的提醒通过手机APP推送给用户,当用户点击程序更新时,APP将程序下载至手机上,并通过蓝牙传输到STM32上,这时单片机解析到的指令为程序更新,便触发IAP在线刷新程序。

    要实现这一功能,必须通过单片机的串口IAP在线升级功能。
    1.什么是IAP?

    IAP(In Application Programming)即在应用编程,IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。

    所以要实现IAP功能,固件程序须分为两个代码,即引导程序(BootLoader)和用户程序(APP)。
    1.引导程序(BootLoader):只执行串口数据的接收、烧写程序并将程序执行地址跳转至用户程序段(此代码只能通过JTAG或SWD烧写)
    2.用户程序(APP):执行用户所要实现的程序(此代码通过串口接收,IAP烧写入单片机flash中)

    2.STM32程序的启动方式
    为什么能将程序分成两个程序分别下载,要理解这个,我们有必要了解一下STM32的启动方式,因为我用的是STM32F103C8T6,所以就以这个型号为例:
    STM32上电或者复位后,代码区始终从0x00000000开始,三种启动模式其实就是将各自存储空间的地址映射到0x00000000中。其启动模式由BOOT0和BOOT1引脚的电平高低来控制。
    在这里插入图片描述
    1、BOOT1=x BOOT0=0:从Flash启动,将主Flash地址0x08000000映射到0x00000000,这样代码启动之后就相当于从0x08000000开始,这是正常的工作模式。
    2、BOOT1=0 BOOT0=1:从系统存储器启动。首先控制BOOT0 BOOT1管脚,复位后,STM32与上述两种方式类似,从系统存储器地址0x1FFF F000开始执行代码,这种模式启动的程序功能由厂家设置。
    3、BOOT1=1 BOOT0=1: 从RAM启动,将RAM地址0x20000000映射到0x00000000,这样代码启动之后就相当于从0x20000000开始,这种模式可以用于调试。
    这里,我默认使用的模式是主闪存控制器启动,也就是从Flash启动。

    3. Flash在STM32内存空间的定义
    STM32单片机内存空间有明确的定义,
    在这里插入图片描述
    查看STM32F103C8T6可知,其Flash是分配在空间从0x0800 0000到0x0801FFFF,最大的空间为127KByte。所以在主闪存控制器启动模式下,STM32一上电,单片机先将0x0800 0000映射到代码区,然后从0x0800 0000开始执行程序。
    在进入main函数前,单片机还做了以下处理(不需要自己编写代码,由单片机内部自动执行)
    在这里插入图片描述
    ortex-M3上电后来到复位中断(已将前4个字节的值存入MSP堆栈指针),转到__main标号,完成RW段的移动、ZI段的初始化,建立堆栈,初始化库函数,然后跳转到main函数,自此就开始执行我们编写的C程序。

    4.引导程序和用户程序内存空间的划分
    我们知道,单片机默认是从0x0800 0000开始执行的,其过程:
    在这里插入图片描述
    1.STM32 在复位后,先从 0X08000004 地址取出复位中断向量的地址,并跳
    转到复位中断服务程序,如图标号①所示;
    2.在复位中断服务程序执行完之后,会跳转到我们的main 函数,如图标号②所示;
    3.而我们的 main 函数一般都是一个死循环,在 main 函数执行过程中,如果收到中断请求(发生重中断),此时 STM32 强制将 PC 指针指回中断向量表处,如图标号③所示;
    4.然后,根据中断源进入相应的中断服务程序,如图标号④所示;
    5.在执行完中断服务程序以后,程序再次返回 main 函数执行,如图标号⑤所示。

    而我们将FLash的内存空间分为引导程序和用户程序,其0x0800 0000~0x0800 2000,8KByte的空间作为BootLoader,将0x0800 2000 ~0x0801 FFFF,共120KByte作为用户空间(STM32F103C8T6实际只有64KByte Flash,用户空间为56KByte)。
    在这里插入图片描述
    通过此种方式后,STM32执行程序的流程变为:
    在这里插入图片描述

    1. STM32 复位后,还是从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到 IAP 的 main 函数,如图标号①所示。
    2. 此部分同图 47.1.1 一样;在执行完 IAP 以后(即将新的 APP 代码写入 STM32的 FLASH,灰底部分。
    3. 新程序的复位中断向量起始地址为 0X08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的 main 函数,如图标号②和③所示,
    4. 同样 main 函数为一个死循环,并且注意到此时 STM32 的 FLASH,在不同位置上,共有两个中断向量表。

    5.引导程序的设计
    (1)首先,实现串口中断函数,蓝牙通过串口将数据传输到单片机上,因为STM32F103C8T6的RAM只有8KByte,所以上位机每次发送的数据为1KByte,单片机烧写完后再发送下1KByte数据。

    extern uint8_t usart_buf[1024+8];
    //数据长度(2B)  数据(1KB)  序号(2B)  [CRC(4B)]
    extern uint16_t buf_cnt;
    extern uint8_t bootStatus;
    
    void USART1_IRQHandler(void)
    {
    	uint8_t temp = 0;
    	if( (USART_GetFlagStatus(USART1, USART_IT_RXNE) != RESET) )
    	{
    		temp = (uint8_t)USART_ReceiveData(USART1);
    		if(++buf_cnt < (1024+8)  && ((buf_cnt & 0x8000) != 0x8000))
    		{
    			usart_buf[buf_cnt - 1] = temp;
    		}
    		else buf_cnt |= 0x8000;
    	}
    }
    

    (2)在main函数中,对接收到的数据进行判断

    if(flag)      //是否串口是否有接收到数据
    {
    	printf("开始更新固件r\n");	
    	// 判断APP程序的起始地址是否为0X08XXXXXX
     	if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)
    	{	 
    		iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新	FLASHFLASH代码	
    		printf("固件更新成功\r\n");		
    	}
    	else 
    	{
    		printf("非固件程序\r\n");
    	}
    	flag = 0;
    

    (3)如果检测到APP程序,进入FLASH烧写函数

    // 从addr起烧录程序
    
    void Iap_Write(uint32_t addr)
    {
    	uint16_t temp = 0;
    	uint16_t data_size = 0;    //烧录大小
    	uint16_t data_len = 0;	   //数据长度
    	uint16_t index = 0;         //数据块索引
    	uint32_t addr_now = addr;	    //写入地址
    	uint8_t data_write[1024] = {0};	//数据缓冲
    	//准备烧录,数据大小为1K
    	while(1)
    	{
    		while((buf_cnt & 0x8000) == 0);		//等待数据接收完毕
    		//解析数据
    		data_len = (uint16_t)usart_buf[1] << 8 | usart_buf[0];	//获取data有效长度
    		for(temp = 2; temp < data_len + 2; temp++)	//从第二位开始拷贝数据
    		{
    			data_write[temp - 2] = usart_buf[temp];
    		}
    		index = usart_buf[1024 + 3] << 8 + usart_buf[1024 + 2];			//获取索引
    		//开始写数据
    		if(data_len < 1024)	//写入剩下的数据
    		{
    			if(data_len % 2 != 0)data_len += 1;
    			STMFLASH_Write(addr_now, (uint16_t *)data_write, data_len / 2);		//
    			data_size += 1;
    			STMFLASH_Write(IAP_INFO, &data_len, 1);
    			putString("OK\n");
    			break;
    		}
    		else
    		{
    			STMFLASH_Write(addr_now, (uint16_t*)data_write, data_len / 2);
    			data_size += 1;
    			addr_now += 1024;	//下一个1K
    			buf_cnt = 0;
    			for(temp = 0; temp < USART_BUF_SIZE; temp++)usart_buf[temp] = 0;
    			putString("Next\n");		
    		}
    	}		//烧录完成
    	//清空串口缓存
    	buf_cnt = 0;
    	for(temp = 0; temp < USART_BUF_SIZE; temp++)usart_buf[temp] = 0;
    }
    

    (4)烧录好APP程序后,引导程序将PC指针地址指向APP程序的起始地址,即0x0800 2000;要对PC指针进行操作,需使用MSR汇编指令来操作。

    //设置栈顶地址
    //addr:栈顶地址
    __asm void MSR_MSP(u32 addr) 
    {
        MSR MSP, r0 			//set Main Stack value
        BX r14
    }
    

    然后执行PC指针跳转函数

    void Iap_load(uint32_t addr)
    {
    	if(((*(vu32*)addr) & 0x2FFE0000) == 0x20000000)		
    	{
    		jump = (iapfun) *(vu32*)(addr + 4);					//强制转化为函数
    		MSR_MSP(*(vu32*)addr);
    		jump();
    	}
    	else 
    	{
    		printf("Error\n");
    		while(1);
    	}
    }
    

    (5)最后,main函数的实现就很简单了,以轮询的方式读取串口数据,然后烧写FLASH,最后跳转至APP程序

    while(1)
    {
    	while((readBootTime() != 0)  && (flag == 0))			//以轮询的方式读取串口
    	{
    		if(Iap_wait() == 8)
    		{
    			USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);	
    			flag = 1;
    		}
    	}
    	if(flag)
    	{
    		IAP_WRITE();
    		flag = 0;
    	}
    	else 
    		IAP_LOAD();       //跳转至APP程序
    	}
    

    6.用户程序APP的实现
    用户程序实现比较简单,只需要对地址进行设计一下就可以,所以我就使用点亮LED来作为APP程序
    在这里插入图片描述
    图中 IROM1 的起始地址(Start)一般为 0X08000000,大小(Size)为 0X10000,
    即从 0X08000000 开始的64K 空间为我们的程序存储(因为我们STM32F103C8T6 的 FLASH大小是 64K)。而图中,我们设置起始地址(Start)为 0X0800 2000,即偏移量为 0X2000字节),因而,留给 APP 用的 FLASH 空间(Size)只有0X8000(56K 字节)大小了。设置好 Start 和 Szie,就完成 APP 程序的起始地址设置。

    (2) 设置APP程序的中断向量表的偏移量
    在 systemInit 函数中的,设置中断向量表的偏移量

    SCB->VTOR = FLASH_BASE | 0x2000;
    

    以上设置完成之后,点击rebuild按钮重新编译,生成LED.hex
    (3)生成APP程序bin文件
    我们通过 MDK 自带的格式转换工具 fromelf.exe,来实现.axf 文件到.bin 文件的转换。该工具在 MDK 的安装目录\ARM\BIN40 文件夹里面
    在这里插入图片描述
    我们就可以在 MDK 编译成功之后,调用 fromelf.exe,根据当前工程的 LED.axf,生成一个 LED.bin 的文件。
    7.APP程序的蓝牙在线升级
    由于公司云端服务器还没搭好,我就先自己的电脑蓝牙与产品蓝牙连接,然后通过用QT写的串口调试助手发送至STM32中,完成APP程序的升级。
    在这里插入图片描述
    至此,基于蓝牙的STM32 IAP在线升级就完成了!

    展开全文
  • STM32 BootLoader升级固件

    2019-09-02 23:57:17
    BootLoader 关于Bootloader,从书上的文字描述,很难理解这个名词是什么,有什么用。...1、BootLoader就是单片机启动时候运行的一段小程序,这段程序负责单片机固件的更新,也就是单片机选择性的自己自己下程...

    原文链接 https://blog.csdn.net/u011303443/article/details/53378602

    BootLoader

    关于Bootloader,从书上的文字描述,很难理解这个名词是什么,有什么用。这次用到了,算是有了更进一步的认识。
    一、知识点

    1、BootLoader就是单片机启动时候运行的一段小程序,这段程序负责单片机固件的更新,也就是单片机选择性的自己给自己下程序。可以更新,也可以不更新,更新的话,BootLoader更新完程序后,跳转到新程序运行;不更新的话,BootLoader直接跳转到原来的程序去运行。
    2、BootLoader更新完程序后并不擦除自己,下次启动后依然先运行BootLoader程序,又可以选择性的更新或者不更新程序,所以BootLoader就是用来管理单片机程序的更新。
    3、在实际的单片机工程项目中,如果加入了BootLoader功能,就可以给单片机日后升级程序留出一个接口,方便日后单片机程序更新。当然,这就需要创建两个工程项目,一个为BootLoader工程,一个为APP工程。
    4、BootLoader工程生成的.hex或者.bin文件通常下载到ROM或Flash中的首地址,这样可以保证上电后先运行BootLoader程序。而APP工程生成的.hex或者.bin文件则下载到ROM或Flash中BootLoader后面的地址中。也就是说,存在ROM/Flash中的内容是分为两部分的。
    5、要实现在同一个ROM/Flash中保存两段程序,并且保证不能相互覆盖,则需要在下载程序时指定地址。如在Keil下,可以进行如下的调整。

    这里写图片描述

    6、实际上,在STM32系列的单片机中,Flash本身就是分扇区的,一个扇区16KB的样子,具体可以查看手册。那么就可以用从第一个扇区的首地址开始下载BootLoader的程序,而从第二个扇区的起始地址开始下载APP程序。如下为STM32F4系列芯片的Flash模块。

    这里写图片描述

    7、单片机上电之后开始执行BootLoader程序,这时单片机会检测用户是否有升级应用程序(APP)的请求,具体表现有很多种,例如检测内存卡,Nand Flash中是否包含升级文件,串口/I2C/SPI等外设接口是否传来升级文件,还有使用GSM来升级的。
    8、所谓的升级,就是将ROM/Flash中存储APP程序的扇区内容擦除并写入新文件。例如一次固件升级的过程可以是:1、单片机上电执行BootLoader,2、BootLoader查找升级文件,3、若找到文件,擦除Flash中的部分扇区(存APP的),4、在擦除的扇区写入升级的文件,5、写入完成,读取数据检验是否出错,6、若数据一致,升级成功,删除升级文件,7、BootLoader程序跳转到APP程序执行。删除升级文件是为了下次上电后不再进行升级。
    9、所谓的跳转,可以理解为改变程序PC指针,指向APP程序扇区的起始地址。

    二、部分代码
    ————————————————
    1、主函数

    int main(void)
    {
    	HAL_Init();//STM32初始化
    	SystemClock_Config();//时钟配置
    	System_GPIOInit();//IO口配置
    	
    	#ifdef BOOTLOAD_DISPLAY_ENABLE
    	SystemColorInit();//显示屏配置
    	#endif
    	
    	System_LoadUpdateFile();//升级函数
    	while (1)
    	{
    		
    	}
    }
    

    2、升级函数

    void System_LoadUpdateFile(void)
    {
    	uint8_t res;	
    	if(bNandFlash_Error)//如果NandFlash错误,串口打印错误信息,跳转到用户程序
    	{
    		d_printf("NandFlash_Error jump\n");
    		BootLoad_Jump();//跳转函数
    		return;
    	}
    	if(bNo_FileSystem)//如果没有文件系统,串口打印错误信息,跳转到用户程序
    	{
    		d_printf("no file system jump\n");
    		BootLoad_Jump();//跳转函数
    		return;
    	}
    	if(f_open(&File, (char *)UPDATE_FILE_PATH, FA_READ)==FR_OK)//如果存在升级文件,开始执行升级
    	{
    		d_printf("update\n");
    		if(BootLoad_Program())//是否写入成功
    		{
    			f_close(&File);//关闭升级文件
    			res=f_unlink((char *)UPDATE_FILE_PATH);//删除升级文件
    			d_printfhex(res);d_printf("\n");
    			res=f_unlink((char *)UPDATE_DIR_PATH);//删除升级目录
    			d_printfhex(res);d_printf("\n");
    
    			BootLoad_Jump();//跳转函数
    		}
    		else
    		{
    			HAL_FLASH_Lock();//锁定Flash
    			d_printf("update fail\n");
    			f_close(&File);//关闭升级文件
    			BootLoad_Jump();//跳转函数
    		}		
    	}
    	else
    	{
    		d_printf("jump\n");
    		f_close(&File);
    		BootLoad_Jump();
    	}
    }
    

    3、重写Flash函数

    uint8_t BootLoad_Program(void)
    {
    	uint32_t BaseAddress=APPLICATION_ADDRESS;//APP地址
    	uint32_t i,br,datacnt=0;
    	uint8_t data8;
    	GlobalPtr32=(uint32_t *)BootBuff;
    	HAL_FLASH_Unlock();//解锁Flash
    	if(BootLoad_Erase()==false)//擦除Flash
    	{
    		return false;
    	}
    	d_printf("size:");d_printfhex32(File.fsize);d_printf("\n");
    	while(1)
    	{
    		f_read(&File,BootBuff,8192,(void *)&br);//读取升级文件
    		for (i=0;i<(br>>2);i++)
    		{
    			if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, BaseAddress, GlobalPtr32[i]) == HAL_OK)//写入升级文件
    			{
    				BaseAddress = BaseAddress +4;
    			}
    			else
    			{ 
    				d_printf("program err\n");
    				return false;
    			}
    		}
    		datacnt+=br;
    		if(datacnt>=File.fsize)//写入完成
    		{
    			break;
    		}
    	}
    	d_printf("verify\n");		//验证Flash中的内容与升级文件是否一致
    	f_lseek(&File,0);			//若一致代表升级成功
    	datacnt=0;					//若不一致代表升级失败
    	BaseAddress=APPLICATION_ADDRESS;
    	while(1)
    	{
    		f_read(&File,BootBuff,8192,(void *)&br);
    		for (i=0;i<br;i++)
    		{
    			data8 = *(__IO uint8_t*)BaseAddress;
    			if (data8 != BootBuff[i])
    			{
    				d_printf("error!\n");
    				return false;
    			}
    			BaseAddress ++;
    		}
    		datacnt+=br;
    		if(datacnt>=File.fsize)
    		{
    			break;
    		}
    	}
    	HAL_FLASH_Lock();//锁定Flash
    	return true;
    }
    

    4、跳转函数(从BootLoader中跳转到APP的main函数)

    void BootLoad_Jump(void)
    {
    	/* Check Vector Table: Test if user code is programmed starting from address 
    	"APPLICATION_ADDRESS" */
    	d_printfhex32((*(__IO uint32_t*)APPLICATION_ADDRESS));d_printf("\n");
    	if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    	{
    	JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS +4);
    	d_printfhex32(JumpAddress);d_printf("\n");
    	HAL_Delay(100);
    	Jump_To_Application = (pFunction) JumpAddress;
    	/* Initialize user application's Stack Pointer */
    	__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
    	Jump_To_Application();
    	}
    }
    
    展开全文
  • 蓝牙nrf51822空中升级

    2017-11-06 23:37:08
    对于单片机做的产品,要实现在线升级单片机内部一般是两段代码,一个是bootloader程序,一个是用户app程序,bootloader程序主要就是实现app升级的程序,它是单片机上电后首次运行的程序,app程序就是实现产品功能...
  • 51单片机蓝牙小车

    千次阅读 多人点赞 2020-07-30 08:58:28
    51单片机蓝牙小车(是我大二做的一个课程设计,小菜鸟一个,欢迎大家指正和参考。) 摘要 本次设计选择基于蓝牙遥控的多功能智能小车为对象。选用STC98C52RC单片机作为主控芯片,电机驱动采用L293N ,...
  • 蓝牙坦克上位机系统升级 蓝牙四驱战车-战神前奏 蓝牙四驱战车-驱动程序调试 蓝牙四驱战车-野外 蓝牙四驱战车-舵机变更 关于51单片机基础 keil uVersion4的安装卸载+破解 51单片机和HC05蓝牙模块对接成功,...
  • 今天用到的M203S模组可以解决嵌入式项目的常见问题,如下: 1、单片机的数据无法上传到云端...M203S模组下载FTP服务器上的单片机程序,并通过串口对单片机进行远程升级。 一、这款M203S的具体参数如下: ● 尺...
  • 【杰理AC692X】6种升级方法介绍

    千次阅读 2020-03-04 18:43:25
    一:使用强升工具升级 1是旧版升级工具,直接插入样机后,蓝灯灭,只有红灯亮,这就进入升级状态。 2是新版升级工具,使用方法: 此方法用CodeBlocks和批处理文件都可升级 二:USB/TF/SD升级 前提要读卡或读U能...
  • 2、固件升级命令响应 和 升级固件下载 二、RT-Thread STM32通用Bootloader + ota_downloader软件包oat升级 1、使用环境 2、RT OAT软件架构 3、STM32通用Bootloader 功能及使用 4、制作包含ota下载器功能的app ...
  • STM32在线升级

    2020-07-16 23:31:23
    有关STM32在线升级的相关资料,里面有官方程序、文档等
  • 单片机多功能调试助手分两个版本,分别是:含CH375 DLL版本、无DLL版本,它们的区别主要体现在是否对CH37X USB提供支持。为了减少对服务器的负担,现在单片机多功能调试助手只提供无DLL的版本,即不对CH372/CH375 USB...
  • 解决方法:修改设备的蓝牙连接间隔在10-20ms 连接间隔修改方法: 1.设备中有做好接收app发送指令后修改的:根据设备商提供的协议往设备上发送连接间隔时间(如ti芯片就有该功能) 2.芯片厂商没有的:在android5.0...
  • 蓝牙模块玩法

    千次阅读 2013-08-04 08:35:49
    蓝牙模块使用非常简单: 1、捣鼓蓝牙模块,将蓝牙模块设置成从机,通过下载的手机(android)蓝牙串口软件实现了数据的透明传输 方法:a、先将蓝牙模块通过USB转串口线连接到PC上,打开PC端串口调试助手,将波特率...
  • STM32在线升级OTA,看这一篇就够啦~

    千次阅读 多人点赞 2020-06-10 09:59:29
    STM32CubeMx开发之路—在线升级OTA(1/4)—基础知识 简介 本文主要讲解在线升级(OTA)的基础知识, 主要是针对IAP OTA从原理分析, 分区划分, 到代码编写和实验验证等过程阐述这一过程. 帮助大家加深对OTA的认识. 1. ...
  • 使用nordic官网的串口蓝牙时,若传输大量数据,会使单片机复位,从而蓝牙断开。 原因:在串口服务函数里发送蓝牙的数据,导致中断响应不及时,系统复位。 解决方法:串口服务函数不要发送蓝牙数据,只接受串口数据...
  • 说到低功耗蓝牙模块,少不了要说说低功耗蓝牙模块中最简单、最常见的通讯方式——透传。透传也叫串口透传,就是透明传输的意思,透传是一种工作方式,不是一种功能,一般出现在串口模块中(蓝牙串口透传模块是为了让...
1 2 3 4 5 ... 20
收藏数 547
精华内容 218
关键字:

蓝牙给升级单片机升级