STM32F407在RAM中执行程序

news2024/10/5 12:29:13

STM32F407在flash中执行代码的速度比在ram中执行代码的速度快。因为STM32F407有一颗“自适应实时存储器加速器”,这里不讨论ART Accelerator的加速方案。
把代码放在RAM中执行纯粹是为了学习。

将个别函数的代码放到RAM中运行

使用自己编写的链接脚本(sct文件)。
在这里插入图片描述
再来看自己编写的分散加载文件内容:

LR_IROM1 0x08000000 0x00004000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00004000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00100000  {  ; RW data
   .ANY (+RW +ZI)
   *.o (RAM_SPEED)
  }
}

LR_ROM1后边的0x08000000是加载地址(代码存储时的地址),0x00004000是加载域的大小。
ER_IROM1 0x08000000是链接地址(代码执行时的地址,PC寻址的地址),0x00004000是执行域的大小。
在链接脚本中定义了一个代码段RAM_SPEED。
程序中将函数指定到代码段RAM_SPEED。

#pragma arm section code = "RAM_SPEED"
void my_delay(void)
{
	volatile uint16_t i,j;
	for(i=0;i<1000;i++)
		for(j=0;j<1000;j++);
}
#pragma arm section

编译链接后的加载地址和链接地址如下:
在这里插入图片描述
运行时PC指针如下图:
在这里插入图片描述
PC指针确实指向了SRAM区域,而不是FLASH区域。
通过打印发现my_delay在SRAM中运行时,耗时89453us。my_delay在FLASH中运行时,耗时71542us。也证实了在F407芯片上SRAM运行程序比FLASH运行程序快。

F407有一块CCM,我们把程序放到CCM中是否可行?
修改链接脚本

LR_IROM1 0x08000000 0x00004000  {    ; load region size_region
	ER_IROM1 0x08000000 0x00004000  {  ; load address = execution address
		*.o (RESET, +First)
		*(InRoot$$Sections)
		.ANY (+RO)
		.ANY (+XO)
	}
	RW_IRAM1 0x20000000 0x00100000  {  ; RW data
		.ANY (+RW +ZI)
	}
	RW_IRAM2 0x10000000 0x00010000  {  ; RW data
		*.o (RAM_SPEED)
	}
}

答案是不行,程序执行到my_delay的时候就hardfault了,原因是CCM呢M4内核只通过D-BUS总线相连,M4内核是通过I-BUS执行取指令的,所以不行。
还有一种方式是通过__attribute__声明函数,将函数声明在RAM_SPEED代码段,sct文件和上边那种方式一样。

__attribute__((section("RAM_SPEED"))) void my_delay(void)
{
	volatile uint16_t i,j;
	for(i=0;i<1000;i++)
		for(j=0;j<1000;j++);
}

将整个工程代码放到RAM中运行

这种方案思路是写两套代码,一套是Boot代码,一套是APP代码。Boot代码在flash中存储在flash中执行,Boot上电将APP的代码拷贝到SRAM中,再跳转到SRAM中执行APP代码。APP代码是在flash中存储,在SRAM中执行。

Boot程序:使用默认的分散加载文件,target选项卡如下:
在这里插入图片描述

	/*其它必要操作*/
	/*从flash中把代码搬运到RAM中  共60K*/
	memcpy(p,(uint8_t *)0x08004000,60*1024);

	jump2app = (IapFun)*(vu32*)(0x20000800 + 4);
	MSR_MSP(*(vu32*)0x20000800);//存0x20000800地址处开始存放程序
	jump2app();  //跳转到APP

由上图和代码可以看出,我们给Boot分配了16KByte flash,2Kbyte RAM,这个根据个人实际情况分配。
APP程序:
先看一下分散加载文件

