STM32F030 IAP升级研究

发布者:自在自由最新更新时间:2018-07-10 来源: eefocus关键字:STM32F030  IAP升级 手机看文章 扫描二维码
随时随地手机看文章

     在使用SMT32F103的时候,发现STM32是可以通过串口实现在线升级的(当然也可以通过文件的形式升级,原理都是一样的),正好在使用STM32F030,所以就想能不能在STM32F030上做一个在线升级的功能,通过一天的捣腾,还是搞出来了。后面想想了,还是把整个过程写成文档的形式分享出来。因为网上的资料都是零散的。

     主要的参考资料:

          《AN4657-STM32Cube_IAP_using_UART》

          《STM32串口IAP实验(战舰STM32开发板实验)http://www.openedv.com/thread-11494-1-1.html

           《STM32串口IAP实验(战舰STM32开发板实验)http://www.openedv.com/thread-11494-1-1.html

           《MDK STM32启动文件的详细分析(_main,map详细分析)http://www.openedv.com/thread-20164-1-1.html

           《stm32 IAP + APP ==双剑合一(HEX) https://wenku.baidu.com/view/cc93905d79563c1ec5da717a.html》     

           《keil .sct分散加载文件及其应用 http://blog.csdn.net/temp741852963/article/details/51668884

     平台:STM32F030F4 Flash 16K, RAM 4K

     功能:IAP程序和APP可以通过按键实现相互跳转的功能。

          

    1.  IAP升级流程:

     

    2. APP回到IAP的流程:

         

     为了区分当前程序是IAP还是APP,我用了一个LED灯来指示,在IAP程序下,LED灯300ms闪烁一次,在APP状态下LED灯1s闪烁一次。

    

     stm32f0系列MCU中断矢量表的定位跟STM32其它系列相比有点差异,即M0系列没有像其它M3/M4/M0+系列所具备的中断矢量表重定位寄存器,其中断矢量表不能借助矢量重定位寄存器简单修改实现。所以Stm32f0 IAP的过程会跟其它系列的STM32芯片的IAP动作有所不同。但是stm32有两种启动方式,一种是从flash启动,默认地址为0x0800000,一种是从RAM启动,默认地址为0x20000000,所以可以让IAP从Flash启动,而APP从RAM启动,通过接口SYSCFG_MemoryRemapConfig配置。由于我们是把APP代码直接拷贝到0x0800000+offset的地址上去的,其中断向量表在Flash里面,所以在APP启动的时候,需要把中断向量表拷贝到RAM的起始地址中去。

     

     

     3. IAP源码和工程配置

     主函数如下:

          int main(void)

{

#ifdef FLASH_UPDATE_FLAG

    //读取是否升级成功的标志

    JTHAL_STMFLASH_Read(APP_UPDATE_FLAG_ADDR, &s_u16AppIsUpdateFlag, 1);

    if (s_u16AppIsUpdateFlag != 1)   //没有升级成功,进入等待升级的状态

    {

        s_u16AppIsUpdateFlag = 0;

        iLedInit();

        iKeyInit();

    }

    else   //升级成功,直接跳转到app处执行

    {

        iJumpToAppStartFun(APP_START_ADDR);

    }

#else

    SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_Flash); //设置成flash启动

    iLedInit();

    iKeyInit();

#endif

    while (1)

    {

        // 通过按键去更新APP

        if (s_u8KeyPress == 1)

        {

            s_u8KeyPress = 0;

            //开始更新APP

            memcpy(s_au8AppStartAddr, s_u8UartBuff+4, 4);

            //防止大小端问题

//        s_u32Val = 0;

//        s_u32Val |= (s_u8UartBuff[7] << 24);

//        s_u32Val |= (s_u8UartBuff[6] << 16);

//        s_u32Val |= (s_u8UartBuff[5] << 8);

//        s_u32Val |= (s_u8UartBuff[4] << 0);

            s_u32Val = *((uint32 *)(s_au8AppStartAddr));

            if((s_u32Val & 0xFF000000) == 0x08000000) // APP 数据有效性判断

            {

                while (wLen != sizeof(s_u8UartBuff))

                {

                    if (sizeof(s_u8UartBuff) - wLen >= 1024)

                        wTmp = 1024;

                    else

                        wTmp = sizeof(s_u8UartBuff) - wLen;

                    JTHAL_STMFLASH_Write(APP_START_ADDR+wLen, (uint16 *)(s_u8UartBuff+wLen), (wTmp+1)/2);//更新FLASH代码

                    wLen += wTmp;

                }

#ifdef FLASH_UPDATE_FLAG

                s_u16AppIsUpdateFlag = 1;

                JTHAL_STMFLASH_Write(APP_UPDATE_FLAG_ADDR, &s_u16AppIsUpdateFlag, 1);

                NVIC_SystemReset();

#else   

                goto JUMP_TO_APP;

#endif

            }

        }

        // LED 快速闪烁

        iLedON();

        iDelayMs(500);

        iLedOff();

        iDelayMs(500);

    }

