在前面的系列文章中我們不厭其煩地一一介紹了在NativeSample中如何開發和調試驅動。從今天開始,我們將介紹TinyCLR項目的相關知識,也許讀者以為這又得需要洋洋灑灑十幾篇才能介紹的完,其實不然,這將是該系列中唯一篇介紹TinyCLR的文章。
由于TinyCLR的相關代碼與硬件無關,我們所做的就是根據實際需要,添加不同的Feature,此外就是合理配置堆棧和代碼存儲位置。其主要工作,具體地來說就是搞定\Solutions\STM3210E\TinyCLR目錄下的TinyCLR.proj和scatterfile_tinyclr_mdk.xml文件。
TinyCLR.proj文件和NativeSample.proj的內容類似,不過額外要添加一些由托管代碼(C#)寫好的庫,比較重要的就是mscorlib.pe,它是TinyCLR的核心文件,大小大概29k。這里也許讀者會奇怪,它的擴展名為什么是pe而不是windows系統上的dll,其實.Net Micro Framework的托管代碼編譯和桌面版的沒有什么不同,用的都是VS2008環境中的Csc.exe,我們的MF程序所引用的Program Files\Microsoft .NET Micro Framework\v4.0\Assemblies目錄下的庫(擴展名為dll的文件),其實就是由Csc.exe編譯而成的,它和.Net Framework沒有任何本質區別,可直接在彼此的工程中互為引用。換句話說dll文件是給我們在PC上編譯.Net Micro Framework時用的,而pe文件才是真正下載到硬件平臺給我們的嵌入式系統用的文件。
那pe文件和dll文件又是什么關系呢?其實pe文件是Program Files\Microsoft .NET Micro Framework\v4.0\Tools \MetaDataProcessor.exe對dll再編譯(更確切的說是刪減和處理)后的文件,其大小大概為原dll文件的一半,如mscorlib.dll文件為85.8k,而mscorlib.pe文件為29k。我們的TinyCLR就是這些pe文件的執行引擎(更詳盡的內容我將在以后準備寫的【玩轉.Net MF】系列文章中介紹pe文件的相關知識)。
我們說過,由于EM-STM3210E開發板的RAM太小,所以我們一開始就得要調試Flash版本的TinyCLR,由于TinyCLR在創建程序集實例時,定義了一個與程序集同樣大小的數組,所以我們的棧至少要大于我們我所要加載的最大的pe文件,比如至少要大于29k。堆是給托管代碼的對象用的,可以根據實際需要定義大小,針對EM-STM3210E開發板scatterfile_tinyclr_mdk.xml的最終配置如下:
<If?Name="TARGETLOCATION"?In="FLASH"> ??????????<!--?120k?--> ??????????<Set?Name="Heap_Begin"??????????Value="0x68000000"/> ???????????<Set?Name="Heap_End"????????????Value="0x6801DFFC"/> ??????????<!--?8k?--> ???????????<Set?Name="Custom_Heap_Begin"???Value="0x6801E000"/> ??????????<Set?Name="Custom_Heap_End"?????Value="0x6801FFFC"/> ???????????<!--?32k?--> ???????????<Set?Name="Stack_Bottom"????????Value="0x20008000"/> ???????????<Set?Name="Stack_Top"???????????Value="0x2000FFFC"/> ??? ??????????<Set?Name="Code_BaseAddress"????Value="0x08000000"/> ??????????<Set?Name="Code_Size"???????????Value="0x00080000"/> ?????????? ??????????<Set?Name="Config_BaseAddress"?Value="0x00000000"/>???? ??????????<Set?Name="Config_Size"?????????Value="0x00020000"/>???? ?????????? ??????????<Set?Name="Deploy_BaseAddress"?Value="0x00020000"/>???????? ??????????<Set?Name="Valid"???????????????Value="true"/> ??????</If> ?? 其中Config是放在NandFlash上的。
Custom_Heap是在V4.0才加入的,主要給Native Code用的,而Heap是專給托管代碼用的。即使我們的Native Code沒有用到Custom_Heap,也一定要定義,否則會出現意想不到問題(當然你也可以屏蔽TinyHal.cpp文件中的HAL_Init_Custom_Heap()代碼,這樣就不需要定義Custom_Heap了)。
在TinyCLR.proj文件中我們僅需支持mscorlib.pe、Microsoft.SPOT.Native.pe、Microsoft.SPOT.Hardware.pe這三個核心庫即可,所以我們也僅添加這三者的Feature。
?
???????<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\core.featureproj"?/>??????<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\Hardware.featureproj"?/>? ???<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\NativeEventDispatcher.featureproj"?/>? ???<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\InterruptHandler.featureproj"?/>??? ???<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\Diagnostics.featureproj"?/>???<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\Debugger.featureproj"?/>??? ???<Import?Condition=""?Project="$(SPOCLIENT)\Framework\Features\Serialization.featureproj"?/>? ??? ???<Import?Project="$(SPOCLIENT)\tools\targets\Microsoft.SPOT.System.Interop.Settings"?/>??? ????????????<ItemGroup>??????<RequiredProjects?Include="$(SPOCLIENT)\CLR\Core\dotNetMF.proj"?/>??????<PlatformIndependentLibs?Include="Core.$(LIB_EXT)"?/>???</ItemGroup>???<ItemGroup>??????<RequiredProjects?Include="$(SPOCLIENT)\CLR\StartupLib\dotNetMF.proj"?/>??????<PlatformIndependentLibs?Include="CLRStartup.$(LIB_EXT)"?/>???</ItemGroup>???<ItemGroup>??????<RequiredProjects?Include="$(SPOCLIENT)\CLR\Libraries\CorLib\dotNetMF.proj"?/>??????<PlatformIndependentLibs?Include="CorLib.$(LIB_EXT)"?/>???</ItemGroup>??????<ItemGroup>??????<RequiredProjects?Include="$(SPOCLIENT)\CLR\Libraries\SPOT\dotNetMF.proj"?/>??????<PlatformIndependentLibs?Include="SPOT.$(LIB_EXT)"?/>???</ItemGroup>??????<ItemGroup>??????<RequiredProjects?Include="$(SPOCLIENT)\CLR\core\Hardware\dotNetMF.proj"?/>??????<PlatformIndependentLibs?Include="Hardware.$(LIB_EXT)"?/>???</ItemGroup>???<ItemGroup>??????<RequiredProjects?Include="$(SPOCLIENT)\CLR\Libraries\SPOT_Hardware\dotNetMF.proj"?/>??????<PlatformIndependentLibs?Include="SPOT_Hardware.$(LIB_EXT)"?/>???</ItemGroup>? ?? 余下的項和NativeSample.proj文章中的類似,這里就不熬述了。
除此之外我們還得要配置一下Solutions\STM3210E目錄下的platform_selector.h文件,具體配置如下:
?
#define?DEBUG_TEXT_PORT?????????COM1 ??#define?STDIO???????????????????????COM2 ??#define?DEBUGGER_PORT???????????COM1 ??#define?MESSAGING_PORT??????????COM2 ? DEBUG_TEXT_PORT指的是我們調試信息輸出通道,如debug_printf的輸出信息就通過該通道,可以為串口、USB也可以是網口。
STDIO hal_printf函數就是通過該通道輸出的。
DEBUGGER_PORT比較重要,MFDeploy的Ping指令就是通過該通道,VS2008下載調試也是該通道。
MESSAGING_PORT 這個通道目前好像沒有被用到。
DEBUG_TEXT_PORT最好也配置為COM2,否則用MFDeploy工具區Ping設備的時候,會失敗。這是因為大量的debug信息會發到PC的串口接收區,而我們的MFDeploy沒有針對此處理,所以會失敗(對USB和網口來說,一般不會存在此類似問題),如果不修改MFDeploy的源碼我們可以先打開超級終端,然后再關閉,由超級終端為我們清空接收緩沖區,這樣再用MFDeploy Ping設備就沒有問題了。我們也可以修改代碼,在Debugger項目中我們在Native.cs文件中添加如下代碼:
[DllImport(KERNEL32,?SetLastError?=?true)] ??????????private?static?extern?bool?PurgeComm(IntPtr?handle,?uint?dwFlags); ??????????public?static?void?ClearReceiveBuf(IntPtr?handle) ??????????{ ??????????????const?int?PURGE_RXABORT?=?0x2; ??????????????const?int?PURGE_RXCLEAR?=?0x8; ??????????????PurgeComm(handle,?PURGE_RXABORT?|?PURGE_RXCLEAR); ??????????} ??????????public?static?void?ClearSendBuf(IntPtr?handle) ??????????{ ??????????????const?int?PURGE_TXABORT?=?0x1; ??????????????const?int?PURGE_TXCLEAR?=?0x4; ??????????????PurgeComm(handle,?PURGE_TXABORT?|?PURGE_TXCLEAR); ????} ?? 然后在Stream.cs文件的AsyncSerialStream中的public AsyncSerialStream( string port, uint baudrate ) : base( port, System.IO.FileShare.None )函數中添加如下代碼:
?????
Native.ClearReceiveBuf(m_handle.DangerousGetHandle()); ??ative.ClearSendBuf(m_handle.DangerousGetHandle()); ? 編譯為Microsoft.SPOT.Debugger.dll文件后,直接覆蓋Microsoft .NET Micro Framework\v4.0\Tools目錄下的同名文件即可。
好了,我們開始編譯Flash版本的TinyCLR,命令如下:
Msbuild .\Solutions\STM3210E\dotNetMF.proj /t:build /p:flavor=debug;memory=Flash
很不幸,我們編譯后的Hex文件并不是Inter Hex文件格式,用ISP工具是無法下載的。幸好MDK目錄下有一個BIN2HEX.EXE文件,通過它我們可以把ER_FLASH.bin文件轉換為Inter Hex文件格式的Hex文件。下面是我為轉換而寫的批處理文件。
if?exist?tinyclr.bin?(?del?tinyclr.bin?) ??if?exist?tinyclr.hex?(?del?tinyclr.hex?) ??copy?C:\MicroFramework_CortexM3\BuildOutput\THUMB2\MDK3.1\le\FLASH\debug\STM3210E\bin\tinyclr.bin\ER_FLASH?tinyclr.bin ??bin2hex?/O134217728?/4?/T?tinyclr.bin ??rem?if?exist?tinyclr.bin?(?del?tinyclr.bin?) ?? 設置好開發板上的跳線,用ISP工具下載我們的tinyclr.hex。如果一切OK,運行后的系統,LCD就會顯示如下畫面:
?
?
用MFDeploy Ping一下我們的開發板,如果出現Pinging... TinyCLR(如下圖),那么祝賀你,你成功了。
?
?
?
好了,我們編寫一個.Net Micro Frame工程示例,來測試一下我們的系統:
?
using?System; ??using?Microsoft.SPOT; ??using?Microsoft.SPOT.Hardware; ??using?System.Threading; ??? ??namespace?MFConsoleApplication1 ??{ ??????enum?GPIO_NAMES ??????{ ??????????PA0,?PA1,?PA2,?PA3,?PA4,?PA5,?PA6,?PA7,?PA8,?PA9,?PA10,?PA11,?PA12,?PA13,?PA14,?PA15, ??????????PB0,?PB1,?PB2,?PB3,?PB4,?PB5,?PB6,?PB7,?PB8,?PB9,?PB10,?PB11,?PB12,?PB13,?PB14,?PB15, ??????????PC0,?PC1,?PC2,?PC3,?PC4,?PC5,?PC6,?PC7,?PC8,?PC9,?PC10,?PC11,?PC12,?PC13,?PC14,?PC15, ??????????PD0,?PD1,?PD2,?PD3,?PD4,?PD5,?PD6,?PD7,?PD8,?PD9,?PD10,?PD11,?PD12,?PD13,?PD14,?PD15, ??????????PE0,?PE1,?PE2,?PE3,?PE4,?PE5,?PE6,?PE7,?PE8,?PE9,?PE10,?PE11,?PE12,?PE13,?PE14,?PE15, ??????????PF0,?PF1,?PF2,?PF3,?PF4,?PF5,?PF6,?PF7,?PF8,?PF9,?PF10,?PF11,?PF12,?PF13,?PF14,?PF15, ??????????PG0,?PG1,?PG2,?PG3,?PG4,?PG5,?PG6,?PG7,?PG8,?PG9,?PG10,?PG11,?PG12,?PG13,?PG14,?PG15 ??????}; ??? ??????public?class?Program ??????{ ??????????static?OutputPort?LED4?=?new?OutputPort((Cpu.Pin)GPIO_NAMES.PF8,?false); ??????????static?OutputPort?LED1?=?new?OutputPort((Cpu.Pin)GPIO_NAMES.PF7,?false); ??????????static?OutputPort?LED2?=?new?OutputPort((Cpu.Pin)GPIO_NAMES.PF6,?false); ??????????static?OutputPort?LED3?=?new?OutputPort((Cpu.Pin)GPIO_NAMES.PF9,?false); ??????????public?static?void?Main() ??????????{ ??????????????Port?PG8?=?new?InterruptPort((Cpu.Pin)GPIO_NAMES.PG8,?true,?Port.ResistorMode.PullUp,?Port.InterruptMode.InterruptEdgeBoth); ??????????????PG8.OnInterrupt?+=?new?NativeEventHandler(KeyCallback);?????????????????????? ??????????????Thread?thread1?=?new?Thread(new?ThreadStart(run1)); ??????????????thread1.Start(); ??????????????Thread?thread2?=?new?Thread(new?ThreadStart(run2)); ??????????????thread2.Start();???????? ??????????????while?(true) ??????????????{???????? ??????????????????LED1.Write(!LED1.Read());????????????????????? ??????????????????for?(int?e?=?0;?e?<?1000;?e++)?;???????? ??????????????}?????? ??????????} ??????????static?void?run1() ??????????{ ??????????????while?(true) ??????????????{ ??????????????????LED2.Write(!LED2.Read()); ??????????????????for?(int?e?=?0;e?<?1000;?e++)?; ??????????????} ??????????}??? ??????????static?void?run2() ??????????{ ??????????????while?(true) ??????????????{ ??????????????????LED3.Write(!LED3.Read());? ??????????????????for?(int?e?=?0;?e?<?1000;?e++)?; ??????????????} ??????????}????????? ??????????private?static?void?KeyCallback(uint?data1,?uint?data2,?DateTime?time) ??????????{ ??????????????if?(data2?!=?0) ??????????????{ ??????????????????//up ???????????????????LED4.Write(false); ??????????????} ??????????????else ??????????????{ ??????????????????//down ???????????????????LED4.Write(true); ??????????????} ??????????} ???????} ??} ??? ?? 下載運行后,你會發現三個LED在不停地閃爍,此外按User按鈕,另一個LED會因按下而亮,放開而滅。
好了,我們的.Net Micro Framework移植工作終于告一段落了(當然我們的代碼還不盡完善,也肯定存在一些Bug,不過相關問題我們也只有留待日后慢慢解決了),等再寫一篇移植總結后,我們便正是結束我們此系列的文章。以后我將準備開始寫【玩轉.Net MF】系列文章了。寫該系列的文章的目的,主要是想深入探討MF技術和對MF做一些您意想不到的拓展。
?
?
總結
以上是生活随笔為你收集整理的【.Net Micro Framework PortingKit – 14】TinyCLR编译与测试的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。