LR_IROM1 0x08004000   0x000FC000{    ; load region size_region
  ER_IROM1 0x20000800 0x0000F000{  
   *.o (RESET, +First)  
;  *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 +0  {  ; RW data
   .ANY (+RW +ZI)
  }
}

Boot程序占用了16K Byte flash,那么我们应用程序就从0x08004000开始存储,也就是APP 分散加载文件的加载地址是0x08004000,给APP分配了0x000FC000个Bytes flash空间。APP的执行域(链接地址)从0x20000800开始,这里想一下能不能从0x20000000开始,肯定不行的呀,如果我们改成了0x20000000,那么Boot程序拷贝的时候就往0x20000000开始的地址处拷贝数据,但是拷贝的那一刻是在Boot中完成的,Boot会使用0x20000000到0x20000800这一段RAM,所以不行。
ER_ROM1中,把RESET链接到执行域(0x20000800)最前边,RO(只读数据段)和XO(执行段)也链接到执行域。
RW_IRAM1中,把初始化不为0的数据段和BSS段放到执行域RW_IRAM1中。
到这里理论上就可以了,我们需要做的核心工作:
1.在Boot程序从Flash中拷贝APP代码到SRAM。
2.跳转到SRAM,运行APP。
3.编写APP的分散加载文件。

但是实际上由于ST官方的启动文件中调用了__main,导致我们修改APP的分散加载文件后会链接报错。如下图
在这里插入图片描述
报错的意思就是entry那些数据段不能放到非启动区域,
由于__main是库文件,所以我们无法修改,也不知道如何修改。所以我放弃了使用__main,我大概知道__main库函数做了那些工作,__main函数就是把RW数据段从flash中搬运到RAM中,把RAM中的BSS数据段清零,最后跳转到main函数,那我们就自己在启动文件中实现这些工作。
汇编文件修改成如下代码:

; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB


; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     0x20000800               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                   ; Window WatchDog                                        
				;省略***
                DCD     FPU_IRQHandler                    ; FPU
                                         
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

                AREA    |.text|, CODE, READONLY

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
					 
					 
				IMPORT	mymain
				IMPORT 	my_memcpy
				IMPORT	my_memset
                IMPORT  SystemInit
					
				IMPORT	|Image$$RW_IRAM1$$RW$$Base|
				IMPORT	|Load$$RW_IRAM1$$RW$$Base|
				IMPORT	|Image$$RW_IRAM1$$RW$$Length|
					
				IMPORT	|Image$$RW_IRAM1$$ZI$$Base|
				IMPORT	|Image$$RW_IRAM1$$ZI$$Length|					 
					 
				;重定位RW段
				LDR     R0, =|Image$$RW_IRAM1$$RW$$Base|
				LDR     R1, =|Load$$RW_IRAM1$$RW$$Base|
				LDR     R2, =|Image$$RW_IRAM1$$RW$$Length|
				BL		my_memcpy
				
				;清除BSS段
				LDR     R0, =|Image$$RW_IRAM1$$ZI$$Base|
				LDR     R1, =0
				LDR     R2, =|Image$$RW_IRAM1$$ZI$$Length|
				BL		my_memset			 
					 
;				BL	SystemInit
                LDR     R0, =SystemInit
                BLX     R0 

;				BL	mymain
                LDR     R0, =mymain
                BX      R0					 
					 
					 
					 
				;IMPORT  SystemInit
				;IMPORT  __main

                 ;LDR     R0, =SystemInit
                 ;BLX     R0
                 ;LDR     R0, =__main
                 ;BX      R0
                 ENDP

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler          [WEAK]
                B       .
                ENDP
BusFault_Handler\
                PROC
                EXPORT  BusFault_Handler           [WEAK]
                B       .
                ENDP
UsageFault_Handler\
                PROC
                EXPORT  UsageFault_Handler         [WEAK]
                B       .
                ENDP
SVC_Handler     PROC
                EXPORT  SVC_Handler                [WEAK]
                B       .
                ENDP
DebugMon_Handler\
                PROC
                EXPORT  DebugMon_Handler           [WEAK]
                B       .
                ENDP
PendSV_Handler  PROC
                EXPORT  PendSV_Handler             [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP

Default_Handler PROC

                EXPORT  WWDG_IRQHandler                   [WEAK]                                        
                ;省略
                EXPORT  FPU_IRQHandler                    [WEAK]

WWDG_IRQHandler                                                       
 ;省略
FPU_IRQHandler
   
                B       .

                ENDP

                ALIGN

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE
                
                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap

                 LDR     R0, =  Heap_Mem
                 LDR     R1, =(Stack_Mem + Stack_Size)
                 LDR     R2, = (Heap_Mem +  Heap_Size)
                 LDR     R3, = Stack_Mem
                 BX      LR

                 ALIGN

                 ENDIF

                 END

;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****

main函数的名字我修改了mymain。在汇编中调用了my_memcpy和my_memset函数,代码实现如下

void my_memcpy(void *pcdest,void *pcsrc,int len)
{
	uint8_t *dest = pcdest;
	uint8_t *src = pcsrc;
	while(len--)
	{
		*dest++ = *src++;
	}
}
void my_memset(void *pcdest,int val,int len)
{
	uint8_t *dest = pcdest;
	while(len--)
	{
		*dest++ = 0;
	}
}

我栈顶指针故意写成0x20000800,因为此时此刻已经来到了APP的世界,0x20000000到0x20000800属于Boot,我们在APP中又把这2K Bytes空间利用起来了,分配给了APP的栈空间。

这个APP程序虽然可以在RAM运行,但是有个问题,就是链接的时候把工程中的所有代码都链接到映像文件了,导致映像文件特别大,我们需要的是只链接那些调用到的代码,把所有都链接进去的原因是程序缺少指定一个入口点,这是在ARM LINK手册中看到的,如下图
在这里插入图片描述
我不知道如何解决,有知道的告诉一下。

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

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

相关文章

《论文阅读28》OGMM

一、论文 研究领域&#xff1a; 点云配准 | 有监督 部分重叠论文&#xff1a;Overlap-guided Gaussian Mixture Models for Point Cloud Registration WACV 2023 二、概述 概率3D点云配准方法在克服噪声、异常值和密度变化方面表现出有竞争力的性能。本文将点云对的配准问题…

【计算机网络原理】初始网络基础

文章目录 1. 网络发展史1.1 单机时代1.2 网络互连局域网 LAN广域网 WAN 2. 网络通信基础2.1 IP 地址2.2 端口号2.3 协议2.4 五元组2.5 协议分层2.5.1 OSI七层模型2.5.2 TCP/IP五层模型 2.6 封装和分用2.6.1 数据封装(发送方情况)2.6.2 数据分用(接收方情况) 总结 1. 网络发展史…

这是不是你们都在找的免费又好用的配音网站?

随着人工智能技术的不断发展和普及&#xff0c;AI配音软件也越来越多地进入人们的视野。它可以帮助我们快速地将文字转换成语音&#xff0c;让我们的工作变得更加高效和便捷。在本文中&#xff0c;我将介绍一款非常实用而且免费的AI配音网站&#xff0c;超级简单好用&#xff0…

C++string的使用

CSDN的uu们&#xff0c;大家好。这里是C入门的第十六讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1.构造函数 1.1 string() 1.2 string(const char* s) 1.3 string(const …

Cinema 4D云渲染一分钟动画要多少钱?如何进行Cinema 4D云渲染?看完就懂了

&#xfeff;1.为什么Cinema 4D要使用云渲染&#xff1f; 近年来&#xff0c;Cinema 4D在实现视觉效果方面取得了很大的进展。但是&#xff0c;随着视觉效果的复杂化&#xff0c;渲染的工作量也相应增加&#xff0c;导致渲染时间变长。在这种情况下&#xff0c;云渲染平台就能…

Linux嵌入式系统开发之路:从小白到大牛

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 嵌入式系统开发是一个充…

Spring framework Day22:Aware接口

前言 在Spring框架中&#xff0c;有许多接口和类都有一个非常重要的作用——让我们能够更方便地构建应用程序和管理组件。其中&#xff0c;Aware接口就是其中一个非常重要的接口之一。通过实现该接口&#xff0c;我们可以让Spring容器感知到特定的组件和资源&#xff0c;并进行…

媒体转码和输出软件:Media Encoder 2024中文版

想要高效地转码、优化输出吗&#xff1f;那就来尝试全新的Media Encoder 2024吧&#xff01;Media Encoder是Adobe公司出品的一款媒体转码和输出软件&#xff0c;可以帮助您快速、高效地将多种格式的视频和音频转换为所需的输出格式。 全新的Media Encoder 2024提供了更加智能…

【CANoe】XML Test Module使用实例

文章目录 一、实操步骤1、增加XML Test Module节点2、配置XML Test Module节点3、XML Test Module节点增加CAPL脚本(.can文件)4、文件夹结构5、使用仿真节点开始测试6、测试结果与测试报告7、同理&#xff0c;在Test Setup也可如此操作 一、实操步骤 1、增加XML Test Module节…

使用conda install一直卡在solving environment的解决方法

使用国内镜像源&#xff0c;但install仍旧一直卡在solving environment&#xff0c;超过10分钟就不用等了&#xff1b; 检查C:\Users\UserName 路径下的.condarc文件 将这个defaults这一行删掉即可

【Linux-常用命令-基础命令-复制-copy-命令-笔记】

【Linux-常用命令-基础命令-复制文件-copy-命令-笔记】 1、前言2、操作3、自己的实践 1、前言 最近&#xff0c;在使用Linux的时&#xff0c;使用相关基础命令是&#xff0c;总是容易忘记&#xff0c;上网一搜&#xff0c;大部分都写的比较繁琐&#xff0c;我就找下复制命令&a…

【算法设计与分析qwl】04 NP-hard——只是举例几个,货郎,双机调度,01背包

NP-hard问题&#xff1a; 有效算法是 输入规模的多项式时间算法。 这些问题的难度处于可有效计算的边界。 算法数据结构程序设计 例4 货郎问题 建模与算法&#xff1a; 解是一个排列&#xff0c; 0-1背包问题&#xff1a; 建模&#xff1a; 双机调度&#xff1a; 建模&#x…

【PPT技巧】如何将多张幻灯片打印在一张纸上?

PPT页面很多&#xff0c;想在打印的时候&#xff0c;多张幻灯片放置在同一页面&#xff0c;也就是打印在一张纸上&#xff0c;如何设置呢&#xff1f; 首先&#xff0c;打开需要打印的PPT文件&#xff0c;点击菜单选项卡【文件】&#xff0c;然后在弹出的页面中点击【打印】选…

单链表经典OJ题:找出链表的中间节点

题目&#xff1a; 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。如果有两个中间结点&#xff0c;则返回第二个中间结点。 图例&#xff1a; 解法&#xff1a; 解法1: 先遍历链表确定链表节点的数量&#xff0c;然后再找到中间位置的节点 解法2: 快慢…

Linux性能优化--补充

14.1. 性能工具的位置 本书描述的性能工具来源于Internet上许多不同的位置。幸运的是&#xff0c;大多数主要发行版都把它们放在一起&#xff0c;包含在了其发行版的当前版本中。表A-1描述了全部工具&#xff0c;提供了指向其原始源位置的地址&#xff0c;并注明它们是否包含在…

百度地图高级进阶开发:圆形区域周边搜索地图监听事件(覆盖物重叠显示层级\图像标注监听事件、setZIndex和setTop方法)

百度地图API 使用百度地图API添加多覆盖物渲染时&#xff0c;会出现覆盖物被相互覆盖而导致都无法触发它们自己的监听&#xff1b;在百度地图API里&#xff0c;map的z-index为0&#xff0c;但是触发任意覆盖物的监听如click时也必定会触发map的监听&#xff1b; 项目需求 在…

6.7 案例分析与实现

思维导图&#xff1a; 6.7 案例分析与实现 #### 案例6.2: 六度空间理论 【案例分析】 - **背景介绍**&#xff1a; 六度空间理论提及在任意两人之间最多仅有6个人的连接。尽管这一理论被广泛提及并得到了某种程度的验证&#xff0c;但从科学角度看&#xff0c;它仍然只是一…

模型的选择与调优(网格搜索与交叉验证)

1、为什么需要交叉验证 交叉验证目的&#xff1a;为了让被评估的模型更加准确可信 2、什么是交叉验证(cross validation) 交叉验证&#xff1a;将拿到的训练数据&#xff0c;分为训练和验证集。以下图为例&#xff1a;将数据分成4份&#xff0c;其中一份作为验证集。然后经过…

C/C++面试常见问题——指针和引用的区别

首先想要理解指针和引用的区别&#xff0c;我们要明确什么是指针&#xff0c;什么是引用 一&#xff0c;指针和引用的基本概念及特性 指针是一个特殊变量&#xff0c;其中存储着所指向变量的地址 指针主要有以下特性&#xff1a; 1. 在使用时需要*解引用 2. sizeof(指针)的…

关于我对 jeecg-boot 的项目理解、使用心得和改进建议

一句话总结&#xff1a; JeecgBoot帮助我提升了后端技术水平&#xff0c;入门了前端&#xff0c;让我在公司内部慢慢能够成长为全栈开发。 一、项目理解 JeecgBoot 项目的核心理念是快速开发、低代码、易扩展。它采用了前后端分离的架构&#xff0c;后端使用Spring Boot Myba…