[STM32] The format and application of sct scattered loading files

Introduction

When the project is built according to the default configuration, MDK will learn the internal FLASH and internal SRAM memory overview of the chip based on the chip model we selected, and 自动生成a scatter loading file (Linker Control File, scatter loading) named after the project name with the suffix *.sct ), the linker allocates each section address according to the configuration of the file and generates scattered loading code, so we can modify the file 定制具体节区的存储位置.

Under normal circumstances, there is no need to write a scatter-loading file, which is automatically generated by the compiler and places certain data in the default location. But on some occasions, you want to put certain data in a specified location.

For example, you can set all variables defined in the source file to be automatically allocated to external SRAM by address, so that you no longer need to use the keyword " attribute " to specify by specific address;

Complex memory mapping: If code and data must be placed in multiple different memory regions, detailed instructions are required to specify which data is placed in which memory space.

Different types of memory: Many systems contain several different physical memory devices, such as flash, ROM, SDRAM, and fast SRAM. Scatter-loading descriptions match code and data to the most suitable memory type. For example, interrupt code can be placed in fast SRAM to reduce interrupt wait times, while infrequently used configuration information can be placed in slower flash memory.

Functions at fixed locations: Functions can be placed at fixed locations in memory, even if the surrounding application is modified and recompiled.

Use symbols to identify heap and stack: When you link your application, you can define some symbols for the heap and stack locations.

It can also be used to control the location of the code's loading area and execution area. For example, the program code can be stored in NAND-FLASH, which is cheap per unit capacity, but the code in NAND-FLASH cannot be provided directly like the code in the internal FLASH. For kernel operation, you can modify the scatter-loading file to set the code loading area to the program location of NAND-FLASH, and the program execution area to the location in SRAM, so that the linker will generate a matching Scatter loading code, this code will 把NAND-FLASH 中的代码加载到 SRAM 中,内核再从 SRAM 中运行主体代码,大部分运行Linux 系统的代码都是这样加载的.

sct file format

Insert image description here
In the default sct file configuration, only the addresses of large areas such as Code, RO-data, RW-data and ZI-data are allocated. During linking, each section (function, variable, etc.) is directly arranged into a specific address space according to its attributes.

The sct file mainly contains parts that describe the loading domain and the execution domain. One file can contain multiple loading domains, and a loading domain can be composed of multiple execution domains. Domains of the same level are separated by curly brackets "{}". The outermost layer is the loading domain , and the second layer of "{}" is the execution domain .

Insert image description here
Insert image description here

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
 
LR_IROM1 0x08000000 0x00020000  {
    
        
	//定义一个加载域,域地址0x08000000,域大小为0x00020000
    //load region size_region 所有代码需要下载到0x08000000 开始的区域中,且这个区域大小只有0x00020000 
  ER_IROM1 0x08000000 0x00020000  {
    
      
	//load address = execution address 第一个运行时域必须和加载域起始地址相同,其大小一般也相同
    //只能是只读的代码段和只读数据段
   *.o (RESET, +First)        //启动代码的首次执行地址,RO执行域名称为ER_IROM1, 
    //将 RESET 段最先加载到本域的起始地址外
    //首次执行的地址为RESET标号所表示的地址,RESET 存储的是向量表
    //对应启动文件中的AREA    RESET, CODE, READONLY
   *(InRoot$$Sections)     //稍后文件中会单独讲到
   .ANY (+RO) //加载所有匹配目标文件的只读属性数据,包含:Code、 RW-Code、 RO-Data。
  }
  RW_IRAM1 0x20000000 0x00005000  {
    
      
    //再定义一个运行时域,域基址0x20000000 
	//RW data 执行域是以0x20000000 开始的长度为0x00004000  一段区域
   .ANY (+RW +ZI)    //其中包括的是哪些文件
  }
}

Loading area description

加载域名 (基地址 | ("+" 地址偏移)) [属性列表] [最大容量]
{
    
    
	执行区域描述
}
LR_IROM1 0x08000000 0x00080000  {
    
        ; load region size_region
......
}

