VXWORKS——驱动开发

简介:在VxWorks嵌入式开发中,BootRom是VxWorks操作系统集成的启动代码,在Tomado集成开发环境的Build菜单中可以直接编译BootRom,它的功能和U-boot类似,都是Bootloader程序。只是BootRom是由VxWorks提供的一个bootloader程序,通过它可以和Tornado集成的一些工具进行VxWorks内核的下载和调试工作。

  通常,BootRom软件有以下功能:
  (1)通过串口下载操作系统映像;
  (2)通过串口升级自身映像;
  (3)通过串口下载系统配置文件、系统信息文件;
  (4)加载操作系统映像,使其正常启动;
  (5)其他的辅助功能,如地址内容查看功能、地址内容修改功能和bootrom菜单显示信息控制功能

1、usrTffsConfig (0, 0, "/kernel" );

vxworks的tffs位于dosfs文件系统和底层硬件中,目的是dosfs文件系统是针对磁盘的FAT文件系统,而大部分嵌入式存储设备是flash,flash和磁盘在物理特性上差别很大,读写方式不同:磁盘是一个一个字节修改,而flash在写之前必须擦除,其擦除和写有次数限制(大部分是10W次);tffs屏蔽了底层设备差异

dosfs位于tffs上层,包含翻译层、MTD层和socket层。翻译层由vxworks提供,不需要修改,我们只需要修改MTD层和socket层。

翻译层主要实现TrueFFS和dosFs之间的高级交互功能,也包含了控制flash映射到块、wear-leveling、碎片回收和数据完整性所需的智能化处理功能。

MTD层:即设备驱动层,包含flash读、写、擦除、ID识别等驱动。

socket层:用来提供tffs和板卡硬件(如flash卡)的接口服务。

2、VXWORKS的BSP开发方法

一般分为公共特性的BSP开发和特有特性的BSP开发。

公共特性的开发对平台来说是各个产品需要做适配的工作,并且不需要修改或者修改很少的vxworks内核代码,在内核配置中增加需要相应的特性即可。但增加特性后,会在BSP目录下的config.h文件增加INCLUDE宏;并且在usrboot()即内核启动程序中添加相应的初始化函数。例如增加tffs特性:在内核配置tffs后,config.h会增加INCLUDE_TFFS宏,并自动在prjconfig.C文件(此文件也是根据配置生成的)的usrIosExtraInit()函数增加tffsDrv()和usrTffsConfig()函数。

特有特性的BSP开发是各个产品负责的,每个产品由于硬件配置不一样,所以BSP特性也需要做相应的改变。这种特有特性的开发则需要将和BSP相关的.c和.h文件放在自己的BSP目录下,修改产品的初始化代码,添加相关的BSP初始化(取代公共特性开发中vxworks自动添加的步骤)。例如增加tffs特性:不需要配置内核支持tffs特性,取代的是将systffs.c、systffs.h放在BSP目录下,在初始化中添加tffsDrv()和usrTffsConfig()函数。

3、TFFS中两大数据结构:FLSOCKET和FLFLASH

FLFLASH是MTD层维护数据的结构:结构中包含了MTD维护的数据和flash的操作方法,包括重映射、读、写、擦除等函数指针。这个数据结构包含socket指针,指向flash对应的socket数据结构。

FLSOCKET是socket层维护的数据结构:为TFFS提供了指向处理flash硬件接口的函数指针。

4.用usrTffsConfig()给flash挂接dos设备

usrTffsConfig(drive,removable,fileName)在tffs flash驱动设备上挂在文件系统。它的参数如下:

drive:制定tffs flash驱动设备的驱动号,有效值是从0到BSP中套接字接口数量。

Removable:指定是否为可移动设备。固定的为0,可移动的为1.

fileName:指定挂载点,例如,”/tffs0/”.

在shell中输入tffsDevFormat(0,0) 成功后,继续输入usrTffsconfig(0,0,”/tffs0/”),返回value=0=0x0,成功。

此时用 devs 命令查看挂接的设备名,发现 /tffs0/ ,说明设备挂接成功。接下来就可以使用 dosfs 文件系统相关命令操作 flash 设备了,如 ls,copy 等。

VxWorks的设备驱动程序有三张表来维护: Fd Table、Dev Table、Drv Table,分别表示文件描述符表、设备列表、驱动程序表。

调用open、read、write、ioctl这些函数时都要使用一个句柄即文件描述符,即fd Table(文件描述符表)。在终端模式下用命令iosFdShow函数查看已使用的文件描述符内容:

