Keil5 MDK在Cortex M系列关于分散加载文件说明指导

news2026/3/18 10:46:24
类别内容摘要本文结合 SRAM 示例工程说明如何在Cortex M LCM32F067 工程中使用 Keil 分散加载文件将部分函数固定到指定 Flash 地址运行并将部分函数搬运到指定 RAM 地址运行。源代码路径链接: https://pan.baidu.com/s/1De7GAP6OVmd0leHCKNNtag?pwddesm 提取码: desm目 录适用范围基础知识分散加载文件概述分散加载文件语法分散加载应用实例常见问题与验证方法1. 适用范围有时候用户希望在单片机工程中实现如下需求某些函数固定在某个 Flash 地址作为固定接口或服务入口某些函数在上电后搬运到 RAM 中执行以提升速度或避免 Flash 操作时取指冲突普通代码和普通变量仍然按照默认方式分别放在 Flash 和 SRAM 中在 Keil MDK 工程中这类需求通常通过分散加载文件来实现。本文结合Project/Examples/SRAM示例工程重点讲解如何通过section(name)给函数打标签如何在.sct文件中把这些 section 分配到不同地址如何理解加载域、执行域、FIXED、__scatterload如何通过 map 验证最终结果2. 基础知识2.1 基本概念在理解分散加载前需要先清楚下面几类数据的含义Code表示程序代码。RO-Data表示只读数据例如const常量。RW-Data表示已初始化的全局变量或静态变量。ZI-Data表示未初始化的全局变量或静态变量。在嵌入式工程中通常有如下结论Code和RO-Data一般放在 Flash 中RW-Data运行时在 RAM 中但其初值镜像也要占用 FlashZI-Data只占用 RAM不占用 Flash 初值空间因此一个工程的空间占用通常可理解为Flash 占用 Code RO-Data RW-DataRAM 占用 RW-Data ZI-Data2.2 启动阶段谁在搬运代码和数据很多学习者第一次接触分散加载时最容易产生的疑问是“既然某个函数要在 RAM 中运行它是怎么从 Flash 到 RAM 的”答案在启动代码中。在 Cortex-M Keil 的典型启动流程里Reset_Handler进入运行库启动过程__main调用__scatterload__scatterload根据 scatter 文件描述把需要搬运的代码或数据从装载地址复制到执行地址RW数据完成初始化ZI数据完成清零最后才跳入main()因此只要 scatter 文件描述正确那么main()运行之前所有要求“在 RAM 中执行”的函数就已经被搬运到目标 RAM 地址了2.3 本工程中的 4 个目标函数本工程中专门设计了 4 个函数用于演示RAM_FillPatternWindow()RAM_MixAndAccumulate()FLASH_FixedSignature()FLASH_FixedParity()它们分别用于演示两个不同 RAM 地址运行两个不同 Flash 固定地址运行最终链接结果为函数名最终符号地址说明RAM_FillPatternWindow0x20000001在 SRAM 执行区 A 运行RAM_MixAndAccumulate0x20000101在 SRAM 执行区 B 运行FLASH_FixedSignature0x08000801固定在 Flash 窗口 AFLASH_FixedParity0x08000901固定在 Flash 窗口 B说明地址最低位为1是 Thumb 状态位实际区域基地址仍然分别是0x20000000、0x20000100、0x08000800、0x080009003. 分散加载文件概述分散加载文件是一个文本文件用于描述链接器如何组织最终映像并决定程序镜像装载到哪里代码和数据执行时位于哪里不同 section 应该进入哪个执行区如果不使用 scatter 文件链接器会按默认规则放置代码和数据。而在下面这些场景中通常就需要显式编写 scatter 文件代码必须放在多个不同内存区域部分函数必须在 RAM 中执行部分函数必须固定在某个 Flash 地址多块 RAM 或多块 Flash 需要分别利用需要精确控制向量表、启动区、应用区、固定接口区的地址布局对本工程而言使用分散加载的直接目的就是固定两段 Flash 代码区划出两段 RAM 执行区普通代码和数据继续走默认的应用区与数据区4. 分散加载文件语法4.1 加载时域的描述一个典型的加载域写法如下LR_IROM1 0x08000000 0x00010000 { ... }这里LR_IROM1是加载域名称0x08000000是加载域起始地址0x00010000是该加载域大小在本工程中这表示整个映像的主装载空间仍然是片上 Flash其组织起点是0x080000004.2 运行时域的描述一个典型的执行域写法如下ER_FLASH_FIXED_A 0x08000800 FIXED 0x00000100 { *.o (FLASH_FIXED_A) }这里ER_FLASH_FIXED_A是执行域名称0x08000800是执行地址FIXED表示装载地址与执行地址相同0x00000100表示执行域大小如果某个执行域不在 Flash而是在 SRAM 中例如ER_RAM_EXEC_A 0x20000000 0x00000100 { *.o (RAM_EXEC_A) }那么它的含义是这段代码最终在0x20000000执行但初始镜像仍由主加载域统一组织在 Flash 中上电后由__scatterload拷贝到该 SRAM 地址4.3 输入段描述scatter 文件中的输入段匹配规则用来决定“哪些内容放进这个执行域”。例如*.o (RAM_EXEC_A)它表示匹配所有目标文件中的RAM_EXEC_A输入段并把这些输入段放到当前执行域中本工程中在 C 代码里写了__attribute__((section(RAM_EXEC_A)))这就会让该函数进入名为RAM_EXEC_A的输入段。scatter 文件再用*.o (RAM_EXEC_A)将其准确分配到ER_RAM_EXEC_A。类似地FLASH_FIXED_A对应固定 Flash 区 AFLASH_FIXED_B对应固定 Flash 区 BRAM_EXEC_B对应第二个 RAM 执行区4.4.ANY的意义.ANY可以理解成“兜底规则”。例如.ANY (RO)表示所有还没有被前面规则收走的只读代码、只读数据都放到当前执行域因此在写 scatter 文件时通常建议顺序为先写专用 section 的匹配规则最后再写.ANY否则很容易出现你想单独分配的函数先被默认.ANY区域收走后面的专用区域反而匹配不到目标5. 分散加载应用实例5.1 本工程的地址规划本工程使用的关键地址如下区域起始地址用途ER_ROOT0x08000000向量表、启动代码、运行库根区ER_FLASH_FIXED_A0x08000800固定 Flash 函数 AER_FLASH_FIXED_B0x08000900固定 Flash 函数 BER_IROM10x08000A00普通应用代码区ER_RAM_EXEC_A0x20000000RAM 执行函数 AER_RAM_EXEC_B0x20000100RAM 执行函数 BRW_IRAM10x20000200普通数据区用图示表示如下flowchart TB subgraph FLASH[Flash 地址空间] F0[0x08000000\nER_ROOT\n向量表 / 启动代码 / __main / __scatterload] F1[0x08000800\nER_FLASH_FIXED_A\nFLASH_FixedSignature()] F2[0x08000900\nER_FLASH_FIXED_B\nFLASH_FixedParity()] F3[0x08000A00\nER_IROM1\n普通应用代码区] end subgraph SRAM[SRAM 地址空间] R0[0x20000000\nER_RAM_EXEC_A\nRAM_FillPatternWindow()] R1[0x20000100\nER_RAM_EXEC_B\nRAM_MixAndAccumulate()] R2[0x20000200\nRW_IRAM1\nRW / ZI 数据] end5.2 本工程的 scatter 文件配置本工程实际采用的 scatter 文件结构如下LR_IROM1 0x08000000 0x00010000 { ER_ROOT 0x08000000 0x00000800 { *.o (RESET, First) *(InRoot$$Sections) } ER_FLASH_FIXED_A 0x08000800 FIXED 0x00000100 { *.o (FLASH_FIXED_A) } ER_FLASH_FIXED_B 0x08000900 FIXED 0x00000100 { *.o (FLASH_FIXED_B) } ER_IROM1 0x08000A00 FIXED 0x0000F600 { .ANY (RO) .ANY (XO) } ER_RAM_EXEC_A 0x20000000 0x00000100 { *.o (RAM_EXEC_A) } ER_RAM_EXEC_B 0x20000100 0x00000100 { *.o (RAM_EXEC_B) } RW_IRAM1 0x20000200 0x00002600 { .ANY (RW ZI) } }其含义可概括为ER_ROOT放根区内容ER_FLASH_FIXED_A和ER_FLASH_FIXED_B放两个固定地址函数ER_IROM1放其余普通应用代码ER_RAM_EXEC_A和ER_RAM_EXEC_B放两段不同地址的 RAM 执行代码RW_IRAM1放普通全局变量和静态变量5.3 在 C 文件中定义自定义 section本工程在main.c中使用了下面的写法#define RAM_EXEC_A_ATTR __attribute__((noinline, section(RAM_EXEC_A))) #define RAM_EXEC_B_ATTR __attribute__((noinline, section(RAM_EXEC_B))) #define FLASH_FIXED_A_ATTR __attribute__((noinline, section(FLASH_FIXED_A))) #define FLASH_FIXED_B_ATTR __attribute__((noinline, section(FLASH_FIXED_B)))然后分别将 4 个函数放入这些 sectionRAM_EXEC_A_ATTR uint32_t RAM_FillPatternWindow(uint32_t seed); RAM_EXEC_B_ATTR uint32_t RAM_MixAndAccumulate(uint32_t value); FLASH_FIXED_A_ATTR uint32_t FLASH_FixedSignature(void); FLASH_FIXED_B_ATTR uint32_t FLASH_FixedParity(uint32_t value);其中noinline的作用是防止编译器把函数直接内联到调用者中便于在链接报告中清楚看到每个函数的独立落点5.4 双 RAM 运行函数配置实例本工程中两个运行在 RAM 的函数分别是RAM_FillPatternWindow()RAM_MixAndAccumulate()它们的功能并不复杂目的是让学习者把注意力集中在“地址分配”上而不是业务逻辑本身。对应关系如下函数section执行区执行地址RAM_FillPatternWindow()RAM_EXEC_AER_RAM_EXEC_A0x20000000RAM_MixAndAccumulate()RAM_EXEC_BER_RAM_EXEC_B0x20000100程序启动时运行库进入__scatterload将RAM_EXEC_A对应的镜像从 Flash 拷贝到0x20000000将RAM_EXEC_B对应的镜像从 Flash 拷贝到0x20000100main()才开始执行因此在main()中调用这两个函数时它们已经在 RAM 中。5.5 固定 Flash 地址函数配置实例本工程中两个固定在 Flash 中的函数分别是FLASH_FixedSignature()FLASH_FixedParity()对应关系如下函数section执行区固定地址FLASH_FixedSignature()FLASH_FIXED_AER_FLASH_FIXED_A0x08000800FLASH_FixedParity()FLASH_FIXED_BER_FLASH_FIXED_B0x08000900由于这两个执行区都带FIXED因此装载地址 执行地址函数直接在 Flash 中原地执行不需要启动时拷贝这类配置很适合实现固定服务入口版本接口固件标识函数固定跳转入口5.6 普通应用区为什么也要使用 FIXED本工程里普通应用区写成了ER_IROM1 0x08000A00 FIXED 0x0000F600这里的FIXED很重要。原因是前面已经人为切出了两个固定 Flash 小窗普通应用区从0x08000A00开始执行如果这里不加FIXED链接器可能会把装载镜像往前压缩造成 Flash 中装载布局和执行布局发生交叉覆盖风险本工程第一次修改 scatter 文件时就出现了这类错误。最终修复办法就是给普通应用区也加上FIXED这是一条很重要的实践经验只要 Flash 代码区需要精确切片而且这些区域本身就在 Flash 原地执行就优先考虑FIXED5.7 本工程中的 section、执行域与函数对应关系总表名称类型位置作用RAM_EXEC_A自定义输入段C 文件定义作为 RAM 函数 A 的标签RAM_EXEC_B自定义输入段C 文件定义作为 RAM 函数 B 的标签FLASH_FIXED_A自定义输入段C 文件定义作为固定 Flash 函数 A 的标签FLASH_FIXED_B自定义输入段C 文件定义作为固定 Flash 函数 B 的标签ER_RAM_EXEC_A执行域SRAM接收RAM_EXEC_AER_RAM_EXEC_B执行域SRAM接收RAM_EXEC_BER_FLASH_FIXED_A执行域Flash接收FLASH_FIXED_AER_FLASH_FIXED_B执行域Flash接收FLASH_FIXED_B6. 常见问题与验证方法6.1 如何看 map 文件map文件更适合检查整体空间分布与是否重叠。重点检查各执行区是否超出分配大小例如ER_RAM_EXEC_A 0x00000100是否真的足够。SRAM 代码区和普通数据区是否重叠本工程中ER_RAM_EXEC_A从0x20000000ER_RAM_EXEC_B从0x20000100RW_IRAM1从0x20000200固定 Flash 区和普通应用区是否冲突本工程中0x080008000x080009000x08000A00这些边界都应保持清晰独立。6.2 初学者常见错误常见错误主要有以下几类只把顶层函数放到 RAM却忽略其子函数仍在 Flash把.ANY (RO)写在专用 section 规则前面忘记给演示函数加noinline没有给 RAM 代码区与普通数据区留出边界在多块 Flash 切片时忘记使用FIXED结束语对分散加载最实用的理解方式可以归纳为四句话先在 C 文件中用section(name)给函数打标签再在.sct文件中把这个标签映射到指定执行域如果执行地址在 RAM启动时由__scatterload搬运过去如果执行地址在固定 Flash使用FIXED让其原地执行掌握了这套方法后就可以在单片机Cortex M系列工程中灵活实现固定地址函数接口RAM 中运行的关键函数多执行区的代码布局设计更复杂的 Boot / App 分区结构

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…