vxWorks笔记

利用vxWorks可裁减可动态链接特性进行模块调试的分析

a) 首先,可将root.c简化,去掉大部分不需要加载的模块和想要调试的模块,以加快系统启动速度。
 
b) 如果vxworks加载的.o中引用了目前系统中不存在的symbol,则系统将该symbol的指针置为0,

即使后面加入了定义该symbol的.o文件,也不会将前面的引用修正,执行这些函数时,系统会崩溃。

因此不能分开加载互相依靠的.o文件。而vxWorks又不能加载.a文件(由于不是elf格式)。

解决方法是:将这些.o文件链接成可执行的.out文件,或用ld -o命令将这些.o文件生成一个大的.o文件再加载,

如:ld -o -r garp.oo garp.o garp_cmd.o gid.o gidtt.o gip.o sys.o

其中 -r表示产生可重定位的输出, 比如,产生一个输出文件它可再次作为'ld'的输入.这经常被叫做"部分连接".
 
c) 加载方法:在shell中执行ld < garp.oo或ld 1, 0, “garp.oo” ,

其中后者将内部连接的符号(如静态函数)也加入系统符号表中,这样就可以直接在shell中调用静态函数了。

使用 moduleShow命令可以查看目前已加载的模块。
 
d) 加载后在shell中执行模块初始化函数,如garp_init 。

如果运行效果不理想,可重新编译该模块并重新加载。

 

e) 因为garp等模块初始化时,分配了许多系统资源,因此在重新加载前,需要对其进行销毁。

可编写诸如 garp_cleanup 等函数,专门用于调试时释放资源。

shell中执行garp_cleanup函数,然后卸载:unld “garp.oo” 。


f) 重新加载后,再执行garp_init。
 

g) 由于

interface_set_showrunning_service,

registercmd,registerncmd,

register_subcmd,

register_module_version

等注册函数所在模块未提供相应的反注册函数,注册多次系统会出问题,因此要保证其只注册一次。

可将garp_init中涉及到这些函数的调用语句注释掉,在第一次加载时手工调用,

以后只要操作系统不重新启动,重新加载不要再调用这些函数。

 
h) 在操作系统启动后,立刻进行所有端口的创建和状态通知,因此我们加载的模块得不到这些通知。

可手工调用相关的回调及其下层函数,进行“假通知”,

如果需要调用静态函数,最好以ld 1,0,”garp.oo”方式进行加载。

 
函数调用栈结构

      Last sp

      PC

      ……

      Last2 sp

      PC

      ……

      Last3 sp

      PC

      ……

 
使用 SYS_PC_SAVE宏,可以得到指针sp,指向Last sp。而last sp单元中存储的值则是指向last2 sp的指针,依此类推。
PC中存储的是该段代码的调用地址。

如下代码可以打印出某行代码的调用关系(打印1至2级调用者)

   SYS_PC_SAVE

   Print("[%s:%d:%s] is called at 0x%08x from 0x%08x\n",

          __FILE__, __LINE__, __FUNCTION__,

          SYS_PC_GET, *(uint32*)(*((uint32*)(&SYS_PC_GET)-1)+4)

          );

   SYS_PC_RESTORE

注:

#define SYS_PC_SAVE register uint32* sp __asm__("1");{

#define SYS_PC_RESTORE }

#define SYS_PC_GET (*(uint32*)(*sp + 4))


 
变量初始化
是填成全" E" (0x1110),而不是全0
 
 
字节序

字节序和处理器有关,小字节序就是高位字节存储于内存的高位地址,低字节存储于内存的低位地址处,甚至连比特位都是如此。大字节序正好相反。基于intel处理器的PC使用的是小字节序(LITTLE ENDIAN),嵌入式处理器多使用大字节序。 

 

LR与堆栈

LR与IP处于同一个函数的情况:f1()调用f2()时,将LR置为f1()中调用f2()之后的那条指令,从f2()返回f1()后,则LR与IP都处在f1()中。注意:这种情况肯定发生在有子函数调用的函数,发生异常时IP>LR。
 

f1()调用f2()时,如果f2()中还会调用其他函数f3(),则编译器会在f2()入口生成代码将LR(f1()中调用f2()之后的指令地址)写入f1()的堆栈,如果f2()不调用任何函数,则不会生成相应代码。

 

Vx的几大优势和特点

1、可裁减的微内核结构