加载域名: Name, the description in the map file will use this name to identify the space. In this example, there is only one loading domain, which is LR_IROM1.
基地址+地址偏移: This part explains the base address of this load domain. You can use the + sign to connect an address offset and calculate it into the base address. The entire load domain uses their results as the base address. For example, the base address of the load domain in this example is 0x08000000, which happens to be the base address of the STM32 internal FLASH.
属性列表: The attribute list describes whether the loaded domain is an absolute address, N-byte alignment and other attributes. This configuration is optional. There are no properties describing the loading domain in this example.
最大容量: Maximum capacity specifies the maximum space that can be used by this loading domain. This configuration is also optional. If this configuration is added, when the linker finds that the space to be allocated to this area by the project is larger than the capacity, it will build the project. Prompts are given during the process. The maximum capacity of the load domain in this example is 0x00080000, which is 512KB, which is exactly the size of the internal FLASH space of this model STM32.

execution domain

执行域名 (基地址 | "+" 地址偏移) [属性列表] [最大容量 ]
{
    
    
///输入节区描述
}

The format of the execution domain is similar to that of the load domain. The only difference is the description of the input section.

Enter the usage of section description.o.ANY (+RO), etc.

In conjunction with the configuration of the loading domain and execution domain, configure "Enter section description" in the corresponding domain to control the section to be stored in the domain.

 //除模块选择样式部分外,其余部分都可选选填
 模块选择样式"("输入节区样式",""+"输入节区属性")"
 模块选择样式"("输入节区样式",""+"节区特性")"

 模块选择样式"("输入符号样式",""+"节区特性")"
 模块选择样式"("输入符号样式",""+"输入节区属性")"
 -----------------------------------------------------------------------------
    *.o (RESET, +First)        //启动代码的首次执行地址,RO执行域名称为ER_IROM1, 
    //将 RESET 段最先加载到本域的起始地址外
    //首次执行的地址为RESET标号所表示的地址,RESET 存储的是向量表
    //对应启动文件中的AREA    RESET, CODE, READONLY
   *(InRoot$$Sections)     //稍后文件中会单独讲到
   .ANY (+RO) //加载所有匹配目标文件的只读属性数据,包含:Code、 RW-Code、 RO-Data。
  ------------------------------------------------------------------------------

Module selection style: The module selection style can be used to select o and lib target files as input sections. It can directly use the target file name or the "*" wildcard, or you can use ".ANY".
“.o”All can be selected o 文件.
Use “.lib”can select all lib 文件.
Use “”或“.ANY”can select all o 文件及 lib 文件.
Among them, the ".ANY" selection statement has the lowest priority. The remaining data will be selected by the ".ANY" statement after all other selection statements have selected.

The RESET of the "(RESET, +First)" statement in the example file is the input section style. It selects the section named RESET and uses the section feature control word "+First" introduced later to indicate that it is to be stored in this section. The first address of the zone. "(InRoot$$Sections)" in the example file is a special selection symbol supported by the linker. It can select all sections in the standard library that are required to be stored in the root area, such as __main.o, __scatter.o, etc.

输入符号样式:Similarly, you can use the input symbol style to select the symbol to be controlled. The symbol style needs to be modified with ":gdef:". For example, you can use "*(:gdef:Value_Test)" to control the selection symbol "Value_Test".

输入节区属性: By adding the input section attribute after the module selection style, you can select different content in the style. A "+" sign must be written before each section attribute descriptor, separated by a space or a "," sign.

section attribute descriptor illustrate
RO-CODE and CODE read-only code snippet
RO-DATA and CONST read-only data segment
RO and TEXT Including RO-CODE and RO-DATA
RW-DATA Readable and writable data segments
RW-CODE Readable and writable code segments
RW and DATA Including RW-DATA and RW-CODE
ZI and BSS Readable and writable data segment initialized to 0
XO Executable only area
ENTRY Entry point of section

For example, in the sample file, use ".ANY(+RO)" to select all remaining sections. The contents of the RO attribute are allocated to the execution domain ER_IROM1. Use ".ANY(+RW +ZI)" to select all remaining sections RW and ZI. The contents of the attributes are allocated to the execution domain RW_IRAM1.

节区特性: The section attribute can use the "+FIRST" or "+LAST" option to configure the location where it is stored. FIRST is stored at the head of the area, and LAST is stored at the tail. Usually important sections are placed at the head, and data such as CheckSum (checksum) are placed at the tail.

For example, in the sample file, "(RESET,+First)" is used to select the RESET section area and requires it to be placed at the first position in this area, and RESET is the vector table defined in the project startup code.

    *.o (RESET, +First)        //启动代码的首次执行地址,RO执行域名称为ER_IROM1, 
    //将 RESET 段最先加载到本域的起始地址外
    //首次执行的地址为RESET标号所表示的地址,RESET 存储的是向量表

