stm32专题三十七:自动分配变量到指定 SRAM 空间

当有多个内存块时,MDK 优先使用空间更大的内存。

使用 sct 文件来进行内存管理:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第1张图片

编程要点:

1 取消勾选Use Memory Layout from Target Dialog,然后直接点击 edit 来编辑工程的 sct 文件:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第2张图片

sct 文件的默认配置如下所示:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第3张图片

看一下此时的 map 文件。可以看到,HEAP 和 STACK 都位于IRAM1 区域。

stm32专题三十七:自动分配变量到指定 SRAM 空间_第4张图片

接下来,我们将64 KB的内存空间分成两块,如下所示(直接复制,然后修改):

stm32专题三十七:自动分配变量到指定 SRAM 空间_第5张图片

我们将 64 KB 的内部SRAM,人为的分成了 20 + 28 KB,按照 MDK 优先使用大容量的空间进行存储,我们预计结果会是保存在ERAM1中,map文件证实了这一结果:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第6张图片

通常,我们会将栈区 STACK 分配到内部 SRAM,用来保存某些程序所用到的局部变量,因此,对sct文件进行修改如下:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第7张图片

通过上述修改,将栈区的内容保存在 IRAM1 中,而其他数据分配不变, map文件如下所示:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第8张图片

有了内存分配,接下来直接使用代码来分析,全局变量、全局数组、局部变量、动态内存 在内存中的地址:

#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"  
#include "./sram/sram.h"
#include 


void Delay(__IO u32 nCount); 


//定义变量到“指定的存储空间”
uint32_t testValue  =7 ;
//定义变量到“指定的存储空间”
uint32_t testValue2  =0;


//定义数组到“指定的存储空间”
uint8_t testGrup[100]  ={0};
//定义数组到“指定的存储空间”
uint8_t testGrup2[100] ={1,2,3};


/*本实验中的sct配置,若使用外部存储器时,堆区工作可能不正常,
  使用malloc无法得到正常的地址,不推荐在实际工程应用*/
/*另一种我们推荐的配置请参考教程中的说明*/

/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{
	uint32_t inerTestValue =10;
	
	/* LED 端口初始化 */
	LED_GPIO_Config();	 
    
  /* 初始化串口 */
  USART_Config();
  
  printf("\r\nSCT文件应用——自动分配变量到“指定的存储空间”实验\r\n");
  
	printf("\r\n使用“	uint32_t inerTestValue =10; ”语句定义的局部变量:\r\n");
	printf("结果:它的地址为:0x%x,变量值为:%d\r\n",(uint32_t)&inerTestValue,inerTestValue);
	
  printf("\r\n使用“uint32_t testValue  =7 ;”语句定义的全局变量:\r\n");
	printf("结果:它的地址为:0x%x,变量值为:%d\r\n",(uint32_t)&testValue,testValue);
	
  printf("\r\n使用“uint32_t testValue2  =0 ; ”语句定义的全局变量:\r\n");
	printf("结果:它的地址为:0x%x,变量值为:%d\r\n",(uint32_t)&testValue2,testValue2);
	
	
	printf("\r\n使用“uint8_t testGrup[100]  ={0};”语句定义的全局数组:\r\n");
	printf("结果:它的地址为:0x%x,变量值为:%d,%d,%d\r\n",(uint32_t)&testGrup,testGrup[0],testGrup[1],testGrup[2]);
	
  printf("\r\n使用“uint8_t testGrup2[100] ={1,2,3};”语句定义的全局数组:\r\n");
	printf("结果:它的地址为:0x%x,变量值为:%d,%d,%d\r\n",(uint32_t)&testGrup2,testGrup2[0],testGrup2[1],testGrup2[2]);
	
	
/*本实验中的sct配置,若使用外部存储器时,堆区工作可能不正常,
  使用malloc无法得到正常的地址,不推荐在实际工程应用*/
  /*另一种我们推荐的配置请参考教程中的说明*/
	
	uint32_t * pointer = (uint32_t*)malloc(sizeof(uint32_t)*3); 
	if(pointer != NULL)
	{
		*(pointer)=1;
		*(++pointer)=2;
		*(++pointer)=3;	
		
		printf("\r\n使用“	uint32_t *pointer = (uint32_t*)malloc(sizeof(uint32_t)*3); ”动态分配的变量\r\n");
		printf("\r\n定义后的操作为:\r\n*(pointer++)=1;\r\n*(pointer++)=2;\r\n*pointer=3;\r\n\r\n");
		printf("结果:操作后它的地址为:0x%x,查看变量值操作:\r\n",(uint32_t)pointer); 
		printf("*(pointer--)=%d, \r\n",*(pointer--));
		printf("*(pointer--)=%d, \r\n",*(pointer--));
		printf("*(pointer)=%d, \r\n",*(pointer));
		
		free(pointer);
	}
	else
	{
		printf("\r\n使用malloc动态分配变量出错!!!\r\n");	
	}
  
  LED_BLUE; 
	

  while(1); 
 

}


