在WinCE下,应用程序直接读/写/擦除flash设备的方法
发布时间:2020-12-15 06:19:37 所属栏目:百科 来源:网络整理
导读:作者:ARM-WINCE 在网上的很多论坛中都看到有人提问:应用程序如何直接读写Flash的扇区,或者是类似的问题。总之,就是希望应用程序能够直接访问Flash设备,直接读写扇区的数据,或者作其他的操作。这几天没事,就尝试着做了一下,把我的方法介绍给大家。 先
作者:ARM-WINCE 在网上的很多论坛中都看到有人提问:应用程序如何直接读写Flash的扇区,或者是类似的问题。总之,就是希望应用程序能够直接访问Flash设备,直接读写扇区的数据,或者作其他的操作。这几天没事,就尝试着做了一下,把我的方法介绍给大家。 先做个简单的介绍。WinCE支持Flash设备,一般指Nandflash或者是NORFlash,采用的架构一般是FAL+FMD架构,我们实现FMD相关的接口函数,Flash的驱动就算完成了。当WinCE启动以后,我们能够看到Flash设备的磁盘。我们可以操作磁盘上面的文件,但是不能直接操作flash设备,对Flash设备的操作无非就是:读,写,擦除,读ID。 现在开始介绍实现的方法。我们如果想在应用程序中直接调用FMD中的FMD_ReadSector(..),FMD_WriteSector(..),FMD_EraseBlock(..)是不太现实的。这里再补充一下,这三个函数分别是Flash的读扇区,写扇区,擦除块的函数。好像有点罗嗦了。但是我们可以在应用程序中调用到FMD_OEMIoControl(..)函数,这个是可以做到的。所以我们需要改一下Flash设备的驱动程序,也就是改Flash设备驱动中的FMD_OEMIoControl(..)这个函数。我的改动如下: BOOL FMD_OEMIoControl(DWORD dwIoControlCode,PBYTE pInBuf,DWORD nInBufSize,PBYTE pOutBuf,DWORD nOutBufSize,PDWORD pBytesReturned) { ? PFMDInterface pInterface = (PFMDInterface)pOutBuf; ? RETAILMSG(1,(TEXT("FMD_OEMIoControl: control code is 0x%x/r/n"),dwIoControlCode)); ? switch(dwIoControlCode) ? { ? case IOCTL_FMD_GET_INTERFACE: ? if (!pOutBuf || nOutBufSize < sizeof(FMDInterface)) ? { ? DEBUGMSG(1,(TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s)./r/n"))); ? return(FALSE); ? } ? ? pInterface->cbSize = sizeof(FMDInterface); ? pInterface->pInit = FMD_Init; ? pInterface->pDeInit = FMD_Deinit; ? pInterface->pGetInfo = FMD_GetInfo; ? ? pInterface->pGetInfoEx = NULL; //FMD_GetInfoEx; ? pInterface->pGetBlockStatus = FMD_GetBlockStatus; ? ? pInterface->pSetBlockStatus = FMD_SetBlockStatus; ? pInterface->pReadSector = FMD_ReadSector; ? pInterface->pWriteSector = FMD_WriteSector; ? pInterface->pEraseBlock = FMD_EraseBlock; ? pInterface->pPowerUp = FMD_PowerUp; ? pInterface->pPowerDown = FMD_PowerDown; ? pInterface->pGetPhysSectorAddr = NULL; ? ? pInterface->pOEMIoControl = FMD_OEMIoControl; ? ? break; ? case 0xff123456: ? FMD_ReadSector(..); //调用读Sector函数 ? break; ? case 0xff654321: ? FMD_WriteSector(..); //调用写Sector函数 ? break; ? case 0xff123457: ? FMD_EraseBlock(..); //调用擦除Block函数 ? break; ? default: ? DEBUGMSG(1,(TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x)./r/n"),dwIoControlCode)); ? return(FALSE); ? } ? return(TRUE); }? 在FMD_OEMIoControl(..)函数里面增加了3个case,这3个case里面调用了读/写/擦除函数。至于Case的值,我是随便定义的。这样Flash设备的驱动部分就改完了。 在改完Flash驱动以后,我下面会提供两种方法,每一种方法都和Flash设备的注册表配置有关: 1. 以Nandflash为例,当然对于NORFlash来说大同小异,注册表配置如下: [HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFlash] "Dll"="ep94xxnandflash.dll" "Prefix"="DSK" "Order"=dword:4 ;"Ioctl"=dword:4 "Profile"="NSFlash" "IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}" ; Override names in default profile [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash] ?"Name"="Ep94xx NAND Flash" ?"Folder"="NANDFlash" ?"PartitionDriver"="MSPart.dll" ?"AutoMount"=dword:1 ?"AutoPart"=dword:1 ?"AutoFormat"=dword:1 [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash/FATFS] "EnableCache"=dword:1 "CacheSize"=dword:1000 "MountBootable"=dword:1 "Flags"=dword:00000024 "CheckForFormat"=dword:1 然后编写应用程序,主要就是通过CreateFile来打开DSK1:设备,然后通过DeviceIoControl(..)函数来调用FMD_OEMIoControl(..)函数,来达到直接读/写/擦除Flash设备的目的。应用程序代码如下: HANDLE hFirm; ?hFirm = CreateFile(TEXT("DSK1:"),GENERIC_READ | GENERIC_WRITE,NULL,OPEN_EXISTING,NULL); ?if(hFirm == INVALID_HANDLE_VALUE) ?{ ? printf("Open Flash Device Failed"); ? return 0; ?} ?iRet = DeviceIoControl(hFirm,0xff123456,para1,para2,para3,para4,para5,para6); //Read Flash Sector ?iRet = DeviceIoControl(hFirm,0xff654321,para6); //Write Flash Sector ?iRet = DeviceIoControl(hFirm,0xff123457,para6); //Erase Flash Block ?printf("DeviceIoControl OK/r/n"); ?while(1) ? ; 通过上面的应用程序,就能够调用到Flash设备驱动中的FMD_OEMIoControl(..)函数,这样根据不同的case就可以调用读/写/擦除函数了。 ? 2. 以Nandflash为例,当然对于NORFlash来说大同小异,注册表配置如下: [HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFlash] "Dll"="ep94xxnandflash.dll" "Prefix"="DSK" "Order"=dword:4 ;"Ioctl"=dword:4 "Profile"="NSFlash" "IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}" ; Override names in default profile [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash] ?"Name"="Ep94xx NAND Flash" ?"Folder"="NANDFlash" ?"PartitionDriver"="MSPart.dll" ?"AutoMount"=dword:1 ?"AutoPart"=dword:1 ?"AutoFormat"=dword:1 [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash/FATFS] "EnableCache"=dword:1 "CacheSize"=dword:1000 "MountBootable"=dword:1 "Flags"=dword:00000024 "CheckForFormat"=dword:1 [HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/NSFlash] "DriverPath"="Drivers//BuiltIn//NANDFlash" "LoadFlags"=dword:0 "BootPhase"=dword:1 然后编写应用程序,主要就是通过OpenStore来打开NSFlash,然后通过DeviceIoControl(..)函数来调用FMD_OEMIoControl(..)函数,来达到直接读/写/擦除Flash设备的目的。应用程序代码如下: ?HANDLE hFirm; ?hFirm = OpenStore(L"NSFlash"); ?if(hFirm == INVALID_HANDLE_VALUE) ?{ ? printf("Open Flash Device Failed"); ? return 0; ?} ?iRet = DeviceIoControl(hFirm,para6); ?iRet = DeviceIoControl(hFirm,para6); ?printf("DeviceIoControl OK/r/n"); ?while(1) ? ; 通过这种方法,也可以在应用程序中调用到FMD_OEMIoControl(..)函数,从而达到直接访问Flash设备的目的。 总结一下,上面的两种方法大致原理其实是一样的,都是通过DeviceIoControl函数来调用FMD_OEMIoControl函数,然后达到直接访问Flash驱动的目的,这样就可以在应用程序中直接读/写/擦除Flash设备了。 最后需要注意的是:你的Flash驱动里面需要对读/写/擦除等直接操作Flash硬件的函数进行保护,因为Flash设备应该是由WinCE的文件系统来管理的,而现在你的应用程序也可以直接访问它了,所以保险起见,添加互斥量保护避免访问冲突。 上面的所有实现,都是在WinCE6.0上面做得,相信在WinCE5.0上面应该差不多。 28楼 suzhbruce 2010-09-13 17:30发表 [回复]? 请问版主nanjianhui: 感谢你的分享, 现要写入数据到NandFlash, 那你上面提到的那个 iRet = DeviceIoControl(hFirm,para6)调用中, para1的写入数据具体格式是怎样的啊..? 难道是SG_REQ格式? 还是其它 ? 可否举例说明一下? 感谢!! 27楼 nanjianhui 2009-09-15 17:22发表 [回复]? 我认为也是可以的,不过我没有试过。你的问题好像是因为你的驱动中没有识别出正确的IOcontrol操作码。 26楼 ashazhuang 2009-09-09 11:19发表 [回复]? WINCE5.0 无法用楼主的方法吧。我在fmd_iocontrol()添加自己的case. 出现错误提示“DSK_iocontrol unknown code (.....)” 25楼 nanjianhui 2008-11-13 09:50发表 [回复]? 这里有Nandflash的参考代码,你可以看一下:? /WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BLOCK/MSFLASHFMD/SDNPCI 24楼 redeg 2008-11-09 21:29发表 [回复]? 楼主,在PB的MSFLASHFMD目录下哪个是NAND FLASH的驱动?FASL目录好像是NOR的驱动对吗? 23楼 lskymate 2008-11-07 18:18发表 [回复]? 版主.謝謝您? 小弟目前改用deviceIoControl? 來取代readFile,writeFile已可成功? 對flash存取.? 感激 22楼 lskymate 2008-11-06 17:43发表 [回复]? (接續上篇)? flashReadBuffer,? 512,? &flashReadCounter,? NULL);? if (readFlashOk == FALSE)? {RETAILMSG(1,(L" Read Mounted Volume Failure!! /n" )); exit(-1);}? // ReadFile - END? 真的不曉得為什麼會出問題..? 可以在為小弟指點一下嗎?? 非常感激? 而關於 註冊表的資訊如下? [HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SKYFMD]? @=""? "Prefix"="DSK"? "Dll"="SKYFMD.dll"? "Index"=dword:2? "IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"? "Profile"="SKYFMD"? [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/SKYFMD]? "DefaultFileSystem"="FATFS"? "PartitionDriver"="mspart.dll"? "Name"="SKYFALFMD"? "AutoMount"=dword:1? "AutoPart"=dword:1? "AutoFormat"=dword:1? "Ioctl"=dword:4? 感激 21楼 lskymate 2008-11-06 17:43发表 [回复]? (接續上篇)? flashReadBuffer,(L" Read Mounted Volume Failure!! /n" )); exit(-1);}? // ReadFile - END? 真的不曉得為什麼會出問題..? 可以在為小弟指點一下嗎?? 非常感激? 而關於 註冊表的資訊如下? [HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SKYFMD]? @=""? "Prefix"="DSK"? "Dll"="SKYFMD.dll"? "Index"=dword:2? "IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"? "Profile"="SKYFMD"? [HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/SKYFMD]? "DefaultFileSystem"="FATFS"? "PartitionDriver"="mspart.dll"? "Name"="SKYFALFMD"? "AutoMount"=dword:1? "AutoPart"=dword:1? "AutoFormat"=dword:1? "Ioctl"=dword:4? 感激 20楼 lskymate 2008-11-06 17:39发表 [回复]? 版主您好? 目前小弟希望可以透過File System來對Flash存取.? 也就是說寫一支AP.利用Logical Sector Address去? 對Flash做讀寫的動作.? 目前是計畫用 writeFile及readFile來寫入及讀取.? 但會發生exception.? 目前 CreateFile 的程式如下? //----------------- CreateFile -----------------? #define FLASHPATH TEXT("//Mounted Volume//Vol:")? hFlash = CreateFile (FLASHPATH,? GENERIC_READ | GENERIC_WRITE,? FILE_SHARE_READ|FILE_SHARE_WRITE,? NULL,? OPEN_EXISTING,? FILE_ATTRIBUTE_NORMAL,? NULL);? if (hFlash == INVALID_HANDLE_VALUE)? { RETAILMSG(1,(L"Open Mounted Volume Failure!!/n" )); exit(-1); }? // CreateFile - END? 讀取資料 ReadFile 的程式如下? //----------------- ReadFile -----------------? flashReadBuffer = (char *) malloc (sizeof(char)*512); //接收資料的buffer? memset (flashReadBuffer,sizeof(char)*512);? flashAddress = SetFilePointer (hFlash,? 0,? FILE_BEGIN);? readFlashOk = ReadFile (hFlash,//執行到這裡時將會發生錯誤(First - chance exception) 19楼 lskymate 2008-09-16 20:36发表 [回复]? 謝謝版主.? 我在Storage Manager Control Panel Applet有看到了.? 非常感激 18楼 nanjianhui 2008-09-16 12:38发表 [回复]? 你可以在控制面板里面,看看有没有一个Storage的Manager,在里面应该可以看到,并且作mount。 17楼 lskymate 2008-09-12 19:28发表 [回复]? 版主您好.? 我發現,C:/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BLOCK/MSFLASHFMD/RAM 下有一個用 virtualalloc 的作法來產生2M的ram Flash.? 但我不知如何使用.所以把他拉出來? 放到DEVICEEMULATOR(BSP)下將他當成driver? 並BUILD成功.然後attach Emulator時.也可以順利? 看到自己在FMD.c加的資訊.? 但在EMULATOR上.並沒有看到關於這個 flash device .的相關資訊.請問我要如何像 linux 那樣 mount這個? flash device 呢?? 非常感激 16楼 eagle1597 2008-09-10 16:33发表 [回复]? 1: "因为在WinCE6.0中限制了IOControl的访问"? 这个我不了解,我的确只在5.0中做过. 谢谢你的指出.? 2: 如果你把srctor留出不给ce管理,当然也就没有必要写额外信息了. 15楼 nanjianhui 2008-09-10 12:53发表 [回复]? 你的方法可行,但是有个问题,在WinCE5.0下可以,但是在WinCE6.0下就不行了。因为在WinCE6.0中限制了IOControl的访问,只有有限的几个case是可以被应用层访问的,所以你的方法就不适用了,关于这个问题,我以前写过一篇blog叫“WinCE BSP中d的OEMIoControl介绍”,你可以看一下。你要是非要通过IOControl来访问,你就需要改public目录下的代码,这样好像不太好啊,你怎么release BSP给你的客户呢?? 关于你说的要往Sector的额外信息写数据的问题,我认为没有什么必要,这块区域应该不属于WinCE可见的磁盘区域,所以你在FMD_GetInfo中,设置总共有多少个block的时候,把这块区域预留出来就可以了。 14楼 eagle1597 2008-09-10 10:40发表 [回复]? 我来发表看法吧.? 楼主的做法是可行的,我也提供另一种做法,那就是在oal层增加ioctl.? 大家知道,在ioctl_tab.h 中有KernelIOControl的一些OEM增加的额外IOCTL,我们完全可以在这里增加一个例如IOCTL_HAL_READFLASE等的Oal函数,在oal层中,诸如调用FMD_ReadSecotr等是很方便的. 增加后,应用层就可以通过KernelIOControl来这行flash的读写了.? 还应该指出的是,在对Flash的某个sector进行物理写后,还应该对该sector的额外信息块写一定的数据以指示该flash存在数据,以至于不会被fal层把这个sector当作空闲而重写该sector.? Sector后的sector_info结构如下:? typedef struct _SectorMappingInfo? {? SECTOR_ADDR logicalSectorAddr;? BYTE bOEMReserved; // For use by OEM? BYTE bBadBlock; // Indicates if block is BAD? WORD fDataStatus;? } SectorMappingInfo,*PSectorMappingInfo;? 而当我们对这个sector进行写后(不通过fal层),我们应该把上面结构体中的fDataStatus置一定的值,以下值供参考:? #define FREE_SECTOR 0xFFFF // Indicates sector is free (erased)? #define DIRTY_SECTOR 0x0001 // Indicates sector is ready to erase? #define SECTOR_WRITE_IN_PROGRESS 0x0002 // Indicates sector write is in progress? #define SECTOR_WRITE_COMPLETED 0x0004 // Indicates sector write completed (data is valid)? #define COMPACTION_IN_PROGRESS 0x0008 // Indicates previous block is being compacted? #define COMPACTION_COMPLETED 0x0010 // Indicates previous block compaction completed? #define SECURE_WIPE_IN_ 13楼 nanjianhui 2008-09-04 09:34发表 [回复]? 在仿真的环境下,你最好在你的BSP中重写一个NandFlash的驱动,但是在实现驱动的FMD层中的函数的时候,你可以不对硬件操作,只对一块内存进行操作。也就是相当于一块RamDisk,但是使用NandFlash驱动来实现的。这样应该是可行的。 12楼 lskymate 2008-09-03 05:05发表 [回复]? 看了版主這篇文章.真是收穫良多.? 真的十分抱歉.在這裡很唐突的請教版主ㄧ些問題? 如果版主方便的話.不知可否為小弟解惑..? 非常感激.? 小弟目前使用Wince 6.0? 想在Emulator上.模擬Flash裝置(沒有板子..)? 目前使用的BSP是DEVICEEMULATOR? 而另外勾選的Catalog Item有? Binary Rom Image file System,? FAT File System? Storage Manager Control Panel Applet? Registry Storage-RAM-based Registry? RAM and ROM File System? Storage Device(全部選項).? PCI NAND Flash Driver.? 在Build時成功.但attach target時會停住..? 出現訊息如下.? 4294784275 PID:400002 TID:10e0002 DEVICE!RegReadActivationValues RegQueryValueEx(Notify/BusPrefix) returned 2? 4294784289 PID:400002 TID:1070002 Unknown: DEBUGCHK failed in file C:/ymzki/private/winceos/DRIVERS/msflash/src/./falmain.cpp at line 1409? 想請問版主.Emulator下如何模擬像flash 這類的block driver.呢?? 非常非常感激.? 詩凱上 11楼 nanjianhui 2008-08-28 10:09发表 [回复]? 你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。 10楼 nanjianhui 2008-08-28 10:03发表 [回复]? 你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。 9楼 nanjianhui 2008-08-28 10:02发表 [回复]? 你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。 8楼 redeg 2008-08-27 10:35发表 [回复]? 楼主,在调用FMD_ReadSector时如何逐一读取每块数据?该如何传递参数,我是新手,还希望楼主能解答.谢谢. 7楼 nanjianhui 2008-08-19 09:37发表 [回复]? 楼上的,没错你是可以得到。问题是你在什么地方得到呢?是在应用程序中得到么,那你应该是得到了驱动函数的指针,你能在应用程序中直接调用么?? 我没有试过,但是我认为不行。如果你实现了,请你写出具体步骤,谢谢。 6楼 slj0998 2008-08-07 18:09发表 [回复]? IOCTL_FMD_GET_INTERFACE:? 用这个不就可以直接得到? PFMDInterface pInterface? 读写直接用? pInterface->pReadSector = FMD_ReadSector;pInterface->pWriteSector = FMD_WriteSector;? 难道不行吗? 5楼 nanjianhui 2008-08-06 12:32发表 [回复]? NandFlash驱动在WinCE6.0下是运行在内核模式的,所以应用程序想要直接调用内核下的驱动的API因该是不可能的。如果楼上有什么好的方法,并且已经实现了,欢迎指点。 4楼 freasy 2008-08-05 21:17发表 [回复]? 只要暴露的足够多,应用程序什么事都可以做了 3楼 freasy 2008-08-05 21:15发表 [回复]? 只要暴露的足够多,应用程序什么事都可以做了 2楼 nanjianhui 2008-07-30 17:54发表 [回复]? 呵呵,你的方法在WinCE6.0上可行么?? 1楼 guopeixin 2008-07-27 15:49发表 [回复]? 1. 首先要说,你这样的方法很是巧妙,但是要修改驱动的代码,这样可能会引起一些未知的问题.? 2. 你可以直接将fmd层的lib连接到ap中,然后直接在ap中对lib暴露出的接口对flash进行操作就可以了.
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- c# – Roslyn – 从内存中组装创建MetadataReference
- dart – 如何在flutter中实现Alphabet滚动
- ruby-on-rails – ruby??gems无法在Synology DS209上运行
- c# – Foreach没有经过所有项目?
- 【Java Web】——配置文件的格式之xml和properties的区分
- ruby-on-rails – Rspec / Rails:未初始化的常量ActiveSup
- 正则表达式 – 有用的正则表达式教程
- Flash ActionScript (21)一个简单实用的loading代码
- c# – 在应用程序/服务关闭/停止之前等待定时器已过事件完成
- SQLite中的内连接简化技巧