->iosFdShow

   fd         name                        drv
  3           /pcConsole/0           2
  4           /vio/1                          7

Fd Table中包含有句柄号(fd),对应的设备名称(name),驱动号(drv),这一个表联系着另外两个重要的表:Dev Table和Drv table。

dev tabel中维护系统中所有的设备,在命令行中敲入devs便可以查看dev Table的内容,就是设备列表:
->devs

drv name
  0 /null
  1 /tyCo/0
  1 /tyCo/1
  2 /pcConsole/0
  2 /pcConsole/1
  4 /ata0a
  6 host:
  7 /vio
  8 /ghDev
  9 xxdev

dev table中包含两个内容:一个是驱动号(drv),一个是设备名称(name),仔细对比上面的dev tabel和fd table就可以发现,这两个表中设备名称和驱动号是对应着的。

Drv table ,驱动程序表,维护者所有的驱动程序,在命令行里:

-> iosDrvShow
drv    create          delete             open           close             read            write            ioctl
  1    388660          0                   388660      3886a0     388eb0     388da0     3886e0
  2    30bae0          0                  30bae0            0           388eb0     388da0     30baf0
  3         0                 0                 384040       3840a0     3840d0     384120     384240
  4    36d3f0       36d7f0           36d030       36d490     36e180      36e1f0     36eb60
  5         0                 0                     0            33e970        33f8b0       33f2d0     356ec0
  6    348e80     349380         3499e0      349ec0       34c2f0       34c640     34c870
  7    3918c0          0              3918c0        3919a0       388eb0     388da0     391a40
  8    318620          0               318620       3186e0       318650     318680     3186b0
  9    318840     318850        318870      3188a0       318900     318930     3188d0

从上面的表中可以看到驱动号(drv)和七个函数。驱动号是驱动程序的一个索引号,这个索引将三张表联系起来,任何一张表都能够通过这个索引找到彼此;Drv table后面有七个驱动函数,下面所列的数字是这些函数的地址。

例如:

open的第一个参数是一个设备名,系统就会首先在dev Table设备列表中寻找该设备名"/ghDev",找到之后就知道了这个设备的驱动号8,8号设备找到了怎么执行相应的open函数呢,这时候系统找到Drv table中与8号对应的驱动程序们的地址,找到与open对应的函数的入口地址318620,便将程序跳转至318620处执行。执行完后为这个已经open成功的8号设备"/ghDev"分配一个fd,并添加到fd table中去,便于应用程序继续使用该设备。在执行完open之后,接着就要对设备进行各种read\write操作,同样在drv tabel中找到相应的入口函数执行。
两个疑问:
1、怎样把我的open函数、wrie函数等加到Drv Table中去呢?
2、怎么让系统把我自己的设备也列入到dev table设备列表中呢?

答案就是两个函数:iosDrvInstall()、iosDevAdd()。

/dev/null是个黑洞设备 ,它丢弃一切写入其中的数据,空设备通常被用于丢弃不需要的输出流。任何写入该设备数据都会被丢弃掉。从这个里面读取数据返回空(也有人认为是读该空设备,直接读到文件尾,那就是返回-1)。将一些不用内容经常发送给这个设备,丢弃不需要的数据。

5、taskSpawn 创建并激活一个新的任务

int taskSpawn
    (
    char          *name,        /*任务名*/
    int           priority,     /*任务优先级,vxWorks好像共255个,而且调度采用优先级抢占式,同优先级轮换式的调度方式*/
    int           options,      /*任务的一些特性,例如VX_SUPERVISOR_MODE 0x0001                               OBSOLETE: tasks always in sup mode*/
    int           stackSize,    /* 需要申请堆栈的大小*/
    FUNCPTR       entryPt,      /*任务处理函数*/
    int           arg1,         /*任务处理函数需要的参数*/
    int           arg2,
    int           arg3,
    int           arg4,
    int           arg5,
    int           arg6,
    int           arg7,
    int           arg8,
    int           arg9,
    int           arg10 
    )

使用i查看系统中的任务。

一般来说,应用程序的优先级不应当比系统任务高。系统默认任务优先级是100   最好把用户任务优先级设置成100开外。

堆栈大小一般是根据你程序的内存使用情况而定的,如果拿不准,可以预设大一些,然后根据运行情况(Tornado里有插件可以时时查询)再降低。一般要有50%的余量。

