这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » [原创]Tornado之TrueFFS编程者指南(六) (狗尾续貂seasobl

共9条 1/1 1 跳转至

[原创]Tornado之TrueFFS编程者指南(六) (狗尾续貂seasoblue)

菜鸟
2004-05-12 06:14:34     打赏
[原创]Tornado之TrueFFS编程者指南(六)-By George (续)
按:看了seasoblue兄如此辛苦地翻译了TrueFFS编程者指南1-5,心想不能老是伸手要吃要穿,自己应当做点什么,就心 血来潮也翻译起来。seasoblue兄谦虚说自己对TrueFFS造诣不深,其实大家心里明白他是大牛,因为字里行间已现山露水 。我需要说明的是我对TrueFFS确实是啥屁不懂,仅仅是想学学,顺便照着字面就翻译了,字里行间肯定是破绽百出。之 所以还厚着脸贴出来,是希望大方之家(如seasoblue、xiaohua等)能多多斧正,俺也好早点入门。
stone_pine@hotmail.com
西元2004年5月11日晚 第三章:如何写socket驱动与MTD
1,简介
这一章将为你提供FLASH存储器、tffs与VXWORKS的接口。它将阐述所有对socket驱动和MTD至关重要的函数和结构体。 其中我们最关心的两个结构体是FLFlash和FLSocket。
tffs内部分配了一个包含5个FLFlash结构体的阵列(array),每个都对应一个可能的flash设备。tffs使用这些FLFlash 结构体来存储数据和函数指针(这些函数是用于管理FLASH设备的)。比如,tffs使用MTD函数来处理对FLASH煤质基本的 读写操作,而FLFlash结构体就包含这些MTD函数指针。当运行一个MTD识别程序时,系统就安装了这些函数指针。
FLFlash结构体还包含一个指向FLSocket结构体的指针。tffs使用这些FLSocket结构体来存储数据和函数指针(所不同的 是,这些函数是用于处理与FLASH设备的硬件接口的,也就是socket接口)。从我们的sysTffsInit()到xxxRegister()程 序调用时,则安装这些函数。
用TFFS注册我们的socket驱动:
在VXWORKS中包含TFFS将会使usrRoot()调用tffsDrv()。而这将发起一个函数调用链:如下图
Figure3-1
/*******************************************/ /*******************************************/
这些函数调用的目的之一就是用TFFS注册我们的socket驱动函数。
多数情况下,注册工作都发生在xxxRegister()中(这个函数的定义在sysTffs.c中)。该函数能更新FLSocket结构体。而 此时,TFFS已经对应socket驱动中的服务程序给FLSocket结构体赋予了一个设备号(也即卷标)。TFFS调用FLSocket结构 体中引用的函数来处理与Flash设备的硬件接口。 给FLASH技术确定一个MTD;
要创建一个TFFS块设备,我们必须调用tffsDevCreate()。这一调用也将发起一个函数调用链。如图3-2 /************************************/
/*************************************/ 这些函数调用的目的之一是确认合适的MTD。该确认过程在flIdentifyFlash()中。flIdentifyFlash()通过逐个执行xxxId entify()表中的程序来确定合适的MTD。(相同的MTD是可以在多个不同的FLASH卷标中同时有效的)。
一旦找到合适的MTD,确认程序就会更新FLFlash结构体中的数据以及指向用于读、写、擦除、映射等操作的MTD程序指针 。此外,确认过程还将完成在当前FLFlash结构体中涉及的FLSocket结构体的初始化。 2,关于FLFlash结构体和FLSocket结构体 tffs最多可以处理5个TFFS块设备。它给每个FLFlash结构体和FLSocket结构体都分配一个可能存在的FLASH设备。当使 用TFFS注册我们的socket驱动时,系统也同时对这些结构体进行初始化。
多数情况下,注册也将更新FLFlash中socket成员涉及的FLSocket结构体。而FLFlash结构体的初始化使通过运行一个MTD 确认程序来完成的。因为,确认程序依赖于FLSocket结构体中所涉及的函数,所以我们必须在运行MTD确认程序之前安装 号socket驱动。 2.1 FLFlash之庐山真面目 几乎所有的FLFlash结构体成员都是通过MTD确认程序设定的,这样它就可以通过检测flash硬件获取它所需要的绝大多 数数据。唯一例外的是socket成员,它是通过TFFS内部函数设定的。
FLFlash结构体在h/tffs/flflash.h中有定义: typedef struct tFlash FLFlash; /* forward definition */ struct tFlash {
FlashType type; /* flash device type (JEDEC id) */
long int erasableBlockSize; /* smallest erasable area */
long int chipSize; /* chip size */
int noOfChips; /* no. of chips in array */
int interleaving; /* chip interleaving */
unsigned flags; /* special options */
void * mtdVars; /* MTD private area for socket */
FLSocket * socket; /* FLSocket for this drive */
/* MTD-supplied flash map function */
void FAR0 * (*map)(FLFlash *, CardAddress, int);
/* MTD-supplied flash read function */
FLStatus (*read)(FLFlash *, CardAddress, void FAR1 *, int, int);
/* MTD-supplied flash write function */
FLStatus (*write)(FLFlash *,CardAddress,const void FAR1 *,int,int)
/* MTD-supplied flash erase function */
FLStatus (*erase)(FLFlash *, int, int);
/* callback to execute after power up */
void (*setPowerOnCallback)(FLFlash *);
};
说明:
(1) type: JEDEC ID用于标识FLASH存储器的硬件。该成员的值在MTD确认程序中设定;
(2) erasableBlockSize:大小,单位为字节,为flash存储器一个可擦除块的大小。该值通过交叉计算而得,因此当 在MTD中设定该值时,通常用如下格式:
vol.erasableBlockSize=aValue*vol.interleaving;
其中,aValue就是未与其它flash芯片交叉存取的可擦除块的大小。 (3) chipsize: 单片flash得存储容量,单位字节。通过MTD中的外部函数flFitInSocketWindow()设定。
(4)noOfChips: 构成FLASH存储阵列的flash存储器的片数;
(5)interleaving: flash存储阵列的交叉存取参数,必须为2的整数幂(如1,2,4等)。用于定义在一个存储 芯片上,两个字节连续媒体的地址差异。
(6)flags: bits0-7 保留用于TFFS;bits8-15 保留用于MTD;
(7)mtdVars: 该区域如果被MTD占用,mtd的确认程序则将它初始化为一个指针指向一个特定的存储区。比 如,16位AMD设备的MTD使用该成员存储一个指针,该指向存有AMD特有的FLASH参数。
(8)socket: 是个指向FLSocket结构体的指针。而这个FLSocket结构体含有指向socket层函数的指针和数据。当我 们注册socket驱动时,该FLSocket结构体中涉及的函数将被安装。而且,因为TFFS要使用这些socket驱动函数来寻址FLAS H存储器,所以我们必须在运行MTD确认程序之前注册我们的socket驱动。
(9)map: 一个指向flash存储器映射(MAP)函数的指针,该函数将flash映射到存储器的一个区域。TFFS初始化时默 认将这个指针成员指向一个适合所有NOR flash存储器类型的映射函数。NAND或其他类型FLASH必须用另外一个指向使用拷 贝映射机制的程序指针来替换默认的。
(10)read: 一个指向flash读函数的指针。在MTD确认程序之前,系统就将该成员指针初始化指向一个适合所有NOR flash存储器类型的读函数。其实,读flash的过程是通过从一个映射窗口拷贝来实现的。如果默认的read指针不适合我们 的flash设备,MTD确认程序需要更新这个指针成员以便让她指向正确的函数;如果正好适合,那当然不需要改。
(11)write: 一个指向flash写函数的指针。该成员默认指向的程序在发现FLASH的写函数不合适时将返回一个写保护 错误信息。同read指针类似,write指针一样需要MTD确认程序将它指向一个合适的函数。
(12)erase: 一个指向flash擦除函数的指针。在发现擦除函数与flash设备不匹配时,该指针默认指向的函数也将返 回一个写操作错误信息。erase指针一样需要MTD确认程序将它指向一个合适的函数。
(13) setPowerOnCallback: TFFS在flash设备上电后应当执行一个函数以便挂接该设备,setPowerOnCallback成员就 是指向这个函数的指针。(需要注意,不要混淆了setPowerOnCallback成员和FLSocket结构体中的PowerOnCallback成员 )。对许多flash存储设备而言,这个函数并不必须。 2.2 FLSocket之庐山真面目 作为socket驱动的开发人员,我们最需要关心的就是FLSocket结构体的初始化。这个结构体为TFFS提供了指向 处理flash硬件接口的函数指针。一般情况下,怎样实现这些flash接口函数相对软件来说更需要硬件细节。
相应地,FLSocket结构体的成员描述指出了风河提供的BSP,这样我们就可以用来作例子。但是,在使用这些BSP时 ,我们需要对特定的硬件特别谙熟。
FLSocket结构体在h/tffs/flsocket.h中有定义:
typedef struct tSocket FLSocket; /* forward definition */
struct tSocket {
unsigned volNo; /* volume no. of socket */
unsigned serialNo; /* serial no. of socket on controller */
FLBoolean cardChanged; /* need media change notification */
int VccUsers; /* no. of current VCC users */
int VppUsers; /* No. of current VPP users */
PowerState VccState; /* actual VCC state */
PowerState VppState; /* actual VPP state */
FLBoolean remapped; /* set to TRUE if the socket window is moved */
void (*powerOnCallback)(void *flash); /* notification routine for Vcc on */
void * flash; /* flash object for callback */
struct { /* window state */
unsigned int baseAddress; /* physical base as a 4K page */
unsigned int currentPage; /* our current window page mapping */
void FAR0 * base; /* pointer to window base */
long int size; /* window size (must by power of 2) */
unsigned speed; /* in nsec. */
unsigned busWidth; /* 8 or 16 bits */
} window;
FLBoolean (*cardDetected) (FLSocket vol);
void (*VccOn) (FLSocket vol);
void (*VccOff) (FLSocket vol);
#ifdef SOCKET_12_VOLTS
FLStatus (*VppOn)(FLSocket vol);
void (*VppOff)(FLSocket vol);
#endif /* SOCKET_12_VOLTS */
FLStatus (*initSocket) (FLSocket vol);
void (*setWindow) (FLSocket vol);
void (*setMappingContext) (FLSocket vol, unsigned page);
FLBoolean (*getAndClearCardChangeIndicator) (FLSocket vol);
FLBoolean (*writeProtected) (FLSocket vol);
#ifdef EXIT
void (*freeSocket) (FLSocket vol);
#endif
}; (1)volNo: 卷标号,除非通过MTD确认程序,否则不要改其值;
(2)serialNo: 可自由使用的结构体成员,典型值设为0;
(3)cardChanged: 该成员的作用是追踪监测是否有flash卡改变,监测周期为100ms,监测函数为cardDetected成员中 的函数。如果cardDetected返回值FALSE,则cardChanged被设为TRUE。如果FLASH媒体不可移动,则该成员应设为FALSE。 如果为TRUE,在TFFS寻址FLASH时,它将重新挂接FLASH设备。
(4)VccUsers: 内部使用,无需改变。
(5)VppUsers: 内部使用,无需改变。
(6)VccState: 内部使用,无需改变。
(7)VppState: 内部使用,无需改变。
(8) remapped: 内部使用。TFFS使用该成员追踪检测window是否被重映射过。如果我们写自己的MTD映射函数,应在返 回值之前设定该成员。
(9)powerOnCallback:通过我们的xxxRegister()函数设定。tffs在调用VccOn成员中的xxxRegister()函数后调用此处 的函数。如果没有必要使用该成员,可将其设为空指针。
(10)flash: 内部使用,无需改变其值。该成员用于支持可移动的flash媒体,且通过TFFS动态设置。
(11)window.baseAddress: 通过我们的xxxRegister()函数设定。在这个上下文中,一个窗口就是主机系统MEM的一部 分,通过这个窗口,一部分媒体空间可直接寻址并可进行地址设定。window.baseAddress成员按4000页保存着这个主机系 统的内存地址(也即窗口基地址除以4K)。之所以这样做是为了防止重建时基地址的页结盟(此处不懂)。
(12)window.currentPage:内部使用。用于存储当前映射的window页。
(13)window.base: 通过在setWindow成员中提供的函数设定。TFFS使用window.base来存放FLASH存储器上存储窗口的 基地址。
(14)window.size:通过在setWindow成员中提供的函数设定。 TFFS使用window.size来存放FLASH存储器上存储窗口的 大小。
(15)window.speed:内部使用。不要通过socket驱动改变此值。TFFS主要用它来存放完成flash设备互操作所需要的时 间。初始化后一般的默认值为250ns,但风河提供的MTD将它复位为120ns。如果我们自己写MTD,一定要在映射函数中正确 地复位该成员值。
(16)window.busWidth:内部使用。用于存储flash的位宽是8位还是16位。最初的复位值是16,但风河提供的MTD都设 位8。如果自己写MTD,也需要在映射函数中正确设置。
(17)cardDetected:通过我们的xxxRegister()函数初始化。它指向一个用于标识PCMICIA槽上有无flash存储卡的函数 。对不可移动的媒体,这个函数通常返回TRUE。如果这个函数返回FALSE,则cardChanged为TRUE。函数的巡检周期为100m s。
(18)VccOn:通过xxxRegister()函数设定。该成员指向一个用于打开flash操作电源的函数。当媒体空闲时,系统会关 掉电源以省电,而在再次访问flash媒体前,系统会调用该函数来再次打开电源。
在打开电源时,只有等到操作电压稳定了,VccOn函数才会返回值,如果必要,还需要调用flDelayMsec()或空闲 语句来等待VCC稳定。
(19)VccOff:通过xxxRegister()函数设定。该成员指向一个用于关闭flash操作电源的函数。通常,在系统相当空闲 的情况下,电源才会关闭。
(20)VppOn:通过xxxRegister()函数设定。系统通常调用该程序来打开编程电源(Vpp通常为12V,而vcc通常为3.3或5V )。由于并不是所有的flash芯片都需要这个电压,因而,只有当定义了SOCKET_12_VOLTS后这个成员才会被包含。
VppOn的函数返回状况与VccOn类似。
(21)VppOff:通过xxxRegister()函数设定。系统通常调用该程序来关闭编程电源。同样地,只有当定义了SOCKET_12_V OLTS后这个成员才会被包含。
(22)initSocket:通过xxxRegister()函数设定。系统在试图访问套接字之前调用与该成员相关的函数。TFFS用这个函 数来处理在访问套接字之前的一些必要的初始化,尤其是当这些初始化在套接字注册时不能完成时。比方说,如果你在套 接字注册时没有做硬件检测,或者flash存储器是可移动的,这个函数应当检测flash媒体,并在它移动后作出正确的回应 。
(22)setWindow:通过xxxRegister()函数设定。系统调用该成员指向的函数来更新window结构体中的关键成员。为大多 数硬件写一个setWindow函数,通常需要做如下几步:
* 按4000页设定window.baseAddress为基地址。页就是window的基地址除以4000。
* 调用flSetWindowSize()并以4K单位指定window大小。
TFFS假定访问窗口总是独占式的。也就是说,在设定这些窗口特征之一后,系统就不再允许你的应用程序直 接改变他们了,否则将破坏它。唯一的例外就是映射寄存器。因为,TFFS在它访问flash后总是重新建立寄存器,你的应 用程序也许会为了别的目的映射这些窗口而不是TFFS。但是,我们千万不能在中断函数中这么做。
系统如果带有多个socket驱动,请确认窗口的基地址各不相同。此外,我们还必须计算窗口大小并确认他们没有 重叠。
(23)setMappingContext:通过xxxRegister()函数设定。该成员指向一个用于设定window映射寄存器的函数。因为, 焊在板子上的flash阵列通常将全部的flash都映射到RAM,所以他们不需要这个函数。但众所周知,ss5 BSP相关的flash 阵列是个例外。还有,使用PCMCIA槽的flash卡使用这个函数来寻址映射寄存器,以便将有效的flash地址转移到主机的内 存窗口。
(24)getAndClearCardChangeIndicator:通过xxxRegister()函数设定。这个函数读取硬件卡改变标志并清除。如果你 没有这种硬件,可将它设为空指针。
(25)writeProtected:通过xxxRegister()函数设定。它指向一个可以获取当前媒体写保护开关状态的函数。当然,前 提是假设这个写保护开关存在。
(26)freeSocket:通过xxxRegister()函数设定。它指向的函数可以释放被socket驱动内部保留的资源。 /******未完(还多呢)********/

[upload=jpg]UploadFile/2004-5/2004511222220917.jpg[/upload]
[upload=jpg]UploadFile/2004-5/2004511222226228.jpg[/upload]
[align=right][color=#000066][此贴子已经被作者于2004-5-11 22:22:31编辑过][/color][/align]




关键词: 原创     Tornado     TrueFFS     编程     指南         

菜鸟
2004-05-12 06:24:00     打赏
2楼
虽然翻译的不好,但毕竟累了大半天,大家还是给点鼓励吧。

菜鸟
2004-05-12 17:00:00     打赏
3楼
我第一个来鼓励!amine,也给他加个精吧!

菜鸟
2004-05-12 17:26:00     打赏
4楼
呵呵,还是xiaohua好。好久没联系,还好吧。上次问你的LCD问题已经搞定了,能正常显示了。现在想看看文件系统就顺手翻译了,有理解错的地方你就直说。

工程师
2004-05-12 17:29:00     打赏
5楼
这个人情我来做啦,哈哈,加精!

菜鸟
2004-05-12 17:53:00     打赏
6楼
劳动成果能得到Gao老大的肯定,真是美死我了。^_^

菜鸟
2004-05-12 19:34:00     打赏
7楼
鲜花鼓励!

菜鸟
2004-05-12 20:09:00     打赏
8楼
不错不错~~~! 了我一个心愿。。。。

菜鸟
2004-05-12 23:31:00     打赏
9楼
以下是引用seasoblue在2004-5-12 12:09:00的发言:
不错不错~~~! 了我一个心愿。。。。
估计你没有仔细看,肯定有理解不到位的地方。

共9条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]