本帖最后由 guiyan 于 2024-1-13 16:31 编辑
前言本文旨在APM32F4xx系列GPIO例程Keil MDK环境下,如何自定义散列文件stc,实现各数据段分区管理,存放在指定内存位置。 一 程序文件中的分区- Code:即代码域,它指的是编译器生成的机器指令。
- RO_data:ReadOnly data,即只读数据域,它指程序中用到的只读数据,全局变量,例如C语言中const关键字定义的全局变量就是典型的RO-data。
- RW_data:ReadWrite data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且 运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。 例如全局变量或者静态变量,且定义时赋予“非0值”给该变量进行初始化。
- ZI_data:ZeroInitialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW_data的区别是程序刚运行时这些数据初始值全都为0,而 后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。 包括未初始化的全局变量,和初始化为0的全局变量。
RW_data和ZI_data,在程序运行的开始阶段,就需要从Flash中复制到RAM中。 - RO:只读区域,包括RO_data和code。
散列文件sct介绍详细可参考官方文档ARM Compiler v5.06 for µVision armlink User Guide的Scatter File Syntax
官方文档路径在Keil安装目录:
C:\Keil_v5\ARM\Hlp\armtools.chm
C:\Keil_v5\ARM\Hlp\DUI0377G_02_mdk_armlink_user_guide.pdf
散列文件sct总览
简单分析:- 加载域 LOAD_ROM_1(起始地址为0x0000) 和 LOAD_ROM_2(起始地址为0x4000)
意思是该区域数据全部都会下载到以起始地址开始的内存空间中。 - 执行域 EXEC_ROM_1(起始地址为0x0000) 和 EXEC_ROM_2(起始地址为0x4000)
意思是输入段的数据,会从这个地址开始执行。
有2种情况:
- 直接从Flash加载域执行
- 把Flash加载域的数据,复制到RAM中,从RAM执行
- 输入段描述
program1.o (+RO):RO属性的数据
program1.o (+RW,+ZI): RW和ZI的数据
program2.o (+RO):RO属性的数据
program2.o (+RW,+ZI): RW和ZI的数据
综上:
就是从0x0000开始下载program1.o的RO数据,并从0x0000执行;
从RO数据结束的地方,紧接着下载program1.o RW数据,但程序运行时,会把RW和ZI数据复制到0x18000开始的内存中执行。
program2.o RO、RW和ZI同理。 前缀符 :gdef: 的使用 在散列文件sct中,可以通过使用前缀符 :gdef: 来存放全局符号( 同个C文件所有全局变量 或者全局函数名)到特定位置上。 /* 示例1 Delay_ms函数*/
void Delay_ms(__IO u32 nms)
{
SysTick_Config(SystemCoreClock / 1000);
cntMs = nms;
while(cntMs != 0);
}
;Delay_ms function
LR_IROM2 0x08005000 0x00004000 { ; load region size_region
ER_IROM2 0x08005000 0x00004000 { ; load address = execution address
*(:gdef:Delay_ms)//Delay_ms函数存放到固定位置0x08005000地址上
}
}
查看map文件: 数据段分区管理应用 在APM32F4xx系列GPIO例程中,修改sct文件,修改如下: ; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
;vctor
LR_ROM_VCTOR 0x08000000 0x00001000 { ; load region size_region
ER_ROM_VCTOR 0x08000000 0x00001000 { ; load address = execution address
*.o (RESET, +First)
}
}
;entry
LR_ROM_ENTRY 0x08001000 0x00000100 { ; load region size_region
ER_ROM_ENTRY 0x08001000 0x00000100 { ; load address = execution address
*(InRoot$Sections)
}
}
;code
LR_ROM_CODE 0x08002000 0x00004000 { ; load region size_region
ER_ROM_CODE 0x08002000 0x00004000 { ; load address = execution address
.ANY (+CODE)
}
}
;const data
LR_ROM_CONST 0x08003000 0x00002000 { ; load region size_region
ER_ROM_CONST 0x20001000 0x00002000 { ; load address = execution address
.ANY (+CONST)
}
}
;rw data
LR_ROM_RW 0x08004000 0x00002000 { ; load region size_region
ER_ROM_RW 0x20000000 0x00002000 { ; load address = execution address
.ANY (+RW +ZI)
}
}
;Delay_ms function
LR_IROM2 0x08005000 0x00004000 { ; load region size_region
ER_IROM2 0x08005000 0x00004000 { ; load address = execution address
*(:gdef:Delay_ms)
}
}
查看map文件,分区管理成功,并能下载程序正常运行。 例程请见附件。
|