首页 vxWorks_BSP移植笔记

vxWorks_BSP移植笔记

举报
开通vip

vxWorks_BSP移植笔记修订历史 版本 日期 原因 V0.01 2009/04/08 创建文档 销售与服务网络(一) 广州周立功单片机发展有限公司 地址:广州市天河北路689号光大银行大厦12楼F4 邮编:510630 电话:(020)38730916 38730917 38730972 38730976 38730977 传真:(020)38730925 网址:www.zlgmcu.com 广州专卖店 地址:广州市天河区新赛格电子城203-204室 电话:(020)87578634 87569917 传真:(020)87578842 南...

vxWorks_BSP移植笔记
修订历史 版本 日期 原因 V0.01 2009/04/08 创建文档 销售与服务网络(一) 广州周立功单片机发展有限公司 地址:广州市天河北路689号光大银行大厦12楼F4 邮编:510630 电话:(020)38730916 38730917 38730972 38730976 38730977 传真:(020)38730925 网址:www.zlgmcu.com 广州专卖店 地址:广州市天河区新赛格电子城203-204室 电话:(020)87578634 87569917 传真:(020)87578842 南京周立功 地址:南京市珠江路280号珠江大厦2006室 电话:(025)83613221 83613271 83603500 传真:(025)83613271 北京周立功 地址:北京市海淀区知春路113号银网中心A座1207-1208室(中发电子市场斜对面) 电话:(010)62536178 62536179 82628073 传真:(010)82614433 重庆周立功 地址:重庆市石桥铺科园一路二号大西洋国际大厦(赛格电子市场)1611室 电话:(023)68796438 68796439 传真:(023)68796439 杭州周立功 地址:杭州市天目山路217号江南电子大厦502室 电话:(0571) 28139611 28139612 28139613 28139615 28139616 28139618 传真:(0571) 28139621 成都周立功 地址:成都市一环路南二段1号数码同人港401室(磨子桥立交西北角) 电话:(028)85439836 85437446 传真:(028)85437896 深圳周立功 地址:深圳市深南中路 2070号电子科技大厦C座4楼D室 电话:(0755)83781788(5线) 传真:(0755)83793285 武汉周立功 地址:武汉市洪山区广埠屯珞瑜路158号12128室(华中电脑数码市场) 电话:(027)87168497 87168297 87168397 传真:(027)87163755 上海周立功 地址:上海市北京东路668号科技京城东座7E室 电话:(021)53083452 53083453 53083496 传真:(021)53083491 西安办事处 地址:西安市长安北路54号太平洋大厦1201室 电话:(029)87881296 83063000 87881295 传真:(029)87880865 销售与服务网络(二) 广州致远电子有限公司 地址:广州市天河区车陂路黄洲工业区3栋2楼 邮编:510660 传真:(020)38601859 网址:www.embedtools.com (嵌入式系统事业部) www.embedcontrol.com (工控网络事业部) www.ecardsys.com (楼宇自动化事业部) 技术支持: CAN-bus: 电话:(020)22644381 22644382 22644253 邮箱:can.support@embedcontrol.com iCAN及数据采集: 电话:(020)28872344 22644373 邮箱:ican@embedcontrol.com MiniARM: 电话:(020)28872684 28267813 邮箱:miniarm.support@embedtools.com 以太网: 电话:(020)22644380 22644385 邮箱:ethernet.support@embedcontrol.com 无线通讯: 电话:(020) 22644386 邮箱:wireless@embedcontrol.com 串行通讯: 电话:(020)28267800 22644385 邮箱:serial@embedcontrol.com 编程器: 电话:(020)22644371 邮箱:programmer@embedtools.com 分析仪器: 电话:(020)22644375 28872624 28872345 邮箱:tools@embedtools.com ARM嵌入式系统: 电话:(020)28872347 28872377 22644383 22644384 邮箱:arm.support@zlgmcu.com 楼宇自动化: 电话:(020)22644376 22644389 28267806 邮箱:mjs.support@ecardsys.com mifare.support@zlgmcu.com 销售: 电话:(020)22644249 22644399 22644372 22644261 28872524 28872342 28872349 28872569 28872573 38601786 维修: 电话:(020)22644245 目 录 TOC \o "1-3" \h \z \u 1. 适用范围 1 2. BSP分析 2 2.1 BSP的文件构成 2 2.2 BSP的执行逻辑 3 2.2.1 BootROM image 3 2.2.2 VxWorks image 4 2.2.3 Driver加载的时机 5 3. 移植要点 6 3.1 异常处理 6 3.2 中断处理 9 3.3 时钟 11 3.4 串口驱动 11 3.4.1 概述 11 3.4.2 ttyDrv(包括tyLib) 12 3.4.3 xxDrv驱动的实现 15 3.5 编译链接 22 4. 参考资料 23 1.适用范围 主要从几个关键主题描述s3c2440a的 VxWorks BSP定制工作, 对整个过程作了详细描述。另外提供一些开发中需要使用的参考资源,包括 手册 华为质量管理手册 下载焊接手册下载团建手册下载团建手册下载ld手册下载 、文档、代码和工具等。 适用于基于ARM的VxWorks 的BSP开发。 此次移植的VxWorks BSP基于Tornado 2.2,适用于EPC6000,MiniHMI-1000等基于s3c2440a的工控板上。实现了向量 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 映射,中断异常管理,系统时钟,辅助时钟,Uart等最基本的驱动与功能。可用于生成VxWorks的bootrom和VxWorks镜像。 2.BSP分析 2.1​ BSP的文件构成 VxWorks的BSP组成文件主要包含在四个目录下: ​ Tornado\target\config\all :所有BSP的公共部分; ​ Tornado\target\config\comps\vxworks:基本模块描述文件(*.cdf); ​ Tornado\target\config\comps\src:模块配置文件(被usrConfig.c使用); ​ Tornado\target\config\bspname:与目标板相关的部分。 通常将\target\config\all 下的文件拷贝到\target\config\bspname\all,同时修改makefile文件中的“CONFIG_ALL”项,设置为正确的路径。这样做的目的是为了在修改all目录下文件时不影响其它的BSP。 下面分别介绍这些文件: 1.​ all目录: 在该目录下主要有如下几个文件: bootConfig.c:是bootrom的主要初始化与控制文件。BootConfig.c是usrConfig.c的一个子集,所以bootrom只能提供完整VxWorks Image中的部分功能。bootrom不使用MMU库(SPARC除外)。在集成环境下修改工程相关的配置信息不会影响bootrom,只有直接修改config.h,configAll.h,bootConfig.c和bootInit.c文件才会影响到bootrom; bootInit.c:定义了romStart()函数,用于bootrom的第二阶段初始化。首先把text和data段从ROM拷到RAM中,然后初始化部分RAM,进行解压; usrConfig.c:包含VxWorks镜像的主要初始化代码。在Tornado集成环境下生成VxWorks镜像时会用到此文件。 2.​ bspname目录: 在该目录下主要有如下几个文件: Makefile:bootrom的Makefile文件。其中定义了一些宏,如:ROM_TEXT_ADRS,ROM_SIZE,RAM_LOW_ADRS,RAM_HIGH_ADRS;这些宏定义应该与config.h下的定义相一致; config.h:包含所有的头文件和与CPU及系统相关的宏定义,如:对Cache和MMU的配置,RAM和ROM的定位以及大小配置; romInit.s:该文件是bootrom和带ROM启动功能的 VxWorks 镜像的初始化入口汇编代码,即实现了romInit()。目标板一上电就开始执行romInit(),主要完成三部分工作: ​ 关看门狗,屏蔽中断,禁能MMU,Cache,配置处理器时钟; ​ 初始化内存控制器; ​ 初始化堆栈指针和其它寄存器以执行C语言,然后调用romStart(). 注意:romInit()中的函数或变量必须设计成与内存地址无关的代码(PIC),如程序清单 2.1所示: 程序清单 2.1 与内存地址无关代码 L$_HiPosn: .long ROM_TEXT_ADRS + HiPosn - FUNC(romInit) L$_rStrtInRom: .long ROM_TEXT_ADRS + FUNC(romStart) - FUNC(romInit) L$_SMRDATA: .long ROM_TEXT_ADRS + SMRDATA - FUNC(romInit) romInit.s只执行一些必要的初始化,其余的初始化工作在后面完成。 sysALib.s:包含目标板或系统相关的汇编语言函数,即实现了_sysInit(),是基于RAM的VxWorks镜像的入口程序,当bootrom引导完镜像后,就会从此出开始执行。sysALib.s类似于romInit.s完成的工作,但它不必设计成PIC,且可调用其它库中的函数。 sysSerial.c:串口驱动程序的安装和初始化。 bspname.h:包含与处理器相关的宏定义。 sysLib.c:包含与目标板或系统相关的C语言函数,sysLib.c中应该实现以下几类函数: ​ 系统时钟中断相关的函数:sysClkConnect(),sysClkDisable(),sysClkEnable(), ​ sysClkInt(),sysClkRateGet(),sysClkRateSet(); ​ 系统硬件初始化函数:sysHwInit(),sysHwInit2() ​ 内存相关的函数:sysMemTop(),sysNvRamGet(),sysNvRamSet() ​ 串口相关的函数:sysSerialHwInit(),sysSerialHwInit2(),sysSerialChanGet() ​ 杂项函数:sysBspRev(),sysModel(),sysToMonitor() ​ 其它可选函数:如:辅助时钟中断相关函数,总线相关函数 其中部分函数的实现在驱动程序子文件中完成。通过包含C文件的方式引入到sysLib.c中,如程序清单 2.2所示: 程序清单 2.2 包含C文件 #include "sysInt.c" /* sys interrupt */ #include "sysTimer.c" /* sys timer */ #include "sysSerial.c" /* sio channel */ #ifdef INCLUDE_END #include "ax88796End.c" /* END device */ #endif 2.2​ BSP的执行逻辑 2.2.1​ BootROM image bootrom主要用于启动装载VxWorks image,因此完成较少的系统初始化,。一般有压缩和不压缩两种形式,如bootrom和boot_uncmp。与VxWorks image的主要区别在于Bootrom调用bootConfig.c,而VxWorks镜像调用usrConfig.c。 1.​ bootrom的执行逻辑: 文件romInit.s中的romInit→文件bootInit.c中的romStart→文件bootConfig.c中的usrInit→sysHwInit()→usrKernelInit()→KernelInit(usrRoot,...) usrRoot→bootCmdLoop(void)命令行选择,或autoboot→bootLoad(pLine, &entry)加载模块到内存(网络,TFFS,TSFS…) →netifAttach()→go(entry) →(entry)()从入口开始执行,不返回。 2.2.2​ VxWorks image 1.​ 不带ROM引导功能的VxWorks镜像 不带ROM引导功能的VxWorks镜像向需要bootrom将其加载到RAM中,sysaLib.s是在RAM中执行的第一个函数,执行逻辑如下: 文件sysaLib.s中的sysInit→文件usrConfig.c中的usrInit→sysHwInit→usrKernelInit→ KernelInit(usrRoot,...) 其主要函数及功能如表 2.1 函数 说明 关于失联党员情况说明岗位说明总经理岗位说明书会计岗位说明书行政主管岗位说明书 表 2.1 函数说明 函 数 函 数 功 能 所 在 文 件 sysInit() (a)锁住中断;(b)禁用缓冲; (c)初始化处理器寄存器到一缺省值; (d)清除所有悬置中断; (e)激活usrInit(),指明启动类型。 sysALib.s usrInit() (a)对bss赋零; (b)保存bootType于sysStartType; (c)调用excVecInit(),初始化所有系统和缺省中断向量; (d)依次调用sysHwInit(), usrKernelInit(),kernelInit(). usrConfig.c usrKernelInit() 依次调用classLibInit(),taskLibInit(),taskHookInit(),semBLibInit(),semMLibInit(),semCLibInit(),semOLibInit(),wdLibInit(),msgQLibInit(),qInit(),workQInit() usrKernel.c kernelInit() 初始化并启动内核。 (a)激活intLockLevelSet(); (b)从内存池顶部创建根堆栈和TCB; (c)调用taskInit(),taskActivate(),用于usrRoot(); (d)调用usrRoot(). kernelLib.c usrRoot() 初始化I/O系统,驱动器,设备(在configAll.h和config.h中指定) (a)调用sysClkConnect(),sysClkRateSet(), iosInit(),[ttyDrv()]; (b)初始化excInit(),logInit(),sigInit(). (c)初始化管道,pipeDrv(); (d)stdioInit(),mathSoftInit()或mathHardInit() (e)wdbConfig():配置并初始化目标代理机 usrConfig.c 2.​ 带ROM引导功能的VxWorks镜像 其中ROM驻留型的镜像在执行romStart函数时只把VxWorks镜像的data段复制到RAM的LOCAL_LOW_ADRS, text部分留在ROM并在ROM中执行,执行逻辑如下: 文件romInit.s中的romInit→文件\comps\src\romStart.c中的romStart→文件usrConfig.c中的usrInit→sysHwInit→usrKernelInit→KernelInit(usrRoot,...) 其主要函数及功能如表 2.2所示: 表 2.2 函数说明 函数 函数功能 所在文件 1.romInit() (a)禁止中断;(b)保存启动类型;(c)硬件初始化; (d)调用romStart(); romInit.s 2.romStart() (a)将数据段从ROM拷贝到RAM,清内存; (b)有必要的话将代码段从ROM拷贝到RAM,有必要的话解压缩;(c)调用usrInit(); romStart.c 3.usrInit() 初始化程序 usrConfig.c 4.usrKernelInit() 如果相应的配置文件被定义,对应函数被调用 usrKernel.c 5.kernelInit() 初始化并启动内核 kernelLib.c 6.usrRoot() 初始化I/O系统,驱动器,创建设备 usrConfig.c 2.2.3​ Driver加载的时机 在syslib.c文件中,被初始化的设备是系统或调试所依赖的,我们称为“近设备”,例如串口、时钟;在用户应用程序内被初始化的设备是依赖于操作系统的,我们成为“远设备”,例如在driver中需要使用信号量。 3.移植要点 3.1​ 异常处理 在VxWorks中对异常向量表的初始化是通过intVecBaseSet和excVecInit这两个函数来完成的。在ARM体系机构中,VxWorks提供的异常向量初始化大致如程序清单3.1所示: 程序清单3.1 VxWorks提供的excVecInit static struct excEnterEntry excEnterEntrys[5]={   {(unsigned char *)(0x00000004),(unsigned char *)excEnterUndef},    {(unsigned char *)(0x00000008),(unsigned char *)excEnterSwi},   {(unsigned char *)(0x0000000c),(unsigned char *)excEnterPrefetchAbort},   {(unsigned char *)(0x00000010),(unsigned char *)excEnterDataAbort},   {(unsigned char *)(0x00000018),(unsigned char *)intEnt} }; STATUS  excVecInit (void){    int i;   armInitExceptionModes();    for(i = 0;i<5;i++){       *(unsigned int*)(excEnterEntrys.vectorBase)  = 0xe59ff0f4;       *(unsigned int *)(excEnterEntrys.vectorBase+0xfc) = (int)(excEnterEntrys.vectorReal);    }    if(cacheLib.textUpdateRtn !=NULL){        cacheLib.textUpdateRtn(0,0x1c);    }    _func_armIrqHandler = (FUNCPTR)intEnt;     return OK;  } 从中可以看出,VxWorks不支持对ARM的FIQ的处理,异常向量表中的5个异常处理函数,是由VxWorks提供的异常处理函数,不需要用户来直接操作。 使用机器码0xe59ff0f4等同于“ldr pc,pc+0xfc”。 这段程序的意思是在异常向量表的安装基地址0地址开始处填写异常向量表跳转语句,在0x100处写异常处理的跳转地址。 VxWorks本来提供了intVecBaseSet函数来设置异常向量表的安装基地址,但是在ARM体系结构中intVecBaseSet是空的,根本不能通过调用该函数来改变异常向量表的安装基地址。 对于一些ARM体系结构的处理器来说,根本没有提供地址重映射功能,如s3c44B0x,或者是能映射的地址空间有限,如LPC2xxx,能重映射到0地址的RAM空间只有64字节。 通常这些处理器的启动Flash是0地址,因此VxWorks提供的excVecInit在这些处理器上无法完成异常向量表的安装。对于s3c2440a来说,在未使能MMU或者使能MMU但是进行平坦地址映射的情况下,Flash仍处于地址0。对于这些情况的处理 方法 快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载 有多种,下面以s3c2440a为例,进行介绍。 我们可以编写自己的excVecInit(),来替换VxWorks提供的excVecInit。如程序清单 3.2所示: 程序清单 3.2 自定义的excVecInit static struct excEnterEntry excEnterEntrys[5]={   {(unsigned char *)( VEC_BASE_ADRS+0x00000004),(unsigned char *)excEnterUndef},    {(unsigned char *)( VEC_BASE_ADRS+0x00000008),(unsigned char *)excEnterSwi},   {(unsigned char *)( VEC_BASE_ADRS+0x0000000c),(unsigned char *)excEnterPrefetchAbort},   {(unsigned char *)( VEC_BASE_ADRS+0x00000010),(unsigned char *)excEnterDataAbort},   {(unsigned char *)( VEC_BASE_ADRS+0x00000018),(unsigned char *)intEnt} }; STATUS  excVecInit (void){    int i;   armInitExceptionModes();    for(i = 0;i<5;i++){       *(unsigned int*)(excEnterEntrys.vectorBase)  = 0xe59ff0f4;       *(unsigned int *)(excEnterEntrys.vectorBase+0xfc) = (int)(excEnterEntrys.vectorReal);    }    if(cacheLib.textUpdateRtn !=NULL){        cacheLib.textUpdateRtn(VEC_BASE_ADRS,0x1c);    }    _func_armIrqHandler = (FUNCPTR)intEnt;     return OK;  } VEC_BASE_ADRS是异常向量表的安装基地址,在“configall.h”中定义,我们可以在“config.h”对其重新定义。如程序清单3.3所示: 程序清单3.3 VEC_BASE_ADRS #undef VEC_BASE_ADRS #define VEC_BASE_ADRS 0x30000000 这样VxWorks提供的异常处理向量表就能被安装到由VEC_BASE_ADRS所确定的RAM空间中。 启动Flash为0地址时还需要作以下处理:在Flash的0地址处编码异常向量处理入口, 异常发生时,经Flash存储器的异常入口,跳转到由自定义的excVecInit 函数所安装的RAM中的异常向量处理入口,再调用vxWorks提供的异常处理函数。如程序清单 3.4所示: 程序清单 3.4 Flash的异常入口程序 cold: mov r0, #BOOT_COLD /* BOOT_COLD boot entry */ warm: b start b Swi b Pabort b Dabort b cold b Irq b Fiq Swi: … Pabort: … Dabort: … Irq: sub sp,sp,#4 stmfd sp!,{r1} ldr r1,vecIrq str r1,[sp,#4] ldmfd sp!,{r1,pc} vecIrq: .long 0x30000018 /* VEC_BASE_ADRS+0X18 */ 异常处理流程如图 3.13.1: 图 3.1 异常处理流程图 对于s3c2440a,还可以使能MMU,将VEC_BASE_ADRS映射到0地址,以提高异常响应的速度。这里只映射了1页的地址空间。 如程序清单 3.5所示: 程序清单 3.5 VEC_BASE_ADRS映射 #ifdef INCLUDE_MMU PHYS_MEM_DESC sysPhysMemDesc[] = { #ifdef EXCEPTE_VECT_MMU_MAP /* remap system except tbl */ { (void *)ROM_BASE_ADRS, (void *)VEC_BASE_ADRS, PAGE_SIZE, VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE|VM_STATE_MASK_CACHEABLE, VM_STATE_VALID | VM_STATE_WRITABLE | VM_STATE_CACHEABLE_NOT }, … 3.2​ 中断处理 ARM的中断是抢占式的,因此在“config.h”中定义中断模式如程序清单3.6: 程序清单3.6 定义中断模式 #define INT_MODE INT_PREEMPT_MODEL intLibInit是中断库初始化函数,需要在中断初始化前调用。它根据传入的 参数 转速和进给参数表a氧化沟运行参数高温蒸汽处理医疗废物pid参数自整定算法口腔医院集中消毒供应 (最大中断向量数,中断模式),来进行处理,根据最大中断向量数分配内存,其结构大致如程序清单3.7所示: 程序清单3.7 中断向量表 struct { VOIDFUNCPTR routine; int parameter; }intVecTable[INT_NUM_LEVELS] 调用intConnect函数安装中断向量程序入口及参数到intVecTable。如程序清单 3.8所示: 程序清单 3.8 intConnect STATUS intConnect ( VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) intLibInit根据参数INT_MODE设置_func_armIrqHandler这个钩子函数 ,这个钩子函数可被设置为intIntRtnPreemt或intIntRtnNoPreemt。在ARM体系结构中,_func_armIrqHandler被设置为intIntRtnPreemt。 VxWorks的中断处理流程大致如图3.2所示: 图3.2 VxWorks的中断处理流程 中断初始化函数的实现如下,我们需要安装VxWorks的中断处理回调函数,如程序清单3.9所示: 程序清单3.9 中断初始化 int s3c2440aIntInit (void) { /* * 所有中断都为 IRQ 模式,屏蔽所有中断,清除所有子中断。 */ … /* * Install the driver routines in the architecture hooks */ sysIntLvlVecChkRtn = s3c2440aIntLvlVecChk; sysIntLvlVecAckRtn = s3c2440aIntLvlVecAck; sysIntLvlChgRtn = s3c2440aIntLvlChg; sysIntLvlEnableRtn = s3c2440aIntLvlEnable; sysIntLvlDisableRtn = s3c2440aIntLvlDisable; … return OK; } 各个回调函数的主要功能如下: sysIntVecChkRtn:查找中断源,并根据中断源确定中断向量(屏蔽当前中断,清中断)。 sysIntLvlVecAckRtn:中断处理结束后的一些工作(使能当前中断)。 sysIntLvlEnableRtn:使能某个中断向量。 sysIntLvlDisableRtn:禁止某个中断向量。 其具体实现根据中断控制器的不同而不同,s3c2440a的具体实现可参考s3c2440a_wrsbsp包中的“sysInt.c”文件。 3.3​ 时钟 系统时钟是操作系统运行的基础,时钟驱动的修改需要首先完成。 3.4​ 串口驱动 3.4.1​ 概述 vxWorks的串行设备的驱动不同于一般的设备的驱动。一般的设备都是在系统初启的时候调用xxDrv()来安装DriverTable。然后,调用xxDevCreate来将该设备描述符xx_DEV加入到DeviceTable中。在应用层使用设备的时候,直接通过fddevice listDriverTable的顺序调用相应的驱动函数即可。他们的层次关系是:应用I/O system Driver。层次关系很明确。然而串行设备的层次关系就不完全是这样子的。基于许多因素的考虑,vxworks的串行设备的驱动分成了如图3.3所示的几层: 图3.3串行设备驱动代码的分层结构 从图中可以看出:系统中的串行设备驱动总共有3层。其中,usrConfig.c和ttyDrv(包括tyLib)提供了一些对串行设备的一些通用操作。sysSerial.c中一些对不同开发板(系统)中串行设备有关的一些数据结构进行初始化。所以,称之为Implementation specific code。最后,的xxDrv.c当然是包括了一些具体设备相关的驱动/操作。(比如读写数据,设置等) 包含了串行设备的系统的总体的一个模型: 图3.4 系统的模型 从图3.4看出串行设备的驱动xxDrv并不是直接和I/O system交互的。中间存在一个ttyDrv(包括tyLib)。实际上,在DriverTable中安装的不是xxDrv的函数而是ttyDrv/tyLib提供的函数。另外,Target Agent可以和xxDrv交换,方便系统的调试。 ttyDrv(包括tyLib):可以称之为一个虚拟的设备驱动。因为他只是介于I/O与底层的具体设备的driver之间,为系统提供的统一的串行设备的界面。另外,还可以调用具体硬件的管理驱动。总之,ttyDrv给系统提供的是一些通用的管理函数(缓冲管理,互斥等)。所以,ttyDrv往往就可以管理多个设备。图3.5表明ttyDrv在系统中的位置: 图3.5 ttyDrv在系统中的位置 xxDrv:给ttyDrv和target agent提供支持。具体的内容在下面叙述。 3.4.2​ ttyDrv(包括tyLib) 从概述中知道ttyDrv(tyLib)是一个虚拟的驱动,既管理着和I/O的交互,又管理着和底层硬件驱动的交互。他在和I/O交换的时候所作的工作主要有: ​ I/O System requirements (such as adding entry inDriver Table and creating device descriptor andadding it to the system Device List) ​ Handling all I/O system entry routines, e.g. ttyOpen,ttyIoctl, tyRead, tyWrite. ​ Manages selectLib calls ​ Manages command line editing (see ioctlfunctionality in tyLib man page) ​ Manages data buffering ​ Manages task sychronization on full or empty buffers ​ Manages mutual exclusion on buffers ​ 其中,ttyDrv负责着ttyOpen、ttyIoctl的接入,而tyLib负责着tyRead、tyWrite的接入。图3.6给出一个更加细致的系统的数据的流向图: 图3.6 ttyDrv的数据流图 从图中,系统的层次关系就很清楚了。应用层往往调用通用的ioLib中的函数read、write、ioCtrl等。这些函数从输入的fd中找到相应的设备描述符,然后找到了driver table。调用driver table中的函数。而driver table中的函数则是第二层的东西了(ttyDrv/tyLib(tyWrite、tyRead等))。ttyDrv/tyLib和真正的设备(xxDrv)打交道。第二层和底层的通讯是通过回调函数(callback)来实现。具体的说就是:ttyDrv提供两个函数负责输出时候底层驱动可以从buffer中的到数据,输入时候底层驱动可以将接受到的字符填入到buffer中。tyLib给提供的回调函数的格式如程序清单3.10: 程序清单3.10 tyLib 回调函数 STATUS tyIRd ( TY_DEV_ID pTyDev, /* ptr to tty device descriptor */ char inchar /*输入的缓存指针 */ ) STATUS tyITx ( TY_DEV_ID pTyDev, /* pointer to tty device descriptor */ char * pChar /* 从缓存中得到的字符 */ ) 下面我们来对从上到下的各个函数进行说明: 1.​ ttyDrv() 他调用iosDrvInstall()将ttyDrv和tyLib中的函数安装的driver table中。此函数是在系统启动的时候由usrRoot()调用。此函数在不INCLUDE_TYCODRV_5_2即自动的被调用。 2.​ ttyDevCreat() 他主要完成如下的工作: ​ Allocates and initializes a device descriptor ​ Initializes tyLib by calling tyDevInit( ): ​ selectLib initialization ​ Creates input and output ring buffers ​ Creates semaphores ​ Calls iosDevAdd( ) to add the device to the device list ​ Installs tyLib routines as input and output callbacks(给底层的设备安装回调函数。) ​ Starts the device in interrupt mode. 此函数也是在系统启动的时候由usrRoot()调用。 3.​ write( ) tyWrite( ) xxDrv ttyDrv将tyWrite安装到了driver talbe中。然后,tyWrite就对所有的串行设备做同样的事情: ​ 如果ring buffer满则阻塞 ​ 从用户的buffer中读数据到ring buffer中 ​ 在一定的情况下激活xxDrv开始传数据周期(一个传输周期首先传送数据到设备,等待设备给出一个中断来表示继续传送下一个数据)。 ​ xxDrv用tyITx()来从输出ring buffer中读数据 4.​ read( ) tyRead( ) xxDrv ttyDrv将tyRead安装到了driver talbe中。然后,tyRead就对所有的串行设备做同样的事情: ​ 如果ring buffer空则阻塞 ​ 从ring buffer读数据到用户的buffer中 ​ 处理X-on/X-off ​ 如果输入ring buffer中还有字符使所有的阻塞的进程启动 ​ xxDrv用tyIRx()来将设备读到的字符写入到输入ring buffer中 5.​ ioctl() ioctl将函数传递到xx ioctl(),如果设备驱动没有实现此功能,则将控制转移到tyIoctl。他们的关系如图3.7所示: 图3.7 ioctl控制的流向 总之,ttyDrv和tyLib之所以要独立称为一层可能主要是因为从代码可复用和统一界面两个角度来考虑的。代码可重用,是因为所有的串行设备都有一些同样的管理工作(缓存的管理,信号的管理等)。同样为了给I/O提供统一界面,ttyDrv在driver table中安装了统一的驱动函数。这样I/O和串行设备的交互就被屏蔽了。最后,图3.8给出一个ttyDrv和tyLib在系统中所做工作的概括图: 图3.8 ttyDrv和tyLib 3.4.3​ xxDrv驱动的实现 要编写串行设备的驱动主要需要做以下几个方面的工作: ​ 初始化:确定系统要支持的串行通道的个数 ​ 初始化设备的描述符 ​ 写设备的初始化代码 ​ 编写entry point函数 ​ 编写设备中断服务程序(ISR) ​ 修改sysSerial.c文件(下一节介绍) 1.​ 初始化过程的概述 要编写设备的初始化代码,首先我们看看系统初始化的大概顺序,如图3.9: 图3.9系统初始化串行设备顺序 上图中sysSerialHwInit()是BSP中要编写的函数(sysSerial.c)。xxDevInit()在入口点函数中编写。SysSerialHwInit2()同样是在BSP中编写。有关sysSerial.c中的函数在下一节叙述。TtyDrv不用说了。而sysSerialChanGet()也是在sysSerial.c所提供的。 在这里,我们首先要做的就是根据具体的串行设备定义出自己的设备描述符xx_DEV结构。这也是编写串行设备驱动的第一步。 xx_DEV结构是加在device list中的所以他们和一个DRV_HEAD,然后包含这一些设备相关的成员将构成一个”设备“。对于串行设备这个具体的成员主要是一个xx_CHAN结构,来表示设备的通道。程序清单 3.11是s3c2440a的xx_CHAN结构的例子: 程序清单 3.11 s3c2440a的xx_CHAN结构 typedef struct { SIO_DRV_FUNCS *pdrvFuncs; /* SIO 驱动程序组 */ int (*pcbGetTxChar)(); /* 中断回调函数 */ int (*pcbPutRcvChar)(); void * pvGetTxArg; /* 回调函数句柄 */ void * pvPutRcvArg; int iChannelMode; /* 同步 IO 通道模式 */ UINT8 (*pfuncHwInByte)(int); /* 物理硬件接收一个字节 */ void (*pfuncHwOutByte)(int, char); /* 物理硬件发送一个字节 */ int iChannelNum; /* 通道号 */ int iBaud; /* 波特率 */ int iHwOption; /* 硬件选项 */ int iRs485Flag; /* 对串口是否要使能485功能 */ } __SAMSUNGSIO_CHANNEL; 2.​ 编写entry point函数 在建立了数据结构的基础上,下面就得做一些具体的通讯函数的编写。这些函数包括SIO_DRV_FUNCS结构中的函数、输入输出ISR和一个辅助函数xxDevInt()用来初始化xx_CHAN结构。SIO_DRV_FUNCS中主要有下表里的一些函数: ​ xxcallBackInstall()函数 s3c2440a的移植如程序清单 3.12: 程序清单 3.12 xxcallBackInstall()函数(s3c2440a的例子) static int __uartcbInstall(SIO_CHAN *psiochanChan, int iCallbackType, STATUS (*callbackRoute)(), void * pvCallbackArg) { __PSAMSUNGSIO_CHANNEL psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan; switch (iCallbackType) { case SIO_CALLBACK_GET_TX_CHAR: /* 发送回电函数 */ psamsungsiochanUart->pcbGetTxChar = callbackRoute; psamsungsiochanUart->pvGetTxArg = pvCallbackArg; return (OK); case SIO_CALLBACK_PUT_RCV_CHAR: /* 接收回电函数 */ psamsungsiochanUart->pcbPutRcvChar = callbackRoute; psamsungsiochanUart->pvPutRcvArg = pvCallbackArg; return (OK); default: errnoSet(ENOSYS); return (ERROR); } } ​ xxDevInit()函数 从图3.9中知道此函数是系统启动过程中首先调用的一个底层驱动函数。它被sysSerialHwInit函数调用。用来在对开发板的串行设备描述符初始化的基础上,来安装entry point函数到SIO_DRV_FUNCS结构里。s3c2440a的移植是通过sioChanCreate来实现的,如程序清单 3.133.13: 程序清单 3.13 sioChanCreate static SIO_DRV_FUNCS __GsiodrvUartDrvFunc = { (int (*)(SIO_CHAN *,int, void *))__uartIoctl, __uartStartup, (int (*)())__uartcbInstall, __uartPollRxChar, (int (*)(SIO_CHAN *, char))__uartPollTxChar }; SIO_CHAN *sioChanCreate (int iChannelNum) { __PSAMSUNGSIO_CHANNEL psamsungsiochanUart; SIO_CHAN *psiochan; UINT8 ucDataBits; UINT8 ucStopBits; UINT8 ucParity; switch (iChannelNum) { case COM0: psamsungsiochanUart = &__GsamsungsiochanUart0; psamsungsiochanUart->pdrvFuncs = &__GsiodrvUartDrvFunc; /* SIO FUNC */ psamsungsiochanUart->iChannelNum = COM0; INTER_SET_SUBMSK((7)); /* disable subInt for UART0 */ break; case COM1: … case COM2: … default: return (NULL); /* 通道号错误 */ } psiochan = (SIO_CHAN *)psamsungsiochanUart; … uartInit(iChannelNum, UNUSE_INF, ucDataBits, ucStopBits, ucParity, UART_DEFAULT_BAUD, NULL); return (psiochan); } 输出数据的驱动部分包含了两个底层的驱动函数的编写:一个启动输出的函数xxTxStartup()、一个接受输出中断的ISR-xxTxInt()。输出部分几个函数的调用关系如图 3.10所示: 图 3.10输出部分函数的调用关系 ​ xxTxStrartup() 当用户要向设备写数据时,就调用了tyWrite。tyWrite将数据写入到ouput ring buffer中后,调用xxTxStrartup()启动设备进行一个输出周期。s3c2440a的移植如程序清单 3.14: 程序清单 3.14 __uartStartup static int __uartStartup (SIO_CHAN *psiochanChan) { __PSAMSUNGSIO_CHANNEL psamsungsiochanUart = (__PSAMSUNGSIO_CHANNEL)psiochanChan; char cTx; switch (psamsungsiochanUart->iChannelNum) { case COM0: if ((((rUFSTAT0) >> 8) & 0x3F) == 0) { /* 可以直接写入发送 FIFO */ do { if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, &cTx) != OK) { break; } WrUTXH0(cTx); /* 发送数据 */ } while ((((rUFSTAT0) >> 8) & 0x3F) < __COM_FIFO_MAX); } else { if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, &cTx) != OK) { break; } while ((((rUFSTAT0) >> 8) & 0x3F) > __COM_FIFO_MAX); WrUTXH0(cTx); /* 发送数据 */ } INTER_CLR_SUBMSK(BIT_SUB_TXD0); /* 使能 FIFO 空中断 */ break; case COM1: … case COM2: … return (OK); } ​ xxTxInt() 当设备输出完毕后,设备就给cpu一个中断表示可以接受下一个字符,然后进入中断xxTxInit()。s3c2440a的移植如程序清单3.15: 程序清单3.15 TX中断处理 if (rSUBSRCPND & BIT_SUB_TXD0) { /* 发送中断 */ if (psamsungsiochanUart->pcbGetTxChar(psamsungsiochanUart->pvGetTxArg, (char *)&ucData) != OK) { /* 发送结束 */ INTER_SET_SUBMSK(BIT_SUB_TXD0); /* 发送结束 */ } else { WrUTXH0(ucData); /* 发送数据 */ } INTER_CLR_SUBSRCPND(BIT_SUB_TXD0); /* 清除发送中断 */ } 输入数据部分的驱动只保含了一个输入中断ISR函数的编写。该ISR在有数据到时候,将寄存器中的数据通过回调函数写入到input ring buffer中。输入部分几个函数的调用关系如图 3.11所示: 图 3.11输入部分函数的调用关系 s3c2440a的移植如程序清单3.16所示: 程序清单3.16 Rx中断处理 if (rSUBSRCPND & BIT_SUB_RXD0) { while (rUFSTAT0 & 0x3F) { /* 需要接收数据 */ ucData = RdURXH0(); psamsungsiochanUart->pcbPutRcvChar(psamsungsiochanUar
本文档为【vxWorks_BSP移植笔记】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_457636
暂无简介~
格式:doc
大小:488KB
软件:Word
页数:28
分类:互联网
上传时间:2011-08-27
浏览量:42