你可以先设置一个比较大的数,然后根据运行后的情况再减小栈,shell里可以查看到栈使用的峰值,你可以在这个基础上考虑20%的冗余。
如果栈溢出,那么和内存越界操作是等同效果的。

6、任务的状态

就绪(READY):任务只需要等待CPU资源;

阻塞(PEND):由于CPU以外的资源不可用而阻塞;

睡眠(DELAY):任务处于睡眠状态;

挂起(SUSPEND):这种任务状态不能执行

DELAY+S既处于睡眠状态又处于挂起状态:挂起异常的任务(默认的异常处理)

PEND+S既处于阻塞状态又处于挂起状态

PEND+T超时阻塞

PEND+S+T超时阻塞并挂起

State+T处于state带有一个继承优先级的任务状态。


7、控制任务调度的函数调用

kernelTimeSlice()控制轮转调度:参数为时间片的长度,即每个任务放弃CPU给另一个同优先级的任务前,系统允许它运行的最大长度。

taskPrioritySet()改变任务的优先级

taskLock()禁止任务调度

taskUnlock()允许任务调度


wind内核的优先级 256个,编号0~255,优先级0最高,255最低。


任务的优先级在创建时指定,任务可以调用taskPrioritySet改变自己的优先级。

8、轮转调度:让优先级相同的、处于就绪态的任务公平的共享CPU。轮转调度使用时间片来分配CPU,每个任务执行一个预先确定的时间段(即时间片)。

使用轮转调度算法时,每个任务都有一个运行时间计数器

随着系统时钟增加而增加,达到规定的值(时间片的值)时,清0,此时,任务放到所在优先级队列的尾部。

一个新加入的任务放在所属优先级队列的尾部,计数器初始为0.当被高优先级任务抢占时,保存它的当前运行时间计数器,下次被调度时,恢复这个值。

9、抢占上锁

在实际应用中,有时候需要避免抢占,以免发生不合理的抢占或者发生一些意想不到的情况。wind的调度器提供:

taskLock()和taskUnlock()来禁止/允许抢占。

禁止:当该任务执行时,将不会发生基于优先级的抢占;

只能防止任务的上下文切换,不能禁止中断;

禁止抢占可以用来实现互斥;但应当尽量使禁止抢占时间最小。


vxworks动态链接功能很容易实现代码共享,一个被多任务调用的单个备份称为共享代码。

共享代码必须是可重入的:被多个任务同时调用而不会发生冲突。

惯例

所有name_r()命名的子程序被认为是不可重入的;

vxworks的I/O驱动程序是可重入的。

编写可重入代码的技术:

使用动态堆栈变量;

使用信号量保护全局或静态变量;

任务变量。

10、vxworks系统根任务

usrRoot是内核执行的第一个任务。prjConfig.c文件中有usrRoot()函数。

vxwork提供丰富的任务控制功能,包含在taskLib库中。包括任务的创建、控制和获取任务信息。

11、taskSpawn

堆栈是系统资源,位于内存中,其底端是TCB(任务控制块)和任务名,堆栈使用0xEE填充。

成功返回任务ID号:四字节

失败返回ERROR:

s_intlib_not_isr_callable程序不能从一个ISR中调用;

s_objlib_obj_id_error不正确的任务ID

s_memobjlib_not_initialized在指定的分区中,没有足够的内存用于发起任务

s_memlib_block_error不能对内存分区互斥访问

s_tasklib_illegal_priority非法的优先级


任务名约定:所有从目标机启动的任务以字母t开头命名,从主机启动的任务以字母u开头命名。

若没有任务名,则vxworks为其分配一个独一无二的名字tN,N是随未命名任务数递增的一个十进制整数。


12、任务运行的控制

taskSuspend()挂起任务

taskResume()恢复任务

taskRestart()重启任务

taskDelay()任务延时,单位为tick,将会导致任务呗移到相同优先级就绪队列的尾部。例如taskDelay(0)可以将CPU交给同优先级的另一个任务。

nanosleep()任务延时,单位为纳秒,参数不能是0.


13、POSIX和wind调度方法的差异:

不同:

POSIX调度基于进程,而WIND调度基于任务。

进程与任务的不同

任务可以直接访问内存,而进程不可以;

进程仅仅继承了父进程的特定特征,而任务则操作在与父任务完全一样的环境中。

进程与任务的相似之处

任务和进程都可以被单独调度。


POSIX与wind的优先级编号方案不同

POSIX的优先级数大,优先级高;

wind的优先级数大,优先级低。



  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值