2、微内核系统的内存管理运行在用户态,而非内核态,低优先级任务在内存分配过程中可被高优先级任务抢占,不会影响实时性。

3、内核无对应的任务和上下文。

4、每个任务的上下文中都保存切出前的errno值并在切入时恢复,相当于每个任务有一个独立的errno变量。

5、为快速响应中断,ISR运行在特定的空间,不同于其他任何任务,因此中断处理没有任务的上下文切换。

6、实时系统的设计目的不是追求大吞吐量,而是响应的及时性。我们希望系统始终以50微秒的延时处理一个事件,而不是有时20微秒有时100微秒。

 

process / thread / task

在很多场合两者概念可互换,process多见于桌面操作系统,每个进程间有内存保护;

task多见于嵌入式系统,task间无内存保护,可操作同一块全局存储区,这在进程间是不可能的,进程间可通过消息队列来通信。

thread可称为轻量进程,同一进程内的不同线程,可以共享该进程内的同一存储区。

在嵌入式系统中,可以认为各任务就是运行在系统唯一一个进程中的不同线程。

 

大多数嵌入式系统都采用基于优先级抢占的任务调度方式。juniper的系统采用的是不可抢占的方式。

 

驱动接收报文有两种方式:

poll(询问):相对低效,定期查询设备有没有报文收到。

ISR(中断服务程序):高效,但是每收到报文都有中断产生,流量大时,容易造成系统过载。

 

驱动发送报文时,需要在发送完成后,释放buffer。发送完成通知方式也是poll和ISR两种。

一般发送成功由poll通知,发送出错由ISR通知,driver需要对设备进行reset。

 

shell

tornado shell中,

?shConfig SH_GET_TASK_IO off

可以将printf输出到目标机

?shConfig SH_GET_TASK_IO on

输出到windshell本身

 

 
 
vxWorks中对时间的精确统计
 

我查了一下,好多网友也给出了不少关于获得毫秒级时间的方法和建议,粘贴如下, 

供大家参考: 

帖1:  

如果支持Timestamp,BSP应提供以下函数 
sysTimestampConnect()   -   连接时间戳中断 
sysTimestampEnable()   -   使能时间戳 
sysTimestampDisable()   -   禁止时间戳 
sysTimestampFreq()   -   取得时间戳的频率 
sysTimestampPeriod()   -   取得时间戳周期 
sysTimestamp()     -   取得时间戳 
sysTimestampLock()   -   禁止中断,取得时间戳 
sysTimestampInt()     -   可选的时间戳ISR 

帖2:  
时间戳就是一个高精度的时钟吧?由于精度高,记录时间的这个变量变化的很快,所以他很快就会溢出,重新从0开始计数,我有时候用它来计算某个函数的运行时间。 

time1,time2,freq; 

freq=systimestampFreq(); 

time1=sysTimestamp(); 

myFunc(); 

time2=sysTimestamp(); 

(time2-time1)/freq大概就是时间了。 

但是,这有一个条件,就是myFunc()运行的很快,用tickGet()难以计算的情况。否则,可能当time2获取值的时候,时间戳都已经溢出了好几次了。 

就算是这样,也不定就成功,可能当得到time1的时候,变量已经要溢出,等得到time2的时候,得到是是一个很小的值,结果,time2-time1就是负值了。 

总之,利用它,在某些情况下,还是可以做一些估算的。 

帖3:  
vxWorks下的tick和timestamp没有什么相关性。也不是你说的秒和分的关系。 

tick 其实可以看成内核调度的频率,也是是时间片、watchdog超时、任务延时的单位,所以是system   clock。timestamp能够得到高精度的计时,跟RTOS调度没什么关系。比如在某个时候读寄存器的计数为A,过一段时间后再读为B,主频为f。 那么B和A之间的时间距离就是:T   =   (B-A)*f。(假设用做timestamp的timer没有rollover)对应到硬件上,tick只要timer能够产生periodic中断就 行,用做timestamp的timer要求多一点点。 

贴4

要获取精确的毫秒的时间间隔,而且频繁的调用又不导致系统CPU占用率过高。 
我建议采取   通过   CPU   机器周期的方法解决。 

基本上大部分主流CPU都一个64位寄存器用来记录CPU上电后的   机器周期个数。 
你可以编写一个汇编函数获取这个   64位计数。 