As shown in the figure, the top of the stack and the reset vector pointer defined in the vector table in the startup file must be stored in the first two addresses of the internal FLASH so that STM32 can start normally, so FIRST must be used to control them to be stored at the first address.

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

 __Vectors DCD __initial_sp; Top of Stack
 DCD Reset_Handler; Reset Handler
 DCD NMI_Handler; NMI Handler

Modify sct files through MDK configuration options

The .sct file is usually in the project folder.

Select how sct files are generated

First, you need to choose how to generate the sct file, whether to use MDK to generate it or use a user-defined sct file . This selection can be configured in the MDK's "Options for Target->Linker->Use Memory Layout from Target Dialog" option.
Insert image description here
1. When checked, keil will generate sct files according to the configuration . keil will generate sct files based on the options in the "Options for Target" dialog box. In this case, even if we manually open the sct file it generates for editing, it will be invalid because MDK will generate a new sct every time the project is built. The file overwrites the old file. This option is checked by default in MDK. If you want MDK to use the sct file we manually edited to build the project, you need to uncheck it and specify the path to the sct file in the Scatter File box.

When generated by keil

Check Use Memory Layout from Target Dialog, and keil will generate the sct file according to the configuration . keil will generate sct files based on the options in the "Options for Target" dialog box.

The internal ROM option in the MDK option can only fill in two option positions at most. If you want to divide the internal ROM into multiple pieces of address management, it cannot be achieved. In addition, the minimum granularity that the MDK configuration can control is a file. If you want to control a specific section, you need to Edit sct files directly

Configure keil options to change sct files

1. Select the chip type in the Device tab
Insert image description here
. 2. After selecting the chip model as STM32F103ZE, the memory information in the Target tab will be updated according to the chip.
In the Target tab, the memory information is divided into two categories: read-only memory (Read/Only Memory Areas) and read/write memory (Read/Write Memory Areas), namely ROM and RAM, and they are further subdivided into off-chip memory (off-chip memory). -chip) and on-chip memory (on-chip).

Modify the storage information in the Target tab, for example, divide the SRAM inside the STM32 into two equal parts.
Insert image description here
Modify the sct file content after modifying the IRAM1 base address.

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

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

Control files are allocated to the specified storage space

After setting the memory information, you can control which part of the memory each source file is customized to. In the project file column of MDK, select the file to be configured, right-click, and select "Options for File xxxx" in the pop-up menu. A file configuration dialog box can pop up, in which memory customization can be performed.
Insert image description here
There is a "Memory Assignment" area (memory allocation) in the dialog box, in which various attribute contents of the file can be allocated, such as Code/Const content (RO), Zero Initialized Data content (ZIdata) and Other Data content (RW-data), IROM1, IRAM1, IRAM2 and other memories.

For example, in the figure, we allocate the contents of the Other Data attribute of the bsp_led.c file to the IRAM2 memory (we checked IRAM1 and IRAM2 in the Target tab). When some RW-data contents are defined in the bsp_led.c file ( For example, a global variable with an initial value other than 0), the variable will be allocated to the IRAM2 space. After the configuration is completed, click OK, then compile the project and view the contents of the sct file.

LR_IROM1 0x08000000 0x00080000{
    
     ; load region size_region
	ER_IROM1 0x08000000 0x00080000{
    
     ; load address = execution address
		*.o (RESET, +First)
		*(InRoot$$Sections)
		.ANY (+RO)
	}
	RW_IRAM1 0x20000000 0x00008000 {
    
     ; RW data
		.ANY (+RW +ZI)
	}
	 RW_IRAM2 0x20008000 0x00008000 {
    
     
	 bsp_led.o (+RW)
	 .ANY (+RW +ZI)
	}
 }

It can be seen that a statement to select the RW content in bsp_led.o has been added to the RW_IRAM2 execution domain in the sct file.

Manually modify sct files

Although these memory configuration options of MDK are very convenient, many advanced configurations still need to be manually written in sct files. For example, the internal ROM option in MDK options can only fill in two option positions at most. If you want to divide the internal ROM into multiple slices, Address management cannot be realized; in addition, the smallest granularity controllable by MDK configuration is a file. If you want to control a specific section, you also need to edit the sct file directly.

Added description of "_ _ attribute __" keyword

