//=====================================================================
//TITLE:
// 修正STM32F103ZE的散列文件
//AUTHOR:
// norains
//DATE:
// Tuesday 20-October-2010
//Environment:
// KEIL MDK 4.0
// .NET Micro Framework Porting 4.1
// RedCow Board
//=====================================================================
如果你需要编译NativeSample工程,那么不可避免地就需要接触到散列文件。对于MDK来说,所用到的则是scatterfile_tools_mdk.xml文件。只不过,如果你是采用默认生成的数值,那么结果会让你很郁闷。那么,为了能有一个快乐的移植之旅,我们现在就来看看这些数值应该如何更改。
在开始之前,我们先来了解一下向量表。对于CORTEX-M3来说,向量表应该位于0x00000000位置。为什么是这个位置呢?因为复位之后,PC指针指向0x00000000。所以,我们先有这么个概念,在开始调试之后,PC应该指向向量表的地址。
对于原来的散列文件内容,有一点不太喜欢的是,居然将向量表和代码分开了,如:
两者分开之后,如果数值设置不好的话,会有很严重的后果,比如向量表会被一些印射的代码所覆盖,或是向量表没有圆整到2的次幂,等等。所以,这里我是将这两者合而为一,如:
当我们以FLASH方式编译时,内存印射如下:
如果以RAM方式编译,内存印射如下:
完整的散列文件scatterfile_tools_mdk.xml内容如下:
<?xml version="1.0"?>
<ScatterFile xmlns="http://schemas.microsoft.com/netmf/ScatterfileSchema.xsd">
<Set Name="Valid" Value="false"/>
<!-- ################################################################################ -->
<If Name="TARGETLOCATION" Value="RAM">
<Set Name="Heap_Begin" Value="0x20002BFC"/>
<Set Name="Heap_End" Value="0x20002DFC"/>
<Set Name="Stack_Bottom" Value="+0"/>
<Set Name="Stack_Top" Value="0x20002FFC"/>
<Set Name="ER_RAM_BaseAddress" Value="0x20003000"/>
</If>
<If Name="TARGETLOCATION" Value="RAM">
<Set Name="Code_BaseAddress" Value="0x20004000"/>
<Set Name="Code_Size" Value="0x0000C000"/>
<Set Name="Valid" Value="true"/>
</If>
<If Name="TARGETLOCATION" Value="FLASH">
<Set Name="Heap_Begin" Value="0x2000EBFC"/>
<Set Name="Heap_End" Value="0x2000EDFC"/>
<Set Name="Stack_Bottom" Value="+0"/>
<Set Name="Stack_Top" Value="0x2000EFFC"/>
<Set Name="ER_RAM_BaseAddress" Value="0x2000F000"/>
</If>
<If Name="TARGETLOCATION" Value="FLASH">
<Set Name="Config_BaseAddress" Value="0x08070000"/>
<Set Name="Config_Size" Value="0x00010000"/>
<Set Name="Code_BaseAddress" Value="0x08000000"/>
<Set Name="Code_Size" Value="0x00060000"/>
<Set Name="Valid" Value="true"/>
<IfDefined Name="ALTERNATEFLASHLOCATION">
<!-- Set Name="Code_BaseAddress" Value="%Code_BaseAddress + Code_Size%"/ -->
</IfDefined>
</If>
<!-- ################################################################################ -->
<If Name="Valid" Value="false">
<Error Message="Configuration not recognized"/>
</If>
<LoadRegion Name="LR_%TARGETLOCATION%" Base="%Code_BaseAddress%" Options="ABSOLUTE" Size="%Code_Size%">
<ExecRegion Name="ER_%TARGETLOCATION%" Base="%Code_BaseAddress%" Options="FIXED" Size="">
<FileMapping Name="VectorsTrampolines.obj" Options="(+RO, +FIRST)" /> <!-- for vector handlers to be far from the vectors -->
<FileMapping Name="FirstEntry.obj" Options="(+RO)" /> <!-- the entry pointer section goes into this region -->
<FileMapping Name="ramtest.obj" Options="(+RO)" /> <!-- this must live somewhere other than RAM, for all but RAM builds -->
<FileMapping Name="*" Options="(SectionForBootstrapOperations)" />
<FileMapping Name="*" Options="(+RO-CODE)" />
<FileMapping Name="*" Options="(+RO-DATA)" />
</ExecRegion>
<ExecRegion Name="ER_RAM_RO" Base="%ER_RAM_BaseAddress%" Options="ABSOLUTE" Size="">
<FileMapping Name="*" Options="(SectionForFlashOperations)" />
</ExecRegion>
<ExecRegion Name="ER_RAM_RW" Base="+0" Options="ABSOLUTE" Size="">
<FileMapping Name="*" Options="(+RW-DATA, +ZI)" />
</ExecRegion>
<ExecRegion Name="ER_HEAP_BEGIN" Base="%Heap_Begin%" Options="ABSOLUTE" Size="UNINIT">
<FileMapping Name="*" Options="(SectionForHeapBegin)" />
</ExecRegion>
<!-- everything between heapbegin and heapend will be allocated for a heap -->
<ExecRegion Name="ER_HEAP_END" Base="%Heap_End%" Options="ABSOLUTE" Size="UNINIT">
<FileMapping Name="*" Options="(SectionForHeapEnd)" />
</ExecRegion>
<!-- this must go last here to provide a low water mark on the stack -->
<ExecRegion Name="ER_STACK_BOTTOM" Base="%Stack_Bottom%" Options="ABSOLUTE" Size="UNINIT">
<FileMapping Name="*" Options="(SectionForStackBottom)" />
</ExecRegion>
<ExecRegion Name="ER_STACK_TOP" Base="%Stack_Top%" Options="ABSOLUTE" Size="UNINIT">
<FileMapping Name="*" Options="(SectionForStackTop)" />
</ExecRegion>
</LoadRegion>
<IfDefined Name="Config_BaseAddress">
<LoadRegion Name="LR_CONFIG" Base="%Config_BaseAddress%" Options="ABSOLUTE" Size="%Config_Size%">
<ExecRegion Name="ER_CONFIG" Base="%Config_BaseAddress%" Options="FIXED" Size="%Config_Size%">
<FileMapping Name="*" Options="(SectionForConfig)" />
</ExecRegion>
</LoadRegion>
</IfDefined>
</ScatterFile>
看得比较仔细的朋友,可能会发现这句已经被注释掉了:
<!-- Set Name="Code_BaseAddress" Value="%Code_BaseAddress + Code_Size%"/ -->
如果不注释掉的话,那么代码是从高位向低位生长,而这却和STM32F103ZE的实际情况相反。所以这里就必须将其注释掉,以让代码从低位往高位生长。
如果编译的是FLASH方式,可以直接通过MDK下载NativeSample.axf文件到开发板中,就能够正常运行。但如果是RAM方式,还需要配合脚本文件。因为编译的是RAM方式的话,如果PC指针默认指向ARM_Vectors,则执行会出现异常,但原因我还暂时还不清楚。不过,这个有个变通的方式,开始调试时,通过脚本文件将PC指针指向EntryPoint函数即可。和RAM配合的完整的脚本文件内容如下:
FUNC void InitNVIC(void)
{
_WDWORD(0xE000ED08,0x20004000);
}
InitNVIC();
PC = EntryPoint;
需要注意的是,这个脚本文件只能配合RAM方式,如果是FLASH,因为ARM_Vectors的位置和向量表寄存器的数值不符,则会导致程序异常。