目前在PC遠端通路裝置Flash,也就是部署TinyCLR和下載下傳應用程式。在以前寫的《NandFlash驅動開發》文章,我們知道Flash被分為六個區,典型的結構如下(以Sam9261_ek開發闆為例):
const BlockRange g_K9F2G_8_BlockStatus[] =
{
{ BlockRange::BLOCKTYPE_BOOTSTRAP , 0, 1 },
{ BlockRange::BLOCKTYPE_CONFIG , 2, 2 },
{ BlockRange::BLOCKTYPE_CODE , 3, 24 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 25, 29 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 30, 34 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 35, 39 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 40, 48 },
{ BlockRange::BLOCKTYPE_STORAGE_A , 49, 49 },
{ BlockRange::BLOCKTYPE_STORAGE_B , 50, 50 },
{BlockRange::BLOCKTYPE_FILESYSTEM, 51, FLASH_BLOCK_COUNT - 1 }
};
我們能否直接讀寫該Flash上的所有區呢?
實作這個功能的好處是易見的,我們再也沒有必要為了下載下傳一個應用程式而啟動相對龐大的VS2008,再也不受必須打開MF工程才能下載下傳的限制。在我們開發Ti DM355開發闆就遇到類似問題,我們給異地開發闆提供者示範相關程式功能時,必須要求對方安裝VS2008,還必須發送我們的項目源碼,否則就無法在另外的開發闆上進行示範。
仔細研究了一下MFDeploy程式(這是典型的C#程式,在Vista和Windows7上可直接運作,在WinXP及以前的系統上需要安裝.Net Framework運作時),發現可以為其開發一個插件來實作我們所要求的功能。
MFDeploy程式可以通過三種方式來通路.Net MF裝置,序列槽、網口和USB,并且可以把TinyCLR部署到裝置上去(需要開發闆運作TinyBooter),也可以清空應用程式區,是以我們隻要把這部分功能給擴充一下就可以了。
插件類必須繼承于MFPlugInMenuItem類,相關代碼如下:
public class PlugInHandle : MFPlugInMenuItem
{
public override string Name { get { return "Read/Write Flash"; } }
public override void OnAction(IMFDeployForm form, MFDevice device)
{
if (form == null || device == null) return;
(new frmRWFlash(form, device)).ShowDialog();
}
}
其中由宿主傳遞過來的form和device非常重要,form就是針對MFDeploy主窗體,主要提供DumpToOutput函數,把消息顯示到資訊區,而device則提供和裝置通信的相關函數,如Ping、Deploy、Erase、Execute等。
插件實作的第一步,要讀寫Flash區,首先要擷取Flash的記憶體映像表,通過如下的代碼就可以擷取:
_DBG.WireProtocol.Commands.Monitor_FlashSectorMap.Reply reply = engine.GetFlashSectorMap();
if (reply != null)
{
for (int i = 0; i < reply.m_map.Length; i++)
{
_DBG.WireProtocol.Commands.Monitor_FlashSectorMap.FlashSectorData fsd = reply.m_map[i];
string usage = "";
switch (fsd.m_flags & _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_MASK)
{
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_APPLICATION:
usage = "Application";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_BOOTSTRAP:
usage = "Bootstrap";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_CODE:
usage = "Code";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_CONFIG:
usage = "Configuration";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_DEPLOYMENT:
usage = "Deployment";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_JITTER:
usage = "Jitter";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_FS:
usage = "File System";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_RESERVED:
usage = "Reserved";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_STORAGE_A:
usage = "Storage";
break;
case _DBG.WireProtocol.Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_STORAGE_B:
usage = "Storage";
break;
case 0xA0:
usage = "Custom";
break;
}
FlashMap.Add(FlashMaps, usage, fsd.m_address, fsd.m_size);
}
}
第二步就是讀寫Flash的扇區資料,可以通過如下代碼實作:
bool ret = engine.ReadMemory(addr, buflen, out bytData);
bool ret = engine.WriteMemory(addr, FileIndex.GetBytes(), 0, (int)FileIndex.HeadSize);
但是僅僅實作以上兩步還不行,因為TinyCLR代碼會限制一些Flash的讀寫範圍,是以我們還得需要修改TinyCLR的代碼。
在/CLR/Debugger目錄下的Debugger.cpp檔案有一個函數CheckPermission,我們修改一下它的代碼,讓它直接傳回true就可以了,這樣我們就可以對Flash任何區都可以讀寫了。
bool CLR_DBG_Debugger::CheckPermission( ByteAddress address, int mode )
{
NATIVE_PROFILE_CLR_DEBUGGER();
bool hasPermission = false;
UINT32 regionIndex, rangeIndex;
m_deploymentStorageDevice->FindRegionFromAddress( address, regionIndex, rangeIndex );
const BlockRange& range = m_deploymentStorageDevice->GetDeviceInfo()->Regions[ regionIndex ].BlockRanges[ rangeIndex ];
return true;
/*
switch(mode)
{
case AccessMemory_Check:
hasPermission = true;
break;
case AccessMemory_Read:
switch(range.RangeType)
{
case BlockRange::BLOCKTYPE_CONFIG: // fall through
case BlockRange::BLOCKTYPE_DIRTYBIT: // fall through
case BlockRange::BLOCKTYPE_DEPLOYMENT: // fall through
case BlockRange::BLOCKTYPE_FILESYSTEM: // fall through
case BlockRange::BLOCKTYPE_STORAGE_A: // fall through
case BlockRange::BLOCKTYPE_STORAGE_B:
hasPermission = true;
break;
}
break;
case AccessMemory_Write:
if(range.IsDeployment())
{
hasPermission = true;
}
break;
case AccessMemory_Erase:
switch(range.RangeType)
{
case BlockRange::BLOCKTYPE_DEPLOYMENT: // fall through
case BlockRange::BLOCKTYPE_FILESYSTEM: // fall through
case BlockRange::BLOCKTYPE_STORAGE_A: // fall through
case BlockRange::BLOCKTYPE_STORAGE_B:
hasPermission = true;
break;
}
break;
default:
hasPermission = false;
break;
}
return hasPermission;*/
}
編譯好插件,把它拷貝到MFDeploy.exe檔案所在的子目錄PlugIn,啟動MFDeploy.exe程式,在Plug-in菜單下就會有我們的插件菜單。
這樣就可以對Flash上的任何區都可以進行讀寫了。并且針對Deployment區,不僅可以下載下傳.Net Micro Framework應用程式,也可以單擊“Run”按鈕,運作目前下載下傳的程式(這樣就不用重新開機TinyCLR了)。
針對File System區,我考慮實作一個類似VS2008遠端工具“遠端檔案檢視器”,這樣PC就會更友善和.Net MF裝置進行互動了。如果大家看過我以前寫的《LCD驅動開發》,螢幕上顯示的位圖,就是通過該插件下載下傳的。