When you need to specify the memory address of a variable, MDK provides a keyword "_ _ attribute _ _" to implement this function.

/*要指定的地址*/
 #define USER_ADDR((uint32_t)0x20005000)
 
 uint8_t testValue __attribute__((at(USER_ADDR)));/*使用 atribute 指定该变量存储到 USER_ADDR,这种方式必须定义成全局变量*/
 testValue = 0xDD;

The formula uses " attribute ((at()))" to specify the address of the variable. The testValue specified in the code is stored in the USER_ADDR address 0x20005000. If the address is changed to the address of the external memory SRAM, the variable will be stored in the external SRAM. , so this keyword can be used to customize the space allocation of various memories to a certain extent. It should be noted that when using this method to define a variable, it must be defined as a global variable outside the function before it can be stored at the specified address.

When there are multiple such variables, in order to prevent the space occupied by the variables from overlapping, or to reduce the fragmented space for full utilization, it is necessary to manually calculate the addresses of each variable, which is very troublesome. Use the sct file to let the linker automatically allocate global variables to the specified The storage area and management can make using the specified storage area as simple as ordinary variable definition.

Example: Automatically allocate variables to the specified SRAM space

Uncheck Options for Target->Linker->Use Memory Layout from Target Dialog

(1) Modify the startup file and initialize the hardware of the "specified storage space" before __main is executed.
(2) Add the execution domain corresponding to the "specified storage space" in the sct file;
(3) Use the section selection statement to select the desired storage space. The content allocated to the "specified storage space";
(4) Write a test program, and after the compilation is normal, check the space allocation of the map file.

1. Modify the startup file to initialize the external "specified storage space" hardware before __main

After the chip is started, the scatter-loading code __scatterload will be called in ResetHandler through the __main function. The scatter-loading code will copy the RW-data stored in FLASH to RAM, then open up a ZI-data space in the RAM area, and It is initialized to a value of 0.

Therefore, in order to ensure that the variables defined in the "specified storage space" in the program can be initialized normally, we need to make the memory used by the space operate normally before the system executes the scatter-loading code, so that it can save data normally. If the initialization of the memory is executed in the main function of C language, then because the memory does not work properly during __scatterload, the copy process is invalid, and the initial value of the RW-data type variable will be abnormal, which will cause the program to run inconsistently. expected.

So you need to modify the startup file
Insert image description here

; Reset handler//注释
Reset_Handler 	PROC //Reset_Handler程序开始
				EXPORT Reset_Handler[WEAK]
				IMPORT SystemInit//导入  SystemInit函数
				IMPORT __main
// 从外部文件引入声明, 格式:IMPORT 要调用的初始化函数名
// 以下语句仅作演示,使用外部存储器时请去掉注释用的“; ”号,本工程使用内部 SRAM,无需初始化
				; IMPORT FSMC_SRAM_Init//使用外部RAM的时候,需要初始化FSMC这个外设
				 LDR R0, =SystemInit//将 SystemInit函数地址赋值到R0 执行R0 也就是说执行 SystemInit函数,初始化时钟等
				 BLX R0

				; 在__main 之前调用 FSMC_SRAM_Init 进行初始化
//以下语句仅作演示,使用外部存储器时请去掉注释用的“; ”号,本工程使用内部 SRAM,无需初始化
				; LDR R0, =FSMC_SRAM_Init//使用外部RAM的时候,需要初始化FSMC这个外设
				; BLX R0
		
		 		LDR R0, =__main
				 BX R0
		 		ENDP

If you need to use expanded SRAM, you need to start the FSMC peripheral before entering the __main function so that the chip can operate the external SRAM. The STM32 peripheral FSMC does not need to do this if it does not use external SRAM.

Introduce the function named FSMC_SRAM_Init defined by the user in other C language files, then use the LDR instruction to load the code address of the function into register R0, and finally use the BLX R0 instruction to jump to the code address of FSMC_SRAM_Init for execution.

2. Modify the sct file and add the execution domain corresponding to the "specified storage space" in the sct file.

To modify the sct file, control the global variables defined in the C source file to be automatically allocated to the "specified storage space" by the linker (the example here is the internal SRAM space at the address 0x20005000 to 0x2000C000)

 *************************************************************
 *** Scatter - Loading Description File generated by uVision ***
 *************************************************************

