使用STM32F103的串口实现IAP程序升级功能

news2025/1/10 20:38:06

使用STM32F103的串口实现IAP程序升级功能


  • 🎬IAP程序烧录全过程演示:
    在这里插入图片描述

✨这几天折腾IAP升级功能,狂补了很多相关BootLoader相关的知识。本来最想实现IAP升级程序的方式是,基于SPI通讯的SD卡,借助挂载的FatFS文件系统,来实现对目标stm32芯片的自身程序的升级,奈何没有实现,只能求其次,先来通过官方现有的串口实现IAP程序升级功能的学习作为跳板。加深对flash读写操作流程的熟悉。

  • 🔧支持串口Ymodem传输协议的工具推荐:SecureCRT(建议安装9.0以下的,有和谐版本的,当然如果支持作者可以付费购买此工具使用)
  • 📍ST官方相关应用文档:文件编号:AN2557 《使用STM32F10xxx的USART实现在应用中编程》:https://www.st.com/resource/en/application_note/cd00161640-stm32f10x-in-application-programming-using-the-usart-stmicroelectronics.pdf
  • 🌿论坛下载地址https://www.stmcu.com.cn/Designresource/detail/document/705747
  • 📍ST官方相对应的示例程序包:https://www.st.com/content/st_com/en/search.html#q=AN2557-t=tools-page=1
    在这里插入图片描述

📓BootLoader相关知识

  • 🌿系统在上电或复位时通常都CPU是从地址0x00000000处开始执行,ARM内核把0x00000000地址上的存储单元映射到了新的地址0x08000000上。CPU存取0x08000000就是存取0x00000000上的物理存储单元。而在这个地址处安排的通常就是系统的BootLoader程序。
    在这里插入图片描述
  • 🌿BootLoader程序所占空间大小

🔖在每个工程通过编译后所产生的.map文件中可以找到相关的信息:

==============================================================================


Memory Map of the image

  Image Entry point : 0x08000131

  Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00001cac, Max: 0x00040000, ABSOLUTE)

    Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x00001c28, Max: 0x00040000, ABSOLUTE)

    Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x08000000   0x08000000   0x00000130   Data   RO         1821    RESET               startup_stm32f10x_hd.o
    0x08000130   0x08000130   0x00000000   Code   RO         1826  * .ARM.Collect$$$$00000000  mc_w.l(entry.o)
    0x08000130   0x08000130   0x00000004   Code   RO         1833    .ARM.Collect$$$$00000001  mc_w.l(entry2.o)
    0x08000134   0x08000134   0x00000004   Code   RO         1836    .ARM.Collect$$$$00000004  mc_w.l(entry5.o)
    0x08000138   0x08000138   0x00000000   Code   RO         1838    .ARM.Collect$$$$00000008  mc_w.l(entry7b.o)
    0x08000138   0x08000138   0x00000000   Code   RO         1840    .ARM.Collect$$$$0000000A  mc_w.l(entry8b.o)
    0x08000138   0x08000138   0x00000008   Code   RO         1841    .ARM.Collect$$$$0000000B  mc_w.l(entry9a.o)
    0x08000140   0x08000140   0x00000000   Code   RO         1843    .ARM.Collect$$$$0000000D  mc_w.l(entry10a.o)
    0x08000140   0x08000140   0x00000000   Code   RO         1845    .ARM.Collect$$$$0000000F  mc_w.l(entry11a.o)
    0x08000140   0x08000140   0x00000004   Code   RO         1834    .ARM.Collect$$$$00002712  mc_w.l(entry2.o)
  • 其中Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00001cac, Max: 0x00040000, ABSOLUTE)描述了BootLoader程序所占起始位置,以及空间。

  • ⚡要实现IAP功能,不仅需要原目标芯片里面的程序做好程序运行地址部署,还要在带准备升级的程序地址上,做好相对应的匹配才行。

  • 🌿已经写入程序的目标芯片,复位后,在从主闪存存储器启动模式下,程序都是地址:0x08000000开始运行。

在这里插入图片描述

🛠程序配置

  • 🌿对stm32目标芯片使用ST-linkV2烧录程序时,烧录地址时默认:0x8000000

在这里插入图片描述

  • 🌿对stm32目标芯片IAP升级程序:需要调用ASF转BIN文件指令,用于通过串口给目标芯片升级使用的程序文件。(当然这个程序可以是上面的原始工程,修改程序后,该偏移地址,生成BIN文件。来作为IAP升级文件,这里使用的时另外一个示例工程生成的IAP升级文件)
    在这里插入图片描述
    • 👉🏻调用asf转BIN文件指令:
C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe  --bin -o  ./STM32100E-EVAL/test.bin  ./STM32100E-EVAL/test.axf

在这里插入图片描述
在这里插入图片描述

⛳IAP升级和SecureCRT使用

  • 🔨SecureCRT配置串口以及参数:
    在这里插入图片描述

在这里插入图片描述

  • 📐Ymodem协议模式配置:
    在这里插入图片描述
    在这里插入图片描述

  • 🏳‍🌈本例程烧录原始程序后,如需进入IAP升级界面,需要在硬件复位的时候,按住PB9按键让其下拉到GND,原始程序时复位后,检测PB9如果是低电平,则进入IAP升级模式。

    • 🍁没有进入升级模式下,打印信息就是跑的主循环while中的代码。
      在这里插入图片描述
    • 🍁复位后,检测PB9如果是低电平,则进入IAP升级模式:
      在这里插入图片描述
  • 在进入IAP模式后,输入数字1,则进入等待上传升级文件模式:

  • 在这里插入图片描述

  • 🌿在SecureCRT界面菜单上找到Tranfer菜单下的Send Ymodem,进行BIN文件的上传。
    在这里插入图片描述

  • 🌿BIN文件上传成功后,打印信息:
    在这里插入图片描述

  • 🌿输入字符C,将程序跳转到新的目标程序地址。

  • 🌿到此已完成对芯片的IAP升级。

📝IAP main主程序

/**
  ******************************************************************************
  * @file    IAP/src/main.c
  * @author  MCD Application Team
  * @version V3.3.0
  * @date    10/15/2010
  * @brief   Main program body
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2010 STMicroelectronics</center></h2>
  */

/** @addtogroup IAP
  * @{
  */

/* Includes ------------------------------------------------------------------*/
#include "common.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
extern pFunction Jump_To_Application;
extern uint32_t JumpAddress;

static u8  fac_us=0;							//us延时倍乘数			   
static u16 fac_ms=0;							//ms延时倍乘数,在ucos下,代表每个节拍的ms数
/* Private function prototypes -----------------------------------------------*/
static void IAP_Init(void);
void delay_init(u8 SYSCLK);//延时初始化函数
void delay_us(u32 nus);//微秒延时
void delay_ms(u16 nms);//毫秒延时
/* Private functions ---------------------------------------------------------*/
void delay_init(u8 SYSCLK)
{
 	SysTick->CTRL&=~(1<<2);					//SYSTICK使用外部时钟源	 
	fac_us=SYSCLK/8;						//不论是否使用OS,fac_us都需要使用
	fac_ms=(u16)fac_us*1000;				//非OS下,代表每个ms需要的systick时钟数   
}	

