STM32F407 SPI FLASH存储代码SRAM执行代码

2023-12-17 19:46:51

接上一篇

上一篇文章中我们介绍了如何将固件下载到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);
}

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

应用程序

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

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)
  }
}

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

总结

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

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

文章来源:https://blog.csdn.net/zhaodong1102/article/details/135044470
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。