JUMP_TO_APP:

    EXTI_DeInit();  //关闭外部中断

    SYSCFG_DeInit();

    RCC_DeInit();

    iJumpToAppStartFun(APP_START_ADDR);

}

#define APP_START_ADDR     0x08002800      //第一个应用程序起始地址(存放在FLASH)

typedef  void (*APP_START_F)(void);              //定义一个函数类型的参数.

static APP_START_F s_pfnAppStart = NULL;

//跳转到应用程序段

//appxaddr:用户代码起始地址.

static void iJumpToAppStartFun(uint32 appxaddr)

{

    s_u32Val = *((vu32*)appxaddr);

    if((s_u32Val & 0x2FFE0000) == 0x20000000)  //检查栈顶地址是否合法.

    {

        s_pfnAppStart =(APP_START_F)*(uint32*)(appxaddr+4);       //用户代码区第二个字为程序开始地址(复位地址)

        __set_MSP(*(__IO uint32_t*) appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)

        s_pfnAppStart();                                 //跳转到APP.

    }

}

     注意:

          1. 如果是通过非重启的方式跳转到APP,跳转之前一定要清除中断,RCC相关配置,因为跳转,相当于调用函数,配置的寄存器值不会改变,开启的中断也不会自动关闭,如果APP中没有编写相同的中断函数,触发中断的时候就挂掉了。

          2.如果是通过非重启的方式回到IAP,那么在执行IAP之前,需要设置为Flash启动模式。

     IAP工程配置:

          

     我这里分配的是10K的flash空间给IAP,这里最好是配置一下。

     

     4.APP源码和工程配置

 int main(void)

{

    iRemapIrqVector(); //拷贝中断向量到RAM,并设置为RAM启动模式

    iKeyInit();

    iLedInit();

    while (1)

    {

        if (s_u8KeyPress == 1)

        {

            s_u8KeyPress = 0;

#ifdef FLASH_UPDATE_FLAG

            //如果通过这种方式,在IAP里面不需要去设置启动模式

            s_u16AppIsUpdateFlag = 0;

            JTHAL_STMFLASH_Write(APP_UPDATE_FLAG_ADDR, &s_u16AppIsUpdateFlag, 1);

            NVIC_SystemReset();

#else

            // 如果通过这种方式去跳转到IAP,在IAP里面一定要设置启动模式为flash模式

            //否则会出现死机的情况

            EXTI_DeInit();  //关闭外部中断

            SYSCFG_DeInit();

            RCC_DeInit();

            iJumpToAppStartFun(APP_START_ADDR);

#endif

        }

        // LED慢闪烁

        iLedOn();

        iDelayMs(10000);

        iLedOff();

        iDelayMs(10000);

    }

}

#if   (defined ( __CC_ARM ))

__IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));

#elif (defined (__ICCARM__))

#pragma location = 0x20000000

__no_init __IO uint32_t VectorTable[48];

#elif defined   (  __GNUC__  )

__IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable")));

#elif defined ( __TASKING__ )

__IO uint32_t VectorTable[48] __at(0x20000000);

#endif

// 重映射中断向量

static void iRemapIrqVector(void)

{

    // 中断向量重映射

    unsigned char i = 0;

    for(i = 0; i < 48; i++)

    {

        VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2)); //中断向量是一个指针,每个占4个字节

    }

    /* Enable the SYSCFG peripheral clock*/

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //这个一定要有

    /* Remap SRAM at 0x00000000 */

    SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM); //设置为RAM启动模式

}

工程配置:



需要勾上Use Memory Layout from Target Dialog选项,否则会出现..\OBJ\STM32F030.axf: Error: L6985E: Unable to automatically place AT section main.o(.ARM.__AT_0x20000000) with required base address 0x20000000. Please manually place in the scatter file using the --no_autoat option.

的问题。 

     

     如果完全按照网上的资料,把APP代码通过串口全部接收到本地(RAM),然后校验,然后写入到flash,这样是行不通的,RAM太小了。所以我就把APP bin文件的内容全部拷贝到一个const数组中,然后通过按键写入到Flash升级。然后通过按键从IAP->APP->IAP切换。至于怎么用4K的RAM去升级大于4K的程序APP,我提供一个思路。

     把APP.bin分成若干个包,每个包包含包编号,包大小,包检验,bin文件总大小。stm32f0收到升级命令后,开始通过包编号顺序去请求包,校验成功后,写入到对应的flash区域,然后请求下一包,直到完成。