LR_IROM1 0x08000000 0x00080000{
    
    ; 加载域
	ER_IROM1 0x08000000 0x00080000{
    
    ; 加载地址 = 执行地址
		* .o(RESET, +First)
		* (InRoot$$Sections)
		ANY(+RO)
	 }
	 RW_IRAM1 0x20000000 0x00005000 {
    
    ; 内部 SRAM
		 * .o(STACK); 选择 STACK 节区,栈
		 stm32f10x_rcc.o(+RW); 选择 stm32f10x_rcc 的 RW 内容
		.ANY(+RW + ZI); 其余的 RW / ZI - data 都分配到这里
	 }
	 RW_ERAM1 0x20005000 0x00007000{
    
    ; “指定的存储空间”
		.ANY(+RW + ZI); 其余的 RW / ZI - data 都分配到这里
 		}
 }

There are two points to note:
1. RW_ERAM1 0x20005000 0x00007000{}

RW_ERAM1 is the execution domain of the "specified storage space" we configured. The name of the execution domain can be chosen casually . The most important thing is its 基地址及空间大小. In this case, the starting address and offset are both in the on-chip RAM. Inside.

Within the RW_ERAM1 execution domain, it uses the ".ANY(+RW +ZI)" statement to select all RW/ZI type data to be allocated to this "specified storage space", so we define the C file in the project When global variables are used, they will be allocated to this area . If external extended memory is used, these data will be stored in the corresponding memory.

2. RW_IRAM1 execution domain
simply uses the external memory SRAM. You need to add a " .o(STACK) and stm32f10x_rcc.o(+RW)" statement to the RW_IRAM1 execution domain (the following paragraph is the reason, you can ignore it)
. If the "specified storage space" belongs to the internal SRAM, there is no problem if the ".o(STACK) and stm32f10x_rcc.o(+RW)" statements are not added.

This is the execution domain in the original sct file. "*.o(STACK) and stm32f10x_rcc.o(+RW)" statements are added to its execution domain configuration.

Originally, after configuring the external SRAM execution domain above, the purpose of global variable allocation has been achieved. Why do we need to modify the original internal SRAM execution domain?

When using externally mounted SRAM.

This is because if the FSMC_SRAM_Init external memory initialization function called before __main calls many library functions, and some local variables are defined inside these functions, and the local variables within the functions need to be allocated to the "stack" space (STACK), so Before the FSMC_SRAM_Init function is executed, the stack space must be prepared. However, before the FSMC_SRAM_Init function is executed, the external memory is not working properly. This contradiction results in the stack space not being allocated to the external memory area.

Although the ".ANY(+RW +ZI)" statement is used in the execution domain RW_IRAM1 of the internal SRAM and the "specified storage space" execution domain RW_ERAM1 to select all the contents of the RW and ZI attributes, for those that match the two same selection statements content, the linker will give priority to the execution domain with larger space. In this case, only when the space of the "specified storage space" execution domain is used up, the content of the RW/ZI attribute will be allocated to the internal SRAM.

So in most cases, the ".ANY(+RW +ZI)" statement in the internal SRAM execution domain does not work, and the stack section area (STACK) belongs to the ZI-data class. If our internal SRAM executes If the domain is still configured according to the original default configuration, the stack section area will be allocated to the "specified storage space". If the "specified storage space" uses external memory at this time, an error will occur. In order to avoid this problem, we allocate the stack section area to the execution domain of the internal SRAM using the "*.o(STACK)" statement.

The "stm32f10x_rcc.o(+RW)" statement is added because the FSMC_SRAM_Init function that initializes the external memory may call the RCC_AHBPeriphClockCmd function in the stm32f10x_rcc.c file. After viewing the map file, we learned that stm32f10x_rcc.c defines some RW-data type variables. . Regardless of whether these data are used during the FSMC_SRAM_Init call, for insurance purposes, we directly allocate this part of the content to the execution area of ​​the internal SRAM.

Example: Prioritize the use of internal SRAM and allocate the heap area to the specified space

Configure the sct file so that the internal SRAM space is used first by default. When needed, use a keyword to specify that the variable is stored in the "specified storage space". In addition, we also map the system default heap space (HEAP) to the "specified storage space". "storage space", so that you can use the malloc function of the C language standard library to dynamically allocate variables from it, and use the standard library to manage the memory of this space, which is very useful in external memory management.

1. Modify the startup file to initialize the external "specified storage space" hardware before __main

