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的生成步骤

  1. 设置APP程序的起始地址和存储空间大小
  2. 设置中断向量表偏移量(设置SCB->VTOR的值即可)
  3. 设置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后清除显示 */}}
}

 

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

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

相关文章

k8s的CICD实施项目

环境需求&#xff1a; 目前领导需要做一个需求&#xff0c;临时把我从运维岗位&#xff0c;把我调度到到专家组让我主导cicd的项目实施 目前环境资源 k8s环境&#xff0c;28台服务器&#xff0c;上面是k8s集群&#xff0c;要实施一个测试环境的cicd以及一个生产环境的cicd gitl…

【线性代数】基础版本的高斯消元法

[精确算法] 高斯消元法求线性方程组 线性方程组 考虑线性方程组&#xff0c; 已知 A ∈ R n , n , b ∈ R n A\in \mathbb{R}^{n,n},b\in \mathbb{R}^n A∈Rn,n,b∈Rn&#xff0c; 求未知 x ∈ R n x\in \mathbb{R}^n x∈Rn A 1 , 1 x 1 A 1 , 2 x 2 ⋯ A 1 , n x n b 1…

AIGC视频生成模型:Runway的Gen系列模型

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Runway开发的视频生成模型Gen系列&#xff0c;包括Gen-1、Gen-2和Gen3 Alpha等&#xff0c;这些模型每次发布都震惊AI圈&#xff0c;荣获多个视频生成的…

【JVM-9】Java性能调优利器:jmap工具使用指南与应用案例

在Java应用程序的性能调优和故障排查中&#xff0c;jmap&#xff08;Java Memory Map&#xff09;是一个不可或缺的工具。它可以帮助开发者分析Java堆内存的使用情况&#xff0c;生成堆转储文件&#xff08;Heap Dump&#xff09;&#xff0c;并查看内存中的对象分布。无论是内…

【基于无线电的数据通信链】Link 11 仿真测试

〇、废话 Link 11 仿真测试 涉及多个方面&#xff0c;包括信号仿真、协议模拟、数据链路层的仿真以及网络性能评估等。Link 11 是一种基于 HF&#xff08;高频&#xff09; 或 UHF&#xff08;超高频&#xff09; 波段的无线通信协议&#xff0c;主要用于军事通信系统中。为了…

AG32 FPGA 的 Block RAM 资源:M9K 使用

1. 概述 AG32 FPGA 包含了 4 个 M9K 块&#xff0c;每个 M9K 块的容量为 8192 bits&#xff0c;总计为 4 个 M9K&#xff08;4K bytes&#xff09;。这使得 AG32 的内部存储非常适合嵌入式应用&#xff0c;能够有效地利用片上资源。 M9K 参数 参考自《AGRV2K_Rev2.0.pdf》。…

【算法笔记】力扣热题100(LeetCode hot-100)438. 找到字符串中所有字母异位词 滑动窗口

力扣热题100&#xff08;LeetCode hot-100&#xff09;之 438. 找到字符串中所有字母异位词 本文主要记录算法思路&#xff0c;着急要答案的同学可以直接跳转到最后的代码。 题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子…

Hadoop•搭建完全分布式集群

听说这里是目录哦 一、安装Hadoop&#x1f955;二、配置Hadoop系统环境变量&#x1f96e;三、验证Hadoop系统环境变量是否配置成功&#x1f9c1;四、修改Hadoop配置文件&#x1f36d;五、分发Hadoop安装目录&#x1f9cb;六、分发系统环境变量文件&#x1f368;七、格式化HDFS文…

【机器人学】2-3.六自由度机器人运动学逆解-工业机器人【附MATLAB代码】

解析解推导 假设有一工业机器人参数如下图所示&#xff1a; matlab代码 clc;clear; %带入机器人初始值 d1 0.670; d4 1.280; d6 0.215;a2 0.312; a3 1.075; a4 0.225;Position[288.1, -433.1, 2832,96.9158, -29.6162, 109.3547]; px Position(1)/1000; py Positio…

ARM学习(42)CortexM3/M4 MPU配置

