//=====================================================================
//TITLE:
// CheckMultipleBlocks函数引发的异常与解决
//AUTHOR:
// norains
//DATE:
// Wednesday 12-January-2011
//Environment:
// .Net Micro Framework Porting 4.1
// MDK V4.0.0
// VS2010
//=====================================================================
最近在调试TinyCLR的时候,发现程序一定会跑到AppDomain_Mark函数,并且执行到函数内的CheckMultipleBlocks调用必定会发生Hard Fault异常。查了很多文档,也做了很多猜测性调试,一直都没有解决该问题。
在百般苦恼的时候,抱着死马当活马医的态度,将叶帆的《TinyCLR编译与测试》(http://blog.csdn.net/yefanqiu/archive/2010/02/18/5310634.aspx)一文中的配置放到我的工程中,没想到,奇迹出现了,程序再也没有跑到AppDomain_Mark里,但却正常输出了.Net Micro Framework的相关信息!
这究竟是怎么一回事呢?经过多次的对比测试,发现原因出在Heap的设置上。因为我想使用单芯片解决方案,不采用外部RAM,想将Heap,Custom_Heap和Stack全部放到STM32F103ZE的内部RAM中,所以书写了如下的内存分配:
<Set Name="Heap_Begin" Value="0x20005200"/>
<Set Name="Heap_End" Value="0x20008CFC"/>
<Set Name="Custom_Heap_Begin" Value="0x20008D00"/>
<Set Name="Custom_Heap_End" Value="0x20008DFC"/>
<Set Name="Stack_Bottom" Value="0x20008E00"/>
<Set Name="Stack_Top" Value="0x20008FFC"/>
Heap的大小为0x20008CFC - 0x20005200 = 0x3AFC = 15 100,也就是大概15KB左右,而这个对于TinyCLR来说太小了,完全就不能满足最小的需求。看到这里,也许有人说,为什么不把Heap_Begin的数值往前移一点,变为0x20003000之类?这也是不可能的。因为在编译TinyCLR的时候,0x20005200之前的内存已经被使用殆尽,再也没有可用的余地了。打开tinyclr.symdefs文件,我们就能够清晰看到这点,如图:
那往前不行,往后可以么?查看了一下我的配置文件,发现有这么一节也是占用RAM的:
<IfDefined Name="PROFILE_BUILD">
<Set Name="ProfileBuffer_Begin" Value="0x20009000"/>
<Set Name="ProfileBuffer_End" Value="0x2000EFFC"/>
</IfDefined>
但在实际测试中,发现将ProfileBuffer屏蔽掉后其实也是可以正常编译的。换句话来说,ProfileBuffer在目前的编译方式中,是可有可无的,那么为什么我们不物尽其用,将其所占据的这部份内存拿来挥霍呢?于是,我们的离散文件可以更改配置如下:
<Set Name="Heap_Begin" Value="0x20008000"/>
<Set Name="Heap_End" Value="0x2000DFFC"/>
<Set Name="Custom_Heap_Begin" Value="+0"/>
<Set Name="Custom_Heap_End" Value="0x2000EFFC"/>
<Set Name="Stack_Bottom" Value="+0"/>
<Set Name="Stack_Top" Value="0x2000FFFC"/>
编译,测试,一切顺利!TinyCLR正常跑起来了!
但这还是留下了小小的隐患,因为目前TinyCLR还比较小,并没有挂载相应的.NMF程序。如果以后放置了更多的.NMF应用程序,会不会因为RAM空间不够,再次引发类似的莫名其妙的问题呢?这个确实不好说。不过,对此我们也并不是没有办法,开发板不是还有外部的RAM么?如果担心内部的64K RAM不够用,我们完全可以用外部的RAM嘛!我们可以将,Heap和Custom_Heap放置到外部RAM,而Stack依旧放置到内部的RAM,也就是说这时候的离散文件配置如下:
<Set Name="Heap_Begin" Value="0x68000000"/>
<Set Name="Heap_End" Value="0x6801DFFC"/>
<Set Name="Custom_Heap_Begin" Value="0x6801E000"/>
<Set Name="Custom_Heap_End" Value="0x6801FFFC"/>
<Set Name="Stack_Bottom" Value="0x20008000"/>
<Set Name="Stack_Top" Value="0x2000FFFC"/>
编译,将TinyCLR下载到开发板,运行,也是一切顺利!TinyCLR也能够在外部RAM跑起来了!