原创 在RTOS上移植uIP TCP/IP协议栈

2010-11-18 21:01 5433 10 15 分类: MCU/ 嵌入式

RT-Thread是国人(ffxz)写的一个实时性(RTOS)嵌入式操作系统。和著名的uCOS-II系统相似,但又很不一样!二者都是以抢占式任务调度的。但RT-Thread初次之外还可以以时间片轮转算法进行任务调度的。这在uCOS-II中是没有的,更具有特色的是RT-Thread采用的一种面向对象的编程思想。这是一种巧妙而有趣的编程方法,更接近于人类对事物的认知本性。


内核对象模型:


RT-Thread的内核对象模型是一种非常有趣的面向对象实现方式。由于C语言更为面向系统底层,操作系统核心通常都是采用C语言和汇编语言混合编写而成。C语言作为一门高级计算编程语言,一般被认为是一种面向过程的编程语言:程序员按照特定的方式把要处理事物的过程一级级分解成一个个子过程。


面向对象源于人类对世界的认知多偏向于类别模式,根据世界中不同物品的特性分门别类的组织在一起抽象并归纳,形成各个类别的自有属性。在计算机领域一般采用一门新的,具备面向对象特征的编程语言实现面向对象的设计,例如常见的编程语言C++,Java,Python等。那么RTThread既然有意引入对象系统,为什么不直接采用C++来实现? 这个需要从C++的实现说起,用过C++的开发人员都知道,C++的对象系统中会引入很多未知的东西,例如虚拟重载表,命名粉碎,模板展开等。对于一个需要精确控制的系统,这不是一个很好的方式,假于它人之手不如握入己手!面向对象有它非常优越的地方,取其精华(即面向对象思想,面向对象设计),也就是RT-Thread内核对象模型的来源。RT-Thread实时操作系统中包含一个小型的,非常紧凑的对象系统,这个对象系统完全采用C语言实现。在了解RT-Thread内部或采用RT-Thread编程时有必要先熟悉它,它是RT-Thread实现的基础。


到目前为止,RT-Thread还算是一个年轻的系统吧。但RT-Thread可以称得上优秀的,RT-Thread的团队也是一支优秀的团队。看看RT-Thread的简介吧:


RT-Thread的基本构架:


A.      实时内核


B.      虚拟文件系统


C.      轻型IP协议栈


D.     Shell系统


E.      图形界面(GUI)



f5315980-a09d-482c-9666-f2aea73e695b.jpg


出色的Shell系统:


RT-Thread的shell系统——FinSH,提供了一套供用户在命令行操作的接口,可以用于调试、查看系统信息。由于系统程序大多数采用C语言来编写,FinSH命令行的设计被设计成类似C语言表达式的风格:它能够解析执行大部分C语言的表达式,也能够使用类似于C语言的函数调用方式(或函数指针方式)访问系统中的函数及全局变量。


 


OK,先介绍到这了,关于RT-Thread,更多可以关注其官方网站: http://www.Rt-Thread.org


虽然官方的RT-Thread是和LwIP结合的,但考虑到移植一个LwIP,相比之下要消耗更多的RAM(>30K)和CODE(>80K),对于很多嵌入式MCU应用而言,是很残酷的。所以这次打算把uIP移植到RT-Thread,而且只用内核部分,这样估计10K以下(或者会更少)的RAM空间和20K左右的Code空间即可了。


软件平台:


RT-Thread + uIP1.0


硬件平台:


深蓝DevBoard(STM32F107RC)


首先要搭建RT-thread 平台。这个就用官方的就好了。移植的思路大体如下:


平台搭建成功之后,关键的以太网初始化代码:


/* Reset ETHERNET on AHB Bus */


  ETH_DeInit();


 


  /* Software reset */


  ETH_SoftwareReset();


 


  /* Wait for software reset */


  while(ETH_GetSoftwareResetStatus()==SET);


 


  /* ETHERNET Configuration ------------------------------------------------------*/


  /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */


  ETH_StructInit(&ETH_InitStructure);


 


  /* Fill ETH_InitStructure parametrs */


  /*------------------------   MAC   -----------------------------------*/


  ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable  ; 


  //ETH_InitStructure.ETH_Speed = ETH_Speed_100M;                                     


  ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;             


  //ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;                                                                                  


  ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;                                                                                 


  ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;                                                                                                                                                                       


  ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Enable;                                                                                                      


  ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Disable;     


  ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;                                                            


  ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;     


  ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;                       


  /* Configure ETHERNET */


  ETH_Init(&ETH_InitStructure, PHY_ADDRESS);


 


  /* Initialize Tx Descriptors list: Chain Mode */


  ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);


  /* Initialize Rx Descriptors list: Chain Mode  */


  ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);


  /* Enable DMA Receive interrupt (need to enable in this case Normal interrupt) */


  ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);


  /* Enable MAC and DMA transmission and reception */


  ETH_Start();


 


然后在以太网中断服务程序中采用邮箱的机制,即建立一个邮箱,当有以太网数据来的时候,通知相应的收邮件线程:


     rt_mb_send(&eth_rx_thread_mb,0);


这样系统中再建立一个收邮件线程:


void eth_rx_thread_entry(void* pr)


{


    int i;


    struct eth_device* device;


    struct timer periodic_timer, arp_timer;


    while(1) {


      if (rt_mb_recv(&eth_rx_thread_mb, (rt_uint32_t*)&device, RT_WAITING_FOREVER) == RT_EOK)


      {


         uip_len = ETH_HandleRxPkt(uip_buf);


         if(uip_len > 0) {


      if(BUF->type == htons(UIP_ETHTYPE_IP)) { //IP包,缓冲地址为[12][13]=0x0800


       uip_arp_ipin();


       uip_input();


       /* If the above function invocation resulted in data that


          should be sent out on the network, the global variable


          uip_len is set to a value > 0. */


       if(uip_len > 0) {


         uip_arp_out();


         TransmitPacket();


       }


      } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {//ARP包


       uip_arp_arpin();


       /* If the above function invocation resulted in data that


          should be sent out on the network, the global variable


          uip_len is set to a value > 0. */


       if(uip_len > 0) {


         TransmitPacket();


       }


      }


 


    } else if(timer_expired(&periodic_timer)) {//5s


      timer_reset(&periodic_timer);


      for(i = 0; i < UIP_CONNS; i++) {


       uip_periodic(i);


       /* If the above function invocation resulted in data that


          should be sent out on the network, the global variable


          uip_len is set to a value > 0. */


       if(uip_len > 0) {


         uip_arp_out();


         TransmitPacket();


       }


      }


 


#if UIP_UDP


      for(i = 0; i < UIP_UDP_CONNS; i++) {


       uip_udp_periodic(i);


       /* If the above function invocation resulted in data that


          should be sent out on the network, the global variable


          uip_len is set to a value > 0. */


       if(uip_len > 0) {


         uip_arp_out();


         TransmitPacket();


       }


      }


#endif /* UIP_UDP */


     


      /* Call the ARP timer function every 10 seconds. */


      if(timer_expired(&arp_timer)) {


       timer_reset(&arp_timer);


       uip_arp_timer();


      }


    }


      }


  }


}


然后在添加uIP系统应用程序 telnet ,编译成功之后,系统跑起来的结果:


fe0e4080-81d1-4741-bd36-0e7dfb719671.jpg


工程包源码:



 

文章评论5条评论)

登录后参与讨论

用户619110 2016-2-17 16:36

很好的资源,很好很强大,谢谢

用户546788 2014-7-15 13:31

来学习一下!

用户417603 2012-4-12 22:49

能加下您的qq吗 我是个小菜鸟,求指教!!!!

用户417603 2012-4-12 22:47

这个工程貌似缺少main函数 编译出现很多错误 请指教下

xucun915_925777961 2010-11-19 15:48

来学习一下!
相关推荐阅读
用户1369714 2012-04-12 12:34
大家好,我是itspy,关于这个博客,请大家看过来!
大家好,我是itspy,关于这个博客...,很失望,以后不会用了 如果大家有什么问题,请到我的另一个博客去留言吧 我也很希望跟大家做交流,有什么技术问题,itspy会很乐意帮助的,新博客欢...
用户1369714 2011-08-07 14:35
uip 移植在rt-thread上的源码
*/本人在以前开发过程中移植uIP到RT-Thread实时线程系统,有需要用到项目中的朋友可以参考一下。 附件是源码包,在以太网驱动采用DM9000,驱动程序和移植文件uipif.c在源码包下(rt...
用户1369714 2011-01-13 10:32
Linux内核的社会视角--Mr. Process的一生
         Linux内核是一个无比复杂的系统,要想看清大致的脉络也非易事。其实,可以把运行中的Linux想像成一个人类的社会,当中的进程就是社会中的人。人有生老病死,进程有创建、异常、终止。人...
用户1369714 2011-01-08 12:39
RT-Thread Radio 网络播放器--初次零距离接触!
      今天很高兴, 收到了RT-Thread Radio套件,还有ffx和RT-Thread工作室写的新书《RT-Thread 实时操作系统 编程指南》。 如此令人快乐的事,如此高兴,实在是想不...
用户1369714 2011-01-05 15:43
如何编写linux的驱动程序
如何编写Linux的驱动程序编写linux驱动程序,应该是一件得心应手的事,因为linux是开源的,从上往下或从下往上,一切都是那么的光明磊落的呈现于眼前。只要你愿意,你可随意了解你所想知道的东西。L...
用户1369714 2010-12-28 10:12
Busybox制作Linux根文件系统
Busybox ——嵌入式Linux中的瑞士军刀利用busybox-1.13.0制作linux根文件系统(yaffs2)源码下载:http://www.busybox.net/downloads/操作...
我要评论
5
10
关闭 站长推荐上一条 /2 下一条