当前位置:   article > 正文

STM32F407 SPI FLASH存储代码SRAM执行代码_stm32程序存放在外部flash

stm32程序存放在外部flash

接上一篇

上一篇文章中我们介绍了如何将固件下载到SPI FLASH中。这一篇我们在上一篇的基础上实现:把存储在外部flash的代码拷贝到外部SRAM中执行。

外部FLASH存储代码在外部SRAM中执行代码的意义

MCU的内部flash和内部sram都不是特别大,在一些大型的应用中,会出现flash和ram不够的情况。这样我们就可以把应用程序存储在外部flash中,然后拷贝到外部sram中执行。
我这里说的外部flash指的是SPI FLASH。对于STM32F407单片机没有QSPI接口,也就不能在外部flash中执行代码了;对与STM32H7,F7这类单片机有QSPI接口,代码也不是必须复制到SRAM中执行,也可以通过QSPI的内存映射功能,在外部flash中执行。

思路

程序分为两部分:一部分是BOOT程序,一部分是应用程序。
MCU上电先执行内部flash的代码(其实也只能先执行内部flash的代码,因为外部flash和sram的接口需要初始化,无法直接从这些器件中直接取指令,执行)也就是BOOT程序。BOOT程序的功能:初始化外部flash接口和外部sram接口,然后把外部flash的代码拷贝到外部sram中,跳转到SRAM中取指令,执行代码。
应用程序没什么特别的,只需应用程序的工程编写合适的分散加载文件(链接脚本)。

加载地址和链接地址

加载地址:就是程序的存储地址。
链接地址:就是程序执行的地址。
这两个地址可以是一样的(比如BOOT程序,程序在内部flash中存储,在内部flash中执行),也可以是不一样的(比如在外部flash中存储,在外部sram中执行)。

BOOT程序

uint8_t read_buf[1024];
uint8_t *p = (uint8_t *)0x68000000;//外部SRAM的基地址
int main(void)
{ 
	u8 key;
	u16 i=0;
    u16 id = 0;
    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);     //初始化延时函数
	uart_init(115200);	//初始化串口波特率为115200
	LED_Init();					//初始化LED 
 	
	KEY_Init(); 				//按键初始化  
	W25QXX_Init();			//初始化外部flash接口
 	
	id = W25QXX_ReadID();
	printf("boot start...\r\n");
	printf("flash chip id = %04x\r\n",id);
	
	FSMC_SRAM_Init();//初始化外部SRAM接口
	
	for(int i=0;i<50;i++)
	{
		W25QXX_Read(read_buf,i*1024,1024);//从外部flash拷贝1K数据到read_buf
		memcpy(p,read_buf,1024);//从read_buf拷贝1K数据到外部SRAM
		p+=1024;
	}
	//跳转
	jump2app = (IapFun)*(vu32*)(0x68000000 + 4);
	/* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */
	MSR_MSP(*(vu32*)0x68000000);
	jump2app();  //跳转到APP
	while(1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

思路中和注释已经解释的很清楚,这里就不再赘述。

应用程序

应用程序的代码没有任何区别,需要自己编写链接脚本。

LR_IROM1 0x68000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x68000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

LR_IROM1 0x68000000 0x00100000 中的0x68000000是加载地址,0x00100000是加载域的地址。
ER_IROM1 0x68000000 0x00100000 中的0x68000000是链接地址,0x00100000是执行域的地址。
链接脚本大家要根据自己的实际工程项目灵活调整。
前边讲到加载地址就是程序的存储地址,链接地址是程序的执行地址。那外部flash存储代码外部sram执行代码,这明显的就是加载地址和链接地址不一样啊,为什么分散加载文件写的却是一样?
解释:其实加载地址和链接地址那是看站在哪个角度去看。站在应用程序的角度,应用程序并没有拷贝代码,CPU执行应用程序第一条指令的时候,应用程序就已经处于外部SRAM了,所以加载地址就等于链接地址了。至于拷贝代码那是BOOT程序去做的,和应用程序没有任何关系。

总结

要实现外部FLASH存储代码内部SRAM执行代码,主要工作有两个,其一是制作下载算法文件,其二是调整应用程序的链接脚本。对于链接脚本中的一些知识需要理解,只有理解了,才能灵活的应用。

需要工程源码的请发私信。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/713268
推荐阅读
相关标签
  

闽ICP备14008679号