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

 

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)



 


出色的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(Ð_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(Ð_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(ð_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(ð_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 ,编译成功之后,系统跑起来的结果:

在RTOS上移植uIP TCP/IP协议栈_第1张图片

 


工程包源码(IAR工程):

 http://bbs.ednchina.com/BLOG_ARTICLE_1917928.HTM

 

你可能感兴趣的:(编程,timer,function,任务调度,语言,NetWork)