//延时nus
//nus为要延时的us数.		    								   
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 				//时间加载	  		 
	SysTick->VAL=0x00;        				//清空计数器
	SysTick->CTRL=0x01 ;      				//开始倒数 	 
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	//等待时间到达   
	SysTick->CTRL=0x00;      	 			//关闭计数器
	SysTick->VAL =0X00;       				//清空计数器	 
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864 
void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;			//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL =0x00;           			//清空计数器
	SysTick->CTRL=0x01 ;          			//开始倒数  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));	//等待时间到达   
	SysTick->CTRL=0x00;      	 			//关闭计数器
	SysTick->VAL =0X00;       				//清空计数器	  	    
} 
/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{
    /* Flash unlock */
    FLASH_Unlock();

    /* Initialize Key Button mounted on STM3210X-EVAL board */
    STM_EVAL_PBInit(BUTTON_KEY, BUTTON_MODE_GPIO);
//    STM_EVAL_LEDInit(LED1);	//PC6
//    STM_EVAL_LEDInit(LED2);	//PC7
//    STM_EVAL_LEDInit(LED3);	//PC8
    STM_EVAL_LEDInit(LED4);  //PC9
		delay_init(72);		//延时初始化
    IAP_Init();	//这里其实做的就是对串口1进行初始化
    SerialPutString("Hello world \r\n");
    /* Test if Key push-button on STM3210X-EVAL Board is pressed PB7*/
    if(STM_EVAL_PBGetState(BUTTON_KEY)  == 0x00)	//GPIOB --> PB9
    {
        /* If Key is pressed */
        /* Execute the IAP driver in order to re-program the Flash */
//    IAP_Init();
        SerialPutString("\r\n======================================================================");
        SerialPutString("\r\n=              (C) COPYRIGHT 2010 STMicroelectronics                 =");
        SerialPutString("\r\n=                                                                    =");
        SerialPutString("\r\n=     In-Application Programming Application  (Version 3.3.0)        =");
        SerialPutString("\r\n=                                                                    =");
        SerialPutString("\r\n=                                   By MCD Application Team          =");
        SerialPutString("\r\n======================================================================");
        SerialPutString("\r\n\r\n");
        Main_Menu();
    }
    /* Keep the user application running */
    else
    {
        /* Test if user code is programmed starting from address "ApplicationAddress" */
      if(((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000) == 0x20000000)//检查栈顶地址是否合法.
				{
            /* Jump to user application */
            JumpAddress = *(__IO uint32_t*)(ApplicationAddress + 4);//用户代码区第二个字为程序开始地址(复位地址)	
            Jump_To_Application = (pFunction) JumpAddress;
            /* Initialize user application's Stack Pointer */
            __set_MSP(*(__IO uint32_t*) ApplicationAddress);//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
            Jump_To_Application();//跳转到APP.
					
        }
    }
		
    while(1)
    {

    delay_ms(500);
		SerialPutString("IAP main test!\r\n");
		STM_EVAL_LEDToggle(LED4);

    }
}

/**
  * @brief  Initialize the IAP: Configure RCC, USART and GPIOs.
  * @param  None
  * @retval None
  */
void IAP_Init(void)
{
    USART_InitTypeDef USART_InitStructure;

    /* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
    /* USART configured as follow:
          - BaudRate = 115200 baud
          - Word Length = 8 Bits
          - One Stop Bit
          - No parity
          - Hardware flow control disabled (RTS and CTS signals)
          - Receive and transmit enabled
    */
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    STM_EVAL_COMInit(COM1, &USART_InitStructure);
}

#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 can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

    /* Infinite loop */
    while(1)
    {
    }
}
#endif

/**
  * @}
  */

/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

📚程序源码

链接:https://pan.baidu.com/s/1bw2gjSS6_Vq48_PtkxakLQ 
提取码:298k

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680370.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++中的内存分区

目录 操作系统的内存区域 C内存分区模型 1. 程序运行前 2. 程序运行后 3. new 操作符的使用 操作系统的内存区域 text段&#xff1a;存储程序的二进制指令&#xff0c;即程序源码编译后的二进制代码data段&#xff1a;存储已被初始化的全局变量、常量bss段&#xff1a;存储…

ES-工作原理

前言 ​ 搜索引擎是对数据的检索&#xff0c;而数据总体分为两种&#xff1a;结构化数据和非结构化数据。而对于结构化数据&#xff0c;因为他们具有特定的结构&#xff0c;所以一般都是可以通过关系型数据库MySQL/oracle的二维表的方式存储和搜索&#xff0c;也可以建立索引。…

Redis的简单使用 (实现Session持久化)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、Redis数据类型的使用 1. 字符串&#xff…

Redis【入门篇】---- Redis的Java客户端-Jedis

Redis【入门篇】---- Redis的Java客户端-Jedis 1. Jedis快速入门2. Jedis连接池1. 创建Jedis连接池2. 改造原始代码 在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a;https://redis.io/docs/clients/ 其中Java客户端也包含很多&#xff1a; 标记为❤的就是推荐…

密码学证明方案寒武纪大爆发——扩容、透明性和隐私的变革潜力

1. 引言 前序博客有&#xff1a; ZKP大爆炸 本文主要参考&#xff1a; StarkWare 2023年6月博客 Cambrian Explosion of Cryptographic Proofs----The transformative potential for scalability, transparency, and privacy2023年3月Eli Ben-Sasson在The 13th BIU Winter …

JavaWeb之Cookie和Session

文章目录 CookieCookie基本介绍Cookie的基本使用Cookie的创建从服务器获取CookieCookie值的修改方案一方案二 浏览器查看CookieCookie声明控制Cookie有效路径Path的设置 SessionSession基本介绍Session的创建和获取&#xff08;id号&#xff0c;是否为新&#xff09;Session域数…

【SQL server关键字】

目录&#xff1a; 前言一、CREATE -- 创建二、INSERT INTO VALUES -- 插入数据三、SELECT FROM -- 查找数据1.SEKECT简单了解2.函数的使用3.选择列表与group by子句的对应4.exists子查询 四、UPDATE SET -- 更改数据五、ALTER -- 修改属性六、JOIN ON-- 链接多个表1. join初…