参考代码下载地址: 点击打开链接 (http://download.csdn.net/detail/losthome/9820748)


关键字:STM32F030  IAP升级 引用地址:STM32F030 IAP升级研究

上一篇:stm32 总中断的打开与关闭
下一篇:STM32之bootloader

推荐阅读最新更新时间:2024-03-16 16:08

如何建一个STM32F030工程模板(标准库版)
1.1建立工程前准备 (1)下载stm32f0标准库文件 在开始建立工程模板前需要先到ST官网下载最新的标准外设库,网址为https://www.st.com/en/embedded-software/stsw-stm32048.html 在网页中找到下载链接,点击下载。(需要登录账号或者填一些个人信息,这里自己操作) 下载下来的压缩包解压后得到STM32F0xx_StdPeriph_Lib_V1.5.0这个文件夹,里面包含STM32F0XX外设功能的例程及内核、外设相关的库文件。 (2)安装stm32f0芯片包 Keil5需要自己下载安装芯片包,才能在建立工程的时候选择自己要的MCU型号,若还没安装可到Kei
[单片机]
如何建一个<font color='red'>STM32F030</font>工程模板(标准库版)
STM32F030 WWDG使用结论
使用STM32F030的WWDG,发现其在STOP下面跟STM8S的休眠模式的情况一样,不会对MCU进行复位. 贴上看门狗代码: /*************************************************************************************** **************************************************************************************** * FILE : wdog_drv.c * Description : * * Copyright (c) 2015 by
[单片机]
STM32F030模拟串口
由于项目需要用到很多串口,而STM32F030的串口资源较少,所以需要自己写模拟串口,下面是过程。 首先进行初始化: #define Auart1RxEXTIPort EXTI_PortSourceGPIOA #define Auart1RxEXTIPin EXTI_PinSource5 #define Auart1RxLineEXTI_Line5 #define Auart1RCC RCC_AHBPeriph_GPIOA #define Auart1Port GPIOA #define Auart1TxPin GPIO_Pin_6 #define Auart1RxPin GPIO_Pin_5 #define Auar
[单片机]
STM32F030_I2C详细配置说明
本文主要总结STM32F030_I2C的相关功能与源代码分享。 I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。I2C 总线支持任何IC 生产工艺(CMOS、双极型)。通过串行数据(SDA)线和串行时钟 (SCL)线在连接到总线的器件间传递信息。每个器件都有一个唯一的地址识别(无论是微控制器——MCU、LCD 驱动器、存储器或键盘接口),而且都可以作为一个发送器或接收器(由器件的功能决定)。除了发送器和接收器
[单片机]
STM32F030_I2C详细配置说明
STM32f030IAP时遇到的问题
bootloard中的跳转和F1(M3内核)的没什么区别 这里的这句话 if((((__IO uint32_t)IAP_ADDR)&0x2FFE0000)==0x20000000) 并不是‘与’“&”操作,而是取出IAP_ADDR的值,判断栈顶地址 特别注意的地方 在bootloard跳转过去的程序需要添加 memcpy((void*)0x20000000,(void*)IAP_ADDR,0xB4); __HAL_SYSCFG_REMAPMEMORY_SRAM(); 在M3内核中可以通过操作VTOR寄存器来重映射中断向量表 SCB- VTOR = FLASH_BASE | 0x10000; /* Vecto
[单片机]
<font color='red'>STM32f030</font>弄<font color='red'>IAP</font>时遇到的问题
STM32F030_RTC详细配置说明
今天总结RTC(Real Time Clock)实时时钟相关的知识。在进行RTC的讲解前,我先对BKP进行一个简单的讲解。 STM32的RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变。 STM32F0的RTC模块和F3的RTC模块最大区别在于F0模块中有“DATE”和“TIME”寄存器,也就是可以直接读取寄存器里面的值,而F3是秒计数寄存器的值,需要通过相关算法下才能得到时间的值。 本文提供的软件工程里面用到BKP的配置,主要是用于掉电保持RTC数值(第一次上电初始化RTC,后面就不用初始化)。例程是在第一次初始化RTC值为:2016年2月29日 周一
[单片机]
STM32F030_RTC详细配置说明
基于STM32F030 Demo板的开发概要(问题解决)
问题出现环境: 1.使用STM32F030 Demo板下载厂家给的LED测试例程时; 2.使用Keil-MDK-uVison5版本; 3.准备Build all时。 问题出现现象: 1.系统无法创建可烧写文件,即Target not created。显示Error为: ..SystemCMSIScore_cm0.h(127): error: #5: cannot open source input file core_cmInstr.h : No such file or directory. 类似问题探究: 1...SystemCMSIScore_cm0.h(127): error: #5: ca
[单片机]
基于<font color='red'>STM32F030</font> Demo板的开发概要(问题解决)
基于P89C51RD2 IAP功能的数据存取与软件升级
摘要:分析Boot ROM中的部分源代码,重点是IAP功能以及ISP和IAP的相互关系;应用IAP功能将剩余程序空间转化为数据空间,以及自编ISP程序来实现仪器的软件升级。 关键词:P89C51RD2 Boot ROM IAP(ISP)功能 软件升级 1 概述 P89C51RD2是Philips公司的80C51系列单片机中的佼佼者,具有1KB的片上RAM和64KB的片上内存;具有3种编程方式,即在系统编程ISP(InSystem Programming)、在应用中编程IAP(In-Application Programming)以及通过商用编程器的并行编程。ISP是指电路板上的空白器件可以编程写入最终用户代码,而不需要从电路
[应用]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved