s3c2440上ucos-ii下lwip移植成功

转自:http://826891.blog.163.com/blog/static/8637693201032610528236/?fromdm&fromSearch&isFromSearchEngine=yes

今天成功移植LwIP(轻型协议栈)1.2.0S3C2440下的ucos-ii操作系统下,上位机能够ping通了。

移植过程及此过程中遇到的一些问题,记录下来如下:

1.      首先参考了焦海波的 uC/OS-II平台下的LwIP移植笔记”,在此表示感谢!粗略看了一遍文章后,开始动手移植,深吸一口气(关键不知道之后会遇到什么样的问题,做好心理准备哈),接下来就按照文章中所说的来做,很好很详细。

2.      完成操作系统模拟层。

3.      完成LwIP的接口。--这才是实际需要我们完成的工作。

a)        网卡初始化工作              --NetNIC_Init()里边调用了网卡初始化子程序CS8900_Init()(à根据个人的所用网卡不同而异了,我用的是CS8900A)

b)        数据包接收子函数   --NetNIC_RxPkt(…)

c)        数据包接收子函数   --NetNIC_TxPkt(…)

d)        中断处理函数           --NetNIC_ISR_Handler(),一般情况下我们需要开启网卡芯片的中断来实现快速响应,因此需要编写中断处理子函数,并将其赋给相应的中断向量。

此函数主要功能是判断中断的类型,并作相应的处理(或发送标志位或直接处理就需要看个人爱好和系统需求了)

最主要的几个和LwIP接口相关的函数就是这几个了,当然还有许多比较基础的函数,针对芯片寄存器操作的比如说普通寄存器操作函数、页面寄存器操作函数。针对芯片操作的比如说芯片检测函数、复位函数等。

       接下来的工作就是调试了,我调试过程中遇到了几个问题,问题不算太大,但很要命。

1.      外部中断的问题。

这里指的是CPU的中断设置问题。我用到是s3c2440CS8900AIRQ10接到了EINT9GPG1)脚上。看了2440中断部分的设置之后,管脚设置为中断监听模式,也开启了外部中断EINT8~23中断,高电平触发也设置了,中断向量也设置好了,但就是进不了中断。用万用表量了CS98900A的中断脚也是有的(发生中断为高电平),后来仔细看GPIO口的说明文档部分才发现还有两个寄存器是用来专门设置外部中断相关的,一个是外部中断屏蔽寄存器(External Interrupt Mask Register)管理是否打开相应的外部中断,另一个是外部中断触发寄存器(External Interrupt Pending Register)用来登记中断源并清除中断源。EINTMASH寄存器默认情况下屏蔽所有中断,所以我的程序进入不了中断服务子程序。找到原因了,打开中断,在中断服务子程序中清除EINTPEND对应的位就可以了。需要注意的是不仅仅要清除INTPND寄存器的对应标志位(EINT8to23—bit5)也要清除EINTPEND寄存器的对应标志位(EINT9—bit9)否则程序会在ISR里边一直运行跑不出来,这里只针对s3c2440,别的处理器我不知道

2.      中断问题解决了,接着调试发现程序会跑飞,只好慢慢一步一步来。

后来发现原来ADS1.2编译的时候在给一个两字节的变量分配空间的时候分配错了,典型的编译器错误(我感觉是,正常情况不应该出现这样的问题)。按照ARM中的字节对齐机理,两个字节的变量所在地址空间值应该是偶数值,而这里ADS给我分配到了一个基数开始的地址空间,很郁闷。而这个变量正好是用来保存返回值信息的变量,因此我只好将变量直接返回而不向子函数传递此地址空间了,程序运行正常了但是,还是没有ping通。

3.      这个问题是野指针惹的祸,嗨,又遇到野指针了!

现象:明明在等待接收数据的信号量到来的信号呢,信号量还没发,等待的语句居然跑过去了。单步运行,发现没有数据包来的时候等待信号量是成功(线程阻塞了)的,只要有一个数据包发送过来,便不能成功等待信号量了。

每次当上位机发送数据的时候,下位机跑到底层接收数据函数里边去之后,等待接收数据信号量NIC_RxCptSignalPtr的类型值就变了,百思不得其解,底层接收数据的函数里边根本没有对次信号量进行操作啊。后来单步跟踪发现在改变一个指针变量的值时,意外的修改了信号量NIC_RxCptSignalPtr的类型。才发现,这个指针变量原来没有初始化就对其操作了。

修改之后,上位机能收到arp报文了,ICMP报文还是没有回应,革命尚未成功,同志尚需努力啊!

4.      典型的数组越界(算是变异的野指针吧)

这个问题就要说到“uC/OS-II平台下的LwIP移植笔记”了。此笔记的25页中初始化sys_timeouts数组的部分有一句for( i = 0; i < sizeof(__staSysTimeouts); i++ )此处sizeof(__staSysTimeouts)是想得到__staSysTimeouts数组元素的个数,而实际上这个数组的大小通过这种方式是不能得到的。找到此数组的生命的地方

//*sys_timeouts数组,用于保存链表timeouts的首地址。

static struct sys_timeouts __staSysTimeouts[T_LWIP_THREAD_MAX_NB + 1];

直接将sizeof(*)换成T_LWIP_THREAD_MAX_NB + 1应该就没啥问题了

或者另一种得到数组元素个数的方式sizeof(__staSysTimeouts)/sizeof(__staSysTimeouts[0])也是可以的。

再说为什么ICMP报文没有回应的问题,因为系统中接收到ICMP报文后,会将消息投递到消息邮箱,而LwIP负责接受此消息。而消息邮箱为一个全局变量mbox,调试过程发现,mbox 的地址空间内容因为上边的这个数组下表越界而改变了,导致消息投递也出现了问题。

修改之后,ICMP报文有回应了,也ping通了。

       由此我想到了编译器的问题,如果编译器好的话sizeof(__staSysTimeouts)应该被编译成一个常量,这个常量的值超出了数组的大小,应该报错啊。为什么没有?可能两个方面的问题:1.sizeof(…)是在运行中给出的结果,故没有检查数组下标越界。2.编译器根本就不对数组下表越界进行限定。

       果然将T_LWIP_THREAD_MAX_NB + 1改为T_LWIP_THREAD_MAX_NB + 2时编译也通过了,尝试着改变编译优化选项编译也通过了,原来是编译器根本就不对数组下表越界进行界定。

你可能感兴趣的:(linux_socket编程,嵌入式)