Modify the Reset_handler function in the startup file of the project startup_stm32f10x.s, and call the initialization function of the memory before the __main function to make the hardware operate normally.

; Reset handler//注释
Reset_Handler 	PROC //Reset_Handler程序开始
				EXPORT Reset_Handler[WEAK]
				IMPORT SystemInit//导入  SystemInit函数
				IMPORT __main
// 从外部文件引入声明, 格式:IMPORT 要调用的初始化函数名
// 以下语句仅作演示,使用外部存储器时请去掉注释用的“; ”号,本工程使用内部 SRAM,无需初始化
				; IMPORT FSMC_SRAM_Init//使用外部RAM的时候,需要初始化FSMC这个外设
				 LDR R0, =SystemInit//将 SystemInit函数地址赋值到R0 执行R0 也就是说执行 SystemInit函数,初始化时钟等
				 BLX R0

				; 在__main 之前调用 FSMC_SRAM_Init 进行初始化
//以下语句仅作演示,使用外部存储器时请去掉注释用的“; ”号,本工程使用内部 SRAM,无需初始化
				; LDR R0, =FSMC_SRAM_Init//使用外部RAM的时候,需要初始化FSMC这个外设
				; BLX R0
		
		 		LDR R0, =__main
				 BX R0
		 		ENDP

2. Modify the sct file and add the execution domain corresponding to the "specified storage space" in the sct file.

 *************************************************************
 *** Scatter - Loading Description File generated by uVision ***
 *************************************************************

LR_IROM1 0x08000000 0x00080000{
    
    ; 加载域
	ER_IROM1 0x08000000 0x00080000{
    
    ; 加载地址 = 执行地址
		* .o(RESET, +First)
		* (InRoot$$Sections)
		ANY(+RO)
	 }
	 RW_IRAM1 0x20000000 0x00005000 {
    
    ; 内部 SRAM
		 * .o(STACK); 选择 STACK 节区,栈
		 stm32f10x_rcc.o(+RW); 选择 stm32f10x_rcc 的 RW 内容
		.ANY(+RW + ZI); 其余的 RW / ZI - data 都分配到这里
	 }
	 RW_ERAM1 0x20005000 0x00007000{
    
    ; “指定的存储空间”
	 	*.o(HEAP) ;选择堆区
		.ANY (EXRAM) ;选择 EXRAM 节区
 		}
 }

Use "*.o(HEAP)" to allocate all heap areas to RW_ERAM1, and use the ".ANY(EXRAM)" statement to allocate the section area named "EXRAM" to RW_ERAM1.

“EXRAM”节区It is customized by us. The syntax is similar to defining global variables in a C file, as long as it is different from other original section names in the project. With this section selection configuration, when we need to define a variable to the "specified storage space", we only need to specify that the variable is allocated to the section, and it will be allocated to the space.

3. Allocate specified variables to sections

The two points 1.2 have been set up before, and the next step is to use it.

Usage 1

//使用 __attribute__ 关键字定义指定变量定义到某节区

//语法: 变量定义 __attribute__ ((section ("节区名"))) = 变量值; 
uint32_t testValue __attribute__((section("EXRAM"))) = 7;

"Variable definition attribute ((section ("section name"))) = variable value;", its main body is the same as the ordinary C language variable definition syntax. Before the assignment "=" sign (you don't need to assign an initial value
) , adding a “__attribute__ ((section ("节区名")))”description of the section it is allocated to. The section name in this example is “EXRAM”that we select the section allocated to the "specified storage space" execution domain in the sct file, so the variable is allocated to this memory.

Usage 2

//使用宏封装 
//设置变量定义到“EXRAM”节区的宏
#define __EXRAM __attribute__((section("EXRAM")))

//使用该宏定义变量到“指定的存储空间”
 uint32_t testValue __EXRAM = 7;

Since “__attribute__”keywords are cumbersome to write, we can use 宏定义把它封装them to simplify the code. In this example, we assign the description statement to "EXRAM" . When applying it, we only need to replace the position of the original " attribute " keyword “__attribute__ ((section ("EXRAM")))”封装成了宏“ __EXRAM”with the name of the macro , such as "uint32_t testValue __EXRAM =7;". Readers who have experience in using 51 microcontrollers will find that this variable definition method is similar to using the keil 51 unique keyword "xdata" to define variables in the external RAM space.

Guess you like

Origin blog.csdn.net/apythonlearner/article/details/133034055