STM32补充——IAP
0 前置知识:
FLASH相关内容:前往STM32补充——FLASH
STM32三种烧录方式(看看就行):
1.ISP:In System Programming(在系统编程)
执行芯片厂商的 Bootloader 程序进入 ISP 模式,进入ISP 模式后,用户可选择官方提供的烧录通信接口(如:串口),并配合ISP 编程工具(如:FlyMcu)对闪存进行烧录。
2.ICP:In Circuit Programing(在线编程)
使用IDE并通过JTAG/SWD接口对闪存进行烧录。
3.IAP:In Application Programming(在应用编程)
使用用户的应用程序(也称为:Bootloader程序)对闪存进行烧录。该应用程序需要通过一种通信接口(如:IO口\USB\CAN\UART\I2C\SPI等)对闪存进行烧录(即把APP程序烧录到闪存)。IAP 通常被开发者用作远程升级的手段。
1.IAP原理介绍

1.1 程序正常运行过程:

①跳转到复位中断服务函数
②跳转到main函数
③发生中断时,会强制跳转到中断向量表
④根据中断源,跳转到对应的中断服务函数
⑤执行中断服务程序后,回到main函数原来的位置执行
1.2 加入IAP后程序运行过程

①执行复位中断服务函数后,跳转到IAP程序main函数
②执行IAP过程,跳转到APP中断向量表
③跳转到APP的main函数
④发生中断时,会强制跳转到地址为0x08000000的中断向量表
⑤根据设置的中断向量表偏移量,跳转到APP对应的中断服务函数
⑥执行中断服务程序后,回到main函数原来的位置执行
2.APP的生成步骤
- 设置APP程序的起始地址和存储空间大小
- 设置中断向量表偏移量(设置SCB->VTOR的值即可)
- 设置MDK编译后运行fromelf.exe,生成.bin文件(在User选项卡,设置编译后调用fromelf.exe,根据.axf文件生成.bin文件,用于IAP更新)
注意:APP程序的起始地址可在Keil上直接设置,但中断向量表偏移量需要另外手动设置
2.1 设置APP程序的起始地址和存储空间大小
设置APP起始地址要注意的点:
1,APP要在BootLoader后面
2,内存不能出现重叠
3,偏移量是0x200的倍数
FLASH_APP:

SRAM_APP:


①Bootloader程序运行预留4KB SRAM
②存放APP程序预留48KB SRAM
③APP程序运行预留12KB SRAM
2.2 设置中断向量表偏移量
APP存放在FLASH中的设置方法:
SCB->VTOR = FLASH_BASE | 0x10000;
APP存放在SRAM中的设置方法:
SCB->VTOR = SRAM_BASE | 0x1000;
2.3 设置MDK编译后运行fromelf.exe,生成.bin文件

D:\MDK5.36\ARM\ARMCC\bin\fromelf --bin -o ..\..\Output\@L.bin ..\..\Output\%L
3. 代码
iap模块:
iapfun jump2app;
uint16_t g_iapbuf[1024]; /* 2K字节缓存 *//*** @brief IAP写入APP BIN* @param appxaddr : 应用程序的起始地址* @param appbuf : 应用程序CODE* @param appsize : 应用程序大小(字节)* @retval 无*/
void iap_write_appbin(uint32_t appxaddr, uint8_t *appbuf, uint32_t appsize)
{uint16_t t;uint16_t i = 0;uint16_t temp;uint32_t fwaddr = appxaddr; /* 当前写入的地址 */uint8_t *dfu = appbuf;for (t = 0; t < appsize; t += 2){temp = (uint16_t)dfu[1] << 8;temp |= (uint16_t)dfu[0];dfu += 2; /* 偏移2个字节(FLASH每次写入两个字节) */g_iapbuf[i++] = temp;if (i == 1024){i = 0;stmflash_write(fwaddr, g_iapbuf, 1024);fwaddr += 2048; /* 偏移2048 16 = 2 * 8 所以要乘以2 */}}if (i){stmflash_write(fwaddr, g_iapbuf, i); /* 将最后的一些内容字节写进去 */}
}/*** @brief 跳转到应用程序段(执行APP)* @param appxaddr : 应用程序的起始地址* @retval 无*/
void iap_load_app(uint32_t appxaddr)
{if (((*(volatile uint32_t *)appxaddr) & 0x2FFE0000) == 0x20000000) /* 检查栈顶地址是否合法.可以放在内部SRAM共64KB(0x20000000) */{/* 用户代码区第二个字为程序开始地址(复位地址) */jump2app = (iapfun) * (volatile uint32_t *)(appxaddr + 4);/* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */sys_msr_msp(*(volatile uint32_t *)appxaddr);/* 跳转到APP */jump2app();}
}
main函数:
int main(void)
{uint8_t t;uint8_t key;uint32_t oldcount = 0; /* 老的串口接收数据值 */uint32_t applenth = 0; /* 接收到的app代码长度 */uint8_t clearflag = 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);lcd_show_string(30, 70, 200, 16, 16, "IAP TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "KEY_UP: Copy APP2FLASH!", RED);lcd_show_string(30, 130, 200, 16, 16, "KEY1: Run FLASH APP", RED);lcd_show_string(30, 150, 200, 16, 16, "KEY0: Run SRAM APP", RED);while (1){if (g_usart_rx_cnt){if (oldcount == g_usart_rx_cnt) /* 新周期内,没有收到任何数据,认为本次数据接收完成 */{applenth = g_usart_rx_cnt;oldcount = 0;g_usart_rx_cnt = 0;printf("用户程序接收完成!\r\n");printf("代码长度:%dBytes\r\n", applenth);}else oldcount = g_usart_rx_cnt;}t++;delay_ms(100);if (t == 3){LED0_TOGGLE();t = 0;if (clearflag){clearflag--;if (clearflag == 0){lcd_fill(30, 190, 240, 210 + 16, WHITE); /* 清除显示 */}}}key = key_scan(0);if (key == WKUP_PRES) /* WKUP按下,更新固件到FLASH */{if (applenth){printf("开始更新固件...\r\n");lcd_show_string(30, 190, 200, 16, 16, "Copying APP2FLASH...", BLUE);if (((*(volatile uint32_t *)(0X20001000 + 4)) & 0xFF000000) == 0x08000000) /* 判断是否为0X08XXXXXX */{iap_write_appbin(FLASH_APP1_ADDR, g_usart_rx_buf, applenth); /* 更新FLASH代码 */lcd_show_string(30, 190, 200, 16, 16, "Copy APP Successed!!", BLUE);printf("固件更新完成!\r\n");}else{lcd_show_string(30, 190, 200, 16, 16, "Illegal FLASH APP! ", BLUE);printf("非FLASH应用程序!\r\n");}}else{printf("没有可以更新的固件!\r\n");lcd_show_string(30, 190, 200, 16, 16, "No APP!", BLUE);}clearflag = 7; /* 标志更新了显示,并且设置7*300ms后清除显示 */}if (key == KEY1_PRES) /* KEY1按键按下, 运行FLASH APP代码 */{if (((*(volatile uint32_t *)(FLASH_APP1_ADDR + 4)) & 0xFF000000) == 0x08000000) /* 判断FLASH里面是否有APP,有的话执行 */{printf("开始执行FLASH用户代码!!\r\n\r\n");delay_ms(10);iap_load_app(FLASH_APP1_ADDR);/* 执行FLASH APP代码 */}else{printf("没有可以运行的固件!\r\n");lcd_show_string(30, 190, 200, 16, 16, "No APP!", BLUE);}clearflag = 7; /* 标志更新了显示,并且设置7*300ms后清除显示 */}if (key == KEY0_PRES) /* KEY0按下 */{printf("开始执行SRAM用户代码!!\r\n\r\n");delay_ms(10);if (((*(volatile uint32_t *)(0x20001000 + 4)) & 0xFF000000) == 0x20000000) /* 判断是否为0X20XXXXXX */{iap_load_app(0x20001000); /* SRAM地址 */}else{printf("非SRAM应用程序,无法执行!\r\n");lcd_show_string(30, 190, 200, 16, 16, "Illegal SRAM APP!", BLUE);}clearflag = 7; /* 标志更新了显示,并且设置7*300ms后清除显示 */}}
}
相关文章:
STM32补充——IAP
0 前置知识: FLASH相关内容:前往STM32补充——FLASH STM32三种烧录方式(看看就行): 1.ISP:In System Programming(在系统编程) 执行芯片厂商的 Bootloader 程序进入 ISP 模式&…...
Jetson Xavier NX (ARM) 使用 PyTorch 安装 Open3D-ML 指南
由于 Jetson 为 ARM64 (aarch64) 的系统架构,所以不能用 pip install 直接安装,需要通过源码编译。 升级系统 JetPack 由于 Open3D-ML 目前只支持 CUDA 10.0 以及 CUDA 11.*,并且 JetPack 的 CUDA 开发环境只有10.2、11.4以及12.2࿰…...
【C++高并发服务器WebServer】-1:Linux中父子进程fork创建及关系、GDB多进程调试
本文目录 一、进程创建二、GDB多进程调试 一、进程创建 在Linux中输入man 2 fork可以查看man文档中的fork的相关函数信息。 fork的作用就是创建一个子进程。 通过fork我们可以知道,创建子进程的时候,复制父进程的信息。 我们看看翻译的man文档信息&am…...
C语言数组详解:从基础到进阶的全面解析
在C语言中,数组是一种基本的数据结构,用于存储多个相同类型的数据。数组的引入使得C语言能够高效地存储和操作大量数据。在任何一个C语言程序中,数组都发挥着极其重要的作用。无论是在算法实现、数据存储、还是在复杂程序的设计中,…...
docker的前世今生
docker来自哪里? 从我们运维部署的历史来看,宿主机从最初的物理机到虚拟机,再到docker,一步步演进到现在。技术演进其实是为了解决当前技术的痛点,那我们来看看有哪些痛点以及如何克服痛点的。 物理机 一般来说&…...
python实现施瓦茨-克里斯托费尔【全网首个】根据用户输入推测函数
上代码: from sympy import symbols, integrate, simplify from sympy.plotting import plotn int(input("n:")) if n < 2:print("Error: Must n > 2") i 0 a [] aef [] A [] x, y symbols(x y) z, w symbols(z w)while i < n…...
c语言中的数组(上)
数组的概念 数组是⼀组相同类型元素的集合; 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。 数组中存放的多个数据,类型是相同的。 数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。 数组创建 在C语言…...
Unity3D仿星露谷物语开发25之创建时钟界面
1、目标 在时钟界面显示当前时钟信息,同时设置特殊按钮可以快速推进时间用于测试。 2、创建GameClock.cs脚本 在Assets -> Scripts -> TimeSystem目录下创建GameClock.cs脚本。 代码如下: using System.Collections; using System.Collections…...
数据结构测试题1
一、选择题: 1.若长度为n的钱性表采用顺序存储结构,删除它的第i数据元素之前,需要先依次向前移动( )个数据元素。( C ) A .n-i B.ni C.n-i-1 D.n-i1 2.在单链表中,已知q指的结点是p指的结点的直接前驱结点&am…...
android wifi AsyncChannel(WifiManager和WifiP2pManager)
AynscChannel的讲解 [Android]AsyncChannel介绍-CSDN博客 WifiP2pManager里的channel的使用理解 WifiP2pManager.java public void createGroup(Channel c, ActionListener listener) {checkChannel(c);c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.NETWORK_ID_PE…...
【Image Captioning】DynRefer
DynRefer是由中国科学院大学于2024年提出的用于1种用于区域级多模态任务的模型。DynRefer 通过模拟人类视觉认知过程,显著提升了区域级多模态识别能力。通过引入人眼的动态分辨率机制, 能够以同时完成区域识别、区域属性检测和区域字幕生成任务。 文章链…...
Midjourney基础-常用修饰词+权重的用法大全
用好修饰词很关键 Midjourney要用除了掌握好提示词的写法,按照上一篇《做Midjourney最好图文教程-提示词公式以及高级参数讲解》画面主体 场景氛围 主体行为 构图方式 艺术风格 图像质量。 要画出有质感的内容我们必须要掌握好“修饰词”,这些修饰…...
没有屋檐的房子-023粪堆旁边的舞蹈
爱美是天性,贫苦的农村人也一样,贫苦的时代也一样。 本世纪,广场舞在华夏大地遍地开花,甚至都传到了外面。但是广场舞这种舞蹈形式并不是互联网时代的特产,也不是电声设备日益高级和普及时代的特产,更不是大…...
基于Docker的Kafka分布式集群
目录 1. 说明 2. 服务器规划 3. docker-compose文件 kafka{i}.yaml kafka-ui.yaml 4. kafka-ui配置集群监控 5. 参数表 6. 测试脚本 生产者-异步生产: AsyncKafkaProducer1.py 消费者-异步消费: AsyncKafkaConsumer1.py 7. 参考 1. 说明 创建一个本地开发环境所需的k…...
【博客之星】年度总结:在云影与墨香中探寻成长的足迹
🐇明明跟你说过:个人主页 🔖行路有良友,便是天堂🔖 目录 一、年度回顾 1、创作历程 2、个人成长 3、个人生活与博客事业 二、技术总结 1、赛道选择 2、技术工具 3、实战项目 三、前景与展望 1、云原生未来…...
SpringBoot的Swagger配置
一、Swagger配置 1.添加依赖 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.2</version> </dependency> 2.修改WebMvcConfig Slf4j Configurat…...
machine learning knn算法之使用KNN对鸢尾花数据集进行分类
通过导入必要的scikit-learn导入必要的库,加载给定的数据,划分测试集和训练集之后训练预测和评估即可 具体代码如下: import numpy as np from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split f…...
C语言练习(16)
猴子吃桃问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第10天早上想再吃时,见只剩一个桃子了…...
SOAFEE 技术研讨会:汽车软件定义与自动驾驶技术探讨
在本次技术研讨会上,来自汽车与科技领域的专家们围绕汽车软件定义及自动驾驶技术展开了深入交流与探讨。从 SOAFEE 蓝图计划的创新性理念,到 Autoware 开源项目及 Open AD Kit 在实际应用中的探索,再到 Edge Workload Abstraction and Orches…...
R语言学习笔记之开发环境配置
一、概要 整个安装过程及遇到的问题记录 操作步骤备注(包含遇到的问题)1下载安装R语言2下载安装RStudio3离线安装pacman提示需要安装Rtools4安装Rtoolspacman、tidyfst均离线安装完成5加载tidyfst报错 提示需要安装依赖,试错逐步下载并安装…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