笔者之前学习过CortexR5的MPU配置,现在学习一下CortexM3/M4 MPU配置 1、背景介绍 笔者在工作中遇到NXP MPU在访问异常地址时,就会出现总线挂死,所以需要MPU抓住异常,就需要配置MPU。具体背景情况可以参考ARM学习(41)NXP MCU总线挂死,CPU could not be halted以及无法连…

PIC单片机HEX文件格式分析

在调试PIC单片机在bootloader程序时&#xff0c;需要将hex文件转换为bin文件&#xff0c;在转换之前先了解一下hex文件中数据是如何定义的。 直接打开一个LED灯闪烁的程序生成的hex文件&#xff0c;芯片型号为PIC18F46K80 可以看到每条数据都是由6部分组成的&#xff0c;下面分…

用户中心项目教程(四)---Vue脚手架完成前端初始化

目录 1.项目的创建 2.使用开发工具打开 3.项目运行方法 4.使用按钮组件 5.全局注册 6.如何进行组件的测试 7.使用组件的效果展示 8.关于这个vue项目内容的说明 1.项目的创建 这个前提你是你完成了我的教程&#xff08;三&#xff09;里面的相关配置&#xff0c;不然你可…

【GitHub】登录时的2FA验证

一、如何进行2FA认证 1.在你的浏览器中下载 Authenticator身份验证插件 2.使用身份验证器添加凭证 2.1 使用身份验证器扫描验证二维码 选择扫描二维码

目标跟踪算法发展简史

单目标跟踪&#xff08;Single Object Tracking&#xff0c;SOT&#xff09;是计算机视觉领域中的一个重要研究方向&#xff0c;旨在在视频序列中持续定位并跟踪一个特定目标。随着计算机视觉和机器学习技术的飞速发展&#xff0c;单目标跟踪算法经历了从经典方法到深度学习的演…

【Java设计模式-7】责任链模式:我是流水线的一员

一、责任链&#xff08;Chain of Responsibility Patten&#xff09;模式是个啥&#xff1f; 想象一下&#xff0c;你要请假。你先把请假申请交给了小组长&#xff0c;小组长一看&#xff0c;这事儿他能决定&#xff0c;就直接批了。要是小组长觉得这事儿得往上汇报&#xff0…

QT调用OpenSceneGraph

OSG和osgQt编译教程&#xff0c;实测通过 一、下载OpenSceneGraph OpenSceneGraphhttps://github.com/openscenegraph/OpenSceneGraph 二、使用CMAKE编译OpenSceneGraph 1.打开cmake&#xff0c;配置源代码目录 2. CMAKE_INSTALL_PREFIX设置为install文件夹&#xff0c;生…

数据结构与算法面试专题——引入及归并排序

数据结构与算法引入 我们都知道数据结构与算法很重要&#xff0c;甚至会将其称为程序员的“内功”&#xff0c;但是我们花了很多时间学的算法和数据结构&#xff0c;好像就只是为了应对算法面试&#xff0c;对日常的开发工作没有什么帮助。 这点对于我们数据工程师来说&#…

《鸿蒙 HarmonyOS 应用开发从入门到精通(第 2 版)》学习笔记 ——HarmonyOS 环境搭建之安装DevEco Studio

作为一款开发工具&#xff0c;除了具有基本的代码开发、编译构建及调测等功能外&#xff0c;DevEco Studio还具有如下特点&#xff1a; 高效智能代码编辑&#xff1a;支持Java、XML、ArkTS、JS、C/C等语言的代码高亮、代码智能补齐、代码错误检查、代码自动跳转、代码格式化、…

电脑办公技巧之如何在 Word 文档中添加文字或图片水印

Microsoft Word是全球最广泛使用的文字处理软件之一&#xff0c;它为用户提供了丰富的编辑功能来美化和保护文档。其中&#xff0c;“水印”是一种特别有用的功能&#xff0c;它可以用于标识文档状态&#xff08;如“草稿”或“机密”&#xff09;、公司标志或是版权信息等。本…

学习记录之原型,原型链

构造函数创建对象 Person和普通函数没有区别&#xff0c;之所以是构造函数在于它是通过new关键字调用的&#xff0c;p就是通过构造函数Person创建的实列对象 function Person(age, name) {this.age age;this.name name;}let p new Person(18, 张三);prototype prototype n…