JDBC 望舒客栈项目 万字详解

目录 一、前言 二、项目结构 三、准备工作 1.建立子包 : 2.导入jar包 : 3.工具类 : 1 Utility工具类 2 JDBCUtilsDruid工具类 4.导入配置文件 : 5.引入BasicDAO : 四、项目主体 1.界面显示 : 1 代码演示 2 运行测试 2.用户登录 : 1 创建员工表employee 2 创建Ja…

JavaScript 事件加载有哪些应用场景?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言什么是JavaScript事…

VUE L MVVM模型 ③

目录 文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持✨ V u e j s Vuejs Vuejs M V V M MVVM MVVM模型Data与El的2种写法总结 文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持✨ ⡖⠒⠒⠒…

多线程中的wait和notify

1、wait和notify 由于线程之间是抢占式执行的&#xff0c;所以线程之间的执行先后顺序难以预知。但实际上是希望合理的协调多个线程之间的执行先后顺序。 完成这个协调工作&#xff0c;主要涉及到三个方法 *wait()/wait(long timeout);让当前线程进入等待状态。 *notify()/n…

【每日算法 数据结构(C++)】—— 02 | 数组的并交集(解题思路、流程图、代码片段)

文章目录 01 | &#x1f451; 题目描述02 | &#x1f50b; 解题思路交集并集 03 | &#x1f9e2; 代码片段交集并集 When you feel like giving up, remember why you started. 当你想放弃时&#xff0c;请记住为什么你开始 01 | &#x1f451; 题目描述 给你两个数组&#xff…

学习机组过程中的疑难问题与解决 -----(1)

本文章是在学习计算机组成原理过程中个人感觉需要理解与记忆的问题&#xff0c;还有一些在学习过程中自己产生的疑问以及解答,本文章可能排版不良&#xff0c;精力有限&#xff0c;还请见谅 第一章&#xff1a; &#xff08;1&#xff09;MAR的位数对应着存储单元的个数&#…

前端三剑客简介

文章目录 css的导入方式CSS选择器 JavascriptJavascript的引入方式输出语句变量数据类型javascript对象String对象 BOM对象DOM对象 W3C标准&#xff1a;网页主要由三部分组成 结构&#xff1a;html表现&#xff1a;css&#xff0c;层叠样式表行为&#xff1a;JavaScript css的…

VulnHub项目:Nagini

1、靶机地址&#xff1a; HarryPotter: Nagini ~ VulnHub 本篇为哈利波特死亡圣器系列的第二部&#xff0c;该靶机中存在3个魂器&#xff0c;依次找到它们&#xff0c;摧毁它们&#xff01; 2、渗透过程 首先收集靶机ip和确定攻击机ip&#xff0c;同时探测靶机开放端口 存在…

一个简单案例理解为什么在多线程的应用中要使用互斥锁

需求:使用10个线程,同时对一个值count进行加一操作,每个线程对count加100000次,最终使得count1000000 第一版代码:不加锁 ​​​lock.c #include<stdio.h> #include<pthread.h>#define THREAD_COUNT 10void *thread_callback(void *arg){int *pcount(int*)arg;in…

Unity例子——第一人称视角的角色控制器

本文是为了前文Unity四元组的举例示范&#xff0c;为了让读者更好地理解。 效果是实现一个可以由鼠标进行方向操作&#xff0c;键盘进行移动操作的任务。 此为效果视频&#xff1a; 1687597097844 下面进行教学&#xff1a; 一、搭建简单场景 新建一个场景&#xff0c;放置一…

SonarQube(sonar-scanner)+GitLab(gitlab-runner)实现提交代码自动扫描项目代码

安装gitlab-runner 插件挂载目录 mkdir -p /data/gitlab-runner/configdocker run -d --name gitlab-runner \ -v /data/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ --restart always \ --privilegedtrue \ gitlab/gitlab-r…

【数据库必备知识】索引和事务

数据库系列文章 1. 零基础带你快速上手SQL语言2. 玩转表及其数据3. 上手表设计 4. 索引和事务 目录 &#x1f4d6;前言 1. 索引 1.1 索引的概念 1.2 索引的作用 1.3 索引的使用场景 1.4 索引的使用 1.5 索引背后的数据结构(B树) 2. 事务 2.1 事务的概念 2.2 数据库使…