在Keil中利用分散加载(scatter)在Flash中实现App区和固件区的分离_keil flash分段

如果将固件区单独分为一个区,可以让无论程序运行在A区或者B区时,都可以调用固件区的模块,这样就相当于可以将固件区的空间复用,提高了空间利用率。

固件区与APP区分开的可行性原理

对于一些嵌入式软件的初学者来说可能会有一些困惑,如果这些模块都不和APP在同一个project中编译,如何被app调用。任何一个函数都是以二进制的方式存储在Flash上的,如果用相同的编译器和编译参数,在同一MCU平台上,无论该函数被放置在什么地址,或者是被那个target或是project编译,其最后存储的二进制代码都是一样的。因此一个嵌入式APP软件只要知道一个函数的类型声明和在Flash位置,就可以直接调用该函数。

如何将函数放在Flash的固定区域

首先我们说一下如何将一个函数甚至是一个模块放在Flash的固定位置。由于笔者一般都是用keil,因此以下的方法都是基于keil环境:

方法一:

如果只有一个函数,我们可以在函数声明的时候在函数末尾加上__attribute__((section(“.ARM.__at_0xXXXXXXXX”)))的语句,将某个函数编译后固定存放在Flash的固定位置。

void function(void) __attribute__((section(".ARM.__at_0xXXXXXXXX")));

void function(void)
{
    ...
}

方法二:

如果要将几个函数一起放在一块区域内,那就不太可能使用方法一了,我们没法提前知道这些函数的长度,就算知道这些函数的长度,还要手动指定其在flash中的位置,让其紧密排列,这样过于麻烦。此时可以将几个函数统都加上__attribute__((section(“abc”))),然后可以将几个函数都放在section abc中,编译器自动会将其紧密排列。但是怎样将section指定位置呢?这里就要引出Keil中的分散加载(scatter)了。

如何使用Keil中的分散加载

Keil中的分散加载在Target的设置文件中的Linker页面,点击取消左上角的勾,就可以编辑下面的Scatter File了。

分散加载的.sct文件一般长成这样:

具体的文件格式大家可以自己搜索查看其他文章或者查看官方文档,这里不在赘述了。

如果我们要将一个section放在一个固定的区域,可以如下修改scatter文档

上面这段代码中就是将section(abc)放在从地址0x08013000的固定区域,最大长度0x1000。

方法三

当然如果用分散加载,还可以有更方便的方法。如下的设置就是将整个"abc"模块都放在了这个app区中了,不用再为每个函数单独添加语句。

但是这里要注意,Flash中只能存放一个模块中的函数和常量,全局变量和静态变量是无法放在Flash中的。而且分散加载中的文件其实是可以使用通配符的,因此使用十分方便。

如何引用Flash中已知位置的函数

如果知道了在函数在Flash中的位置和函数的类型,就可以在程序中直接定义一个函数指针,然后指向该地址,直接引用即可。但是这里面有一个坑,如果函数存放的位置是0xXXXXXXXX,那函数指针指向的地址应该是0xXXXXXXXX+1,如果直接赋值0xXXXXXXXX,那程序就会运行到Hardfault中了。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

tps://bbs.csdn.net/topics/618654289)

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Keil 调用 malloc 函数时,分配出来的地址在 flash 的原因可能是堆的起始地址和大小没有正确配置。在默认情况下,Keil 会将堆分配到内部 SRAM 的起始地址处,如果 SRAM 空间不足,Keil 会将堆分配到 FLASH 的起始地址处。如果你使用的是 ROM-less 版本的 RA6M4 芯片,那么内部 SRAM 的空间可能较小,可能会导致堆分配到 FLASH 的起始地址处。在这种情况下,当你使用 malloc 函数时,分配出的地址就有可能在 FLASH 。 为了解决这个问题,你可以手动配置堆的起始地址和大小,以确保分配的内存空间在 RAM 。具体的操作方法如下: 1. 在 Keil 编译选项添加 `--heap_size=xxx` 参数,指定堆大小为 xxx 字节。 2. 在代码定义一个全局的堆数组,并将其放在 RAM ,例如: ``` #define HEAP_SIZE 1024 uint8_t heap_buf[HEAP_SIZE] __attribute__((section(".my_heap"), zero_init)); ``` 其,`__attribute__((section(".my_heap")))` 表示将 `heap_buf` 放在名为 `.my_heap` 的 RAM ,`zero_init` 表示将 `heap_buf` 数组的元素初始化为 0。 3. 在代码添加 `_sbrk` 函数的定义,用于实现动态内存分配。例如: ``` void *_sbrk(int incr) { static uint8_t *heap_end = heap_buf; uint8_t *prev_heap_end; prev_heap_end = heap_end; if (heap_end + incr > heap_buf + HEAP_SIZE) { /* 堆内存溢出 */ return (void *)0; } heap_end += incr; return (void *)prev_heap_end; } ``` 其,`_sbrk` 函数用于向操作系统申请增加堆大小,`heap_end` 表示堆的结束地址,`HEAP_SIZE` 表示堆的大小。 4. 在代码调用 `malloc` 函数进行内存分配,例如: ``` char *str = (char *)malloc(10); ``` 5. 编译代码并烧录到目标设备。 通过以上步骤,你就可以在 Keil 调用标准 C 库的 malloc 函数,并确保分配出来的内存地址在 RAM 了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值