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报错 提示需要安装依赖,试错逐步下载并安装…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...