void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}

实际串口打印结果如下:

可以看到,全局变量位于 ERAM1,局部变量位于栈区 IRAM1,动态内存位于堆区 ERAM1。

stm32专题三十七:自动分配变量到指定 SRAM 空间_第9张图片

再设想一下,如果ERAM1真的是一个外部扩展的SRAM,那么毫无疑问的,肯定在速度上不如内部SRAM。所以,我们希望优先将变量保存到内部SRAM,而HEAP和其他的才保存在外部的SRAM。但由于 MDK 的链接器特性,都优先使用大容量作为存储空间,那么该怎么办?

其实很简单,只需要在 ERAM1 中注释掉就行;

stm32专题三十七:自动分配变量到指定 SRAM 空间_第10张图片

map 文件结果如下所示:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第11张图片

关于 __attribute__ 关键字的说明

在程序中,当需要指定某个变量的内存地址时, MDK 提供了一个关键字__attribute__,来实现绝对地址定位的功能,这种用法通常是为了把变量指定到外部扩展的存储器。

__attribute__ 的用法如下所示:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第12张图片

指定变量分配到节区:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第13张图片

可以看到,我们将变量定义到名为 EXRAM 的节区中,而在 sct 文件中,我们还可以指定 EXRAM 的执行域:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第14张图片

 

分配变量到外部SRAM

编程要点:

  1. 修改启动文件,在__main执行之前初始化“指定的存储空间”的硬件;
  2. 在 sct文件中增加“指定的存储空间”对应的执行域;
  3. 使用节区选择语句选择要分配到“指定的存储空间”的内容;
  4. 测试;

为什么要修改启动文件?

stm32专题三十七:自动分配变量到指定 SRAM 空间_第15张图片

试想一下,如果我们在程序中,将大量的 RW-data 定义到外部SRAM,那么在分散加载代码的过程中,系统会将原本保存在FLASH中的RW-data复制到SRAM中,这就要求我们必须先完成对外部SRAM的初始化,不然外部SRAM都起不来,还怎么保存数据呢?

修改启动文件如下所示:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第16张图片

在原来的启动文件中可以增加上述加粗表示的代码,增加的代码中使用到汇编语法 IMPORT,引入用户在其它C语言文件中定义的名为 FSMC_SRAM_Init 的函数(函数名要根据具体的程序来改),接着使用 LDR 指令加载函数的代码地址到寄存器 R0,最后使用BLX R0 指令跳转到 FSMC_SRAM_Init 的代码地址执行。

加入的代码实现了 Reset_handler 在执行__main 函数前先调用了我们自定义的FSMC_SRAM_Init函数,从而为分散加载代码准备好正常的硬件工作环境。

在 sct 文件中增加执行域:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第17张图片

关于为什么要定义 STACK 和 stm32f10x_rcc.o的描述:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第18张图片

stm32专题三十七:自动分配变量到指定 SRAM 空间_第19张图片

优先使用内部SRAM作为数据存储器的原因:

stm32专题三十七:自动分配变量到指定 SRAM 空间_第20张图片

 

你可能感兴趣的:(stm32专栏)