然后你在程序开工时,作一个10秒的定时,在定时前后各获取一次CPU   机器周期。 
然后相减,就可以得到每秒钟的CPU   机器周期, 
这个数字除以1000就是每毫秒的CPU   机器周期。 
这个值可以在运行中作为常量,使用我们将之命名位   毫秒因子 

然后你在上一个次执行时取一下上一个次执行和下一次执行, 
下一次执行时再取一次上一个次执行和下一次执行。 
两次相减得到   间隔的CPU   机器周期   。然后利用上面毫秒因子换算成毫秒就可以了。、 

利用这种方法你就是想精确到   纳秒   也是可以的。 

我们经常用这个方法来测量   一段代码的准确执行时间。

 

VxWorks 任务调度

Vx有没有空任务?

原贴地址:http://topic.csdn.net/u/20070207/16/8da9259a-65b8-4856-8e48-761ad1dd00fa.html

 搂主有条件可以看看 vxworks 的内核代码 
分析reschedule  函数你可以看到 
在这个里面有一个while死循环,读ready队列 
如果ready队列为空,就在这里一直while死循环的读ready队列 

所以空跑Vxworks的话,是没有IDLE任务 
---  这跟多任务分时系统WIN32 LINUX是不一样的,这种操作系统boot以后有个init任务,会起idle任务 
在linux内核代码中你可以看到的:) 

但是由于使用Vxworks的大多都填了root函数,Vxworks启动后根据配置文件会调用这个函数 
这个root函数里面,大多数人的处理都是起了一个优先级255的for死循环 

所以,在加入root后的Vxworks(这个就不是仅仅只有一个Vxworks的kernel了)是有一个idle任务 
永久性的在ready队列里面 
导致reschedule里面的while总是可以读到一个ready态的任务 

还有什么不明白的,建议看代码,如果看不到,欢迎交流 :)

VxWorks bootrom 问题集锦

在工控机上安装VxWorks

参考: http://topic.csdn.net/u/20080401/14/de5763c1-859a-423b-b2f1-3b0ab40ff39a.html

我安装了Tornado 2.2,拷贝了pcPentium的bsp,修改了CONFIG.H, 里的一段, 

fei(0,0)host:vxWorks h=192.168.0.125 e=192.168.0.129 u=target pw=pass f=0x08 tn=VxTarget 

, 然后在工控机上用PQ分了1个100M FAT 的空间(没有软区),激活了,然后在Tornado里面生成了BOOTROM.BIN,用优盘拷贝到工控机C盘里,包括MKBOOT.BAT 等文件,最后执行 MKBOOT C: BOOTROOM.BIN ,然后查看C盘下,生成了BOOTROM.SYS文件,然后重新启动.到了出现很多++++++++后,计算机又自动重启动,然后有是++++++++, 连蓝屏都没有出现  怎么办?非常郁闷.我刚刚接触VXWORKS,所以请各位大虾帮助我! 

值得注意的是,我把相同的BSP拷贝另外一台德国控创的845芯片组工控机上就没有问题.而且研华技术支持不对VXWORKS进行帮助!!!多谢了了!!

chkdsk一下c盘里的bootrom.sys,看看是不是连续的。怀疑是bootrom不连续引起的。 
最好将bootrom.bin及其他mkboot.bat vxsys.com文件copy到其他盘,比如D盘,然后将C盘格式化一下,然后在D盘下 
d:> lock C:          
d:> mkboot c: bootrom.bin

在U盘上安装VxWorks

参考:http://topic.csdn.net/u/20080408/17/f30ab394-5631-49f7-94f7-80bb7ab32094.html

temp

参考: http://topic.csdn.net/u/20080102/11/8a6f69a0-107f-4425-a8ca-71b73425d941.html

启动压缩VxWorks

参考:http://topic.csdn.net/u/20071125/21/734b5422-05f8-4248-9c2f-44664b353f50.html

将符号表去掉了在压缩。 工具链中的objcopy或者strip都可以做到的。而且你的工程文件中有这样的选项的,要不要符号表。

vxworks_rom.hex只是基本型,你可以用vxworks_romcompress.hex型啊,这才是压缩型。

看看romstart函数就知道了。

用rar或者zip压缩,从flash加到内存时解压就可以了,这是经典用法。

前提是你bsp已经没问题了,解压缩的过程只要几个关键的符号没错就没问题,BSP不需要做太大改动吧~~~.hex的我没用过就不知道了(vxWorks_romCompress.bin 和  vxWorks_romCompress.hex的区别?)

VxWorks 中断处理

中断程序不需要返回值

链接:http://topic.csdn.net/u/20071005/17/f7911eea-7b71-4830-bdd1-7f7ae4007c79.html

中断处理的压栈对象依赖于MCU的实现,某些MCU支持一个单独的中断堆栈,在这种情况下自然压入专门的中断堆栈,而一些MCU不支持单独的中断堆栈,OS会相应的将中断堆栈实现在被中断任务的堆栈中,则可以认为是压入被中断任务的堆栈。

返回值的问题,用全局变量的方法来解决的。不过要注意除了该中断外,只能有一个地方去访问该全局变量,最好加个判断什么的,容易出现问题。例如碰到更高优先级的中断什么的,全局的变量的值不好控制。

 

VxWorks 串口通信

为什么select阻塞通信任务后,任务就不能恢复了?

参考:http://topic.csdn.net/u/20080112/13/279e79c4-179c-42bf-a0e9-4eb96faae46a.html

select函数在设备读(或写)操作未就绪时应该处于阻塞状态,也就是说你的进程在串口没有收到数据时会处于挂起状态,一旦select监测到有数据可读(或可写如),进程就会转为运行态,继续执行。

可以专门启动一个任务直接对串口read好了,将获取的数据往一个消息队列里放,然后其他任务从消息队列里读就好了(或者将这个过程封装成读函数就更好了),消息队列反正是有timeout功能的了。这样就能实现想要的功能而不用select了。

VxWorks Shell 相关问题

shell的printf和函数执行

原文链接:http://topic.csdn.net/u/20080312/22/37b408d1-123b-4fed-8776-ade8adecc14d.html

Q1 . 我编译的VXWORKS内核是包含了target shell组件和一个host与target符号表同步的组件的,在TORNADO编好程序后download到虚拟机中,为什么在tornado的命令 行下能运行程序中的函数,而在虚拟机中的vxworks命令行下运行同样的函数却提示undefined symbol? 

A1 : Tornado操作界面->Tools->Target server->Configure... 

此处配置target server时,Target server property对应的下拉框中 
Core file and symbol system选项下 
有个Synchronize Target/Host Symbol Table需要勾上 
不推荐同步主机和目标机的符号表,貌似有问题 

Q2 . 在tornado的命令行下执行某个函数时,为什么有的包含printf语句的函数会打印在tornado的命令行下,而有的函数会打印在虚拟机中的vxworks中?我看不出它们的区别在哪.让printf打印在哪里靠什么控制?

A2 : 如果没有重定向的话,printf都是打印到target shell下,即你说的虚拟机上的 

printf语句都是打印到标准输出,看你定向到哪个位置就打印到哪个位置了

A2.1 : host shell下执行某一个函数的时候,WDB会自动生成一个新的任务来运行,这个任务的IO将被重定向到host shell上。这样,你在host shell下敲某一个函数的时候,printf的内容就直接打到host shell上了。 
假设这个函数里有生成新的任务的代码,这样里面生成的任务还是独立的,printf默认就打到标准IO,即界面上去了。 
如果在host shell下,你调用的是-> sp 函数, 这样你会发现全都打标准IO上去了。

A2.2 :
输出到目标 ->?shConfig SH_GET_TASK_IO off 

输出到windshell ->?shConfig SH_GET_TASK_IO on

VxWorks 内存管理

一个悬而未决的内存问题

参考:http://topic.csdn.net/u/20080331/23/3cfde4bd-1adb-4416-b8d3-087c382175ea.html

malloc(1024*1024*10)正确 
malloc(1024*1024*5)或malloc(1024*1024*6)反而出错? 

vxworks(disable MMU)程序运行到malloc(1024*1024*5)时,出错: 
machine check 
program counter:  0x793360 
machine status:  0x4b000 
8286f4  vxTaskEntry    +60 : 324ec ([]) 
722f88  wBufferMemInit+40 : malloc ([]) 
793444  malloc        +1c : memPartAlloc ([]) 
792e34  memPartAlloc  +6c : memPartAlignedAlloc ([]) 
792c5c  memPartAlignedAlloc+19c: 7932a4 ([]) 
改为malloc(1024*500)以内,正确! 
改为malloc(1024*1024*10),也正确! 
改为malloc(1024*1024*6),出错! 

VxWorks的malloc和free会导致内存碎片,推荐自己做内存管理。

猜你喜欢

转载自www.cnblogs.com/realplay/p/9648814.html