uC/OSⅡ下协议栈uIP的移植与应用
- 格式:pdf
- 大小:279.87 KB
- 文档页数:4
uC/OS-II是源码开放、可固化、可移植、可裁剪、可剥夺的实时多任务OS 内核,适用于任务多、对实时性要求较高的场合。
uC/OS-II适合小型系统,具有执行效率高、占用空间小、实时性优良和可扩展性等特点,最小内核可编译至2K。
uC/OS-II内核提供任务调度与管理、时间管理、任务间同步与通信、内存管理和中断服务等功能。
所谓RTOS移植,就是使一个实时内核能在某个微处理器或微控制器上运行。
大部分的uC/OS-II代码试用C写的,但仍需要用C和ASM写一些与处理器相关的代码,这是因为uC/OS-II在读写处理器寄存器时只能通过ASM实现。
要是uC/OS-II正常运行,处理器必须满足一定的条件:处理器的C编译器能产生可重入代码;用C语言就可以打开和关闭中断;处理器支持中断,并能产生定时中断;处理器支持能够容纳一定量数据的硬件堆栈;处理器有将SP和其他CPU reg读出和存储到堆栈或内存中的指令;uC/OS-II移植工作主要包括以下三个方面的内容:(1)修改与处理器核编译器相关的代码:主要在includes.h中,修改数据类型定义说明,OS_ENTER_CRITICAL()、OS_EXIT_CRITICAL()和堆栈增长方向定义OS_STK_GROWTH。
(2)用C语言编写10个移植相关的函数:主要在OS_CPU_C.C中,包括堆栈初始化OSTaskStkInit()和各种回调函数。
(3)编写4个汇编语言函数:主要在OS_CPU_A.ASM中,包括:_OSTickISR //时钟中断处理函数_OSIntCtxSW //从ISR中调用的任务切换函数_OSCtxSW //从任务中调用的任务切换函数_OSStartHighRdy //启动最高优先级的任务uC/OS-II移植的关键问题:(1)临界区访问:uC/OS-II需要先禁止中断再访问代码临界段,并且在访问完毕后重新允许中断,这就使得uC/OS-II能够保护临界段代码免受多任务或ISR的破坏。
uip应用介绍一个适用于8/16位单片机的嵌入式TCP/IP协议栈(uIP)在发电机远程监测系统中的应用。
重点阐述uIP的功能特性、体系结构和相关接口,并详细介绍如何在该协议栈上实现一个嵌入式Web服务器。
目前uIP已成功地移植到51单片机上。
目前,随着互联网的发展,越来越多的工业测控设备已经将网络接入功能作为其默认配置,以实现设备的远程监控和信息分布式处理。
笔者曾参与某发电机射频监测仪的开发,该设备主要用于诊断和预警发电机早期故障,并通过RS232接口定时输出电平和状态数据,现场专门设一台PC作接收、显示及存储。
每年都要有专家到各发电厂对以往数据作检查和诊断,不胜其烦。
因此有必要设计一个RS232到Internet的数据传输模块,以便对发电机的运行状况作远程监测。
设计该模块的关键在于如何实现一个嵌入式TCP/IP协议栈,根据以往的经验,自己设计一个协议栈的难度很可能超过应用本身,而采用商业的协议栈似乎又无必要(功能过于复杂),最后笔者选用一种功能简易的免费TCP/IP协议栈uIP 0.9作为设计核心。
1 、嵌入式TCP/IP协议栈目前,市场上几乎所有的嵌入式TCP/IP协议栈都是根据BSD版的TCP/IP协议栈改写的。
在商业嵌入式TCP/IP协议栈大都相当昂贵的情况下,很多人转而使用一些源代码公开的免费协议栈,并加以改造应用。
目前较为著名的免费协议栈有:lwIP(Light weight TCP/IP Stack)——支持的协议比较完整,一般需要多任务环境支持,代码占用ROM>40KB,不适合8位机系统,没有完整的应用文档;uC/IP(TCP/IP stack for uC/OS)—基于uC/OS的任务管理,接口较复杂,没有说明文档。
笔者采用的协议栈系瑞典计算机科学研究所Adam Dunkels开发的uIP0.9。
其功能特性总结如下:完整的说明文档和公开的源代码(全部用C语言编写,并附有详细注释);极少的代码占用量和RAM资源要求,尤其适用于8/16位单片机(见表1);高度可配置性,以适应不同资源条件和应用场合;支持ARP、IP、ICMP、TCP、UDP(可选)等必要的功能特性;支持多个主动连接和被动连接并发,支持连接的动态分配和释放;简易的应用层接口和设备驱动层接口;完善的示例程序和应用协议实现范例。
uIP协议栈分析uIP特性uIP协议栈往掉了完整的TCP/IP中不常用的功能,简化了通讯流程,但保存了网络通讯必须使用的协议,设计重点放在了IP/TCP/ICMP/UDP/ARP这些网络层和传输层协议上,保证了其代码的通用性和结构的稳定性。
由于uIP协议栈专门为嵌进式系统而设计,因此还具有如下优越功能:(1)代码非常少,其协议栈代码不到6K,很方便阅读和移植。
(2)占用的内存数非常少,RAM占用仅几百字节。
(3)其硬件处理层、协议栈层和应用层共用一个全局缓存区,不存在数据的拷贝,且发送和接收都是依靠这个缓存区,极大的节省空间和时间。
(4)支持多个主动连接和被动连接并发。
(5)其源代码中提供一套实例程序:web服务器,web客户端,电子邮件发送程序(SMTP 客户端),Telnet服务器,DNS主机名解析程序等。
通用性强,移植起来基本不用修改就可以通过。
(6)对数据的处理采用轮循机制,不需要操纵系统的支持。
由于uIP对资源的需求少和移植轻易,大部分的8位微控制器都使用过uIP协议栈, 而且很多的著名的嵌进式产品和项目(如卫星,Cisco路由器,无线传感器网络)中都在使用uIP协议栈。
uIP架构uIP相当于一个代码库,通过一系列的函数实现与底层硬件和高层应用程序的通讯,对于整个系统来说它内部的协议组是透明的,从而增加了协议的通用性。
uIP协议栈与系统底层和高层应用之间的关系如图2-1所示。
从上图可以看出,uIP协议栈主要提供了三个函数供系统底层调用。
即uip_init(), uip_input() 和uip_periodic()。
其与应用程序的主要接口是UIP_APPCALL( )。
uip_init()是系统初始化时调用的,主要初始化协议栈的侦听端口和默认所有连接是封闭的。
当网卡驱动收到一个输进包时,将放进全局缓冲区uip_buf中,包的大小由全局变量uip_len约束。
同时将调用uip_input()函数,这个函数将会根据包首部的协议处理这个包和需要时调用应用程序。
uCOS-II移值过程实例讲解我将uCOS-II 移植到了EPONS 的C33209的平台上,接下来我就基于我移植好的代码讲解如何将uCOS-II从一种MCU移植到另一种MCU。
首先介绍uCOS-II的文件,如下表:ucos_ii.hos_cfg.hos_cpu.hos_core.cos_dbg_r.cos_flag.cos_mbox.cos_mem.cos_mutex.cos_q.cos_sem.cos_task.cos_time.cucos_ii.cos_cpu_c.cos_cpu_a.asm其中我们和硬件平台相关的文件的文件名被加粗了,也就是说若要将uCOS-II移植到新的平台上只要关心以上四个文件就行了。
当然你也可以根据需要再添加你自己的和平台相关的文件,事实上我也是这么做的。
在我移植的例子中就添加了四个和平台相关的文件,文件如下表:crt0.cdrv_rtc.cvector.cext.scrt0.c是用来初始化系统的比如说MCU的一些特殊寄存器、设置外围的总线接口,等。
drv_rtc.c是用来初始化系统中的一个RTC的,这个RTC可以为内核提供必要的基于时间片调度的时基。
同时提供了对RTC开始和停止的操作函数。
在我的例子中RTC会每秒产生32次中断。
vector.c顾名思义,它是系统上电后为系统提供矢量入口表的文件,当然也包括中断向量表。
ext.s是为uc/OS-II 提供OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()函数的具体实现以及在用户程序的中断函数出入时要调用的状态保护和状态恢复函数OS_SA VEALL ()和OS_RESTOREALL ()。
前面两个函数的功能是:OS_ENTER_CRITICAL()屏蔽中断;OS_EXIT_CRITICAL()恢复原来的中断使能状态。
1. os_cpu_a.asm的说明要想顺利的移植首先要了解uCOS-II的一些基本概念。
uC/GUI NIOS II移植及应用笔记这是前些日子在使用uc/GUI的时候即下来的一些东西原来发布在EDACN的bbs上面。
现在不知道沉到哪里去了。
现在把它重新整理发布在这里。
随后在明年过年的时候把后续的几个高级主题整理出来。
下面开始我的笔记!有兴趣的兄弟们可以来看看。
step1.下载uC/GUI的代码。
(废话没有源代码移植个鸟)我下载的时uC/GUI3.32这是能得到的源代码中最全的一个版本。
看看里面都有些什么东西。
由于这里的发间大小的限制的问题不能上传源代码。
很是郁闷。
有需要的同志可以联系我。
Email:william7447@首先看看所有名叫Simulation的东西这是uC/GUI在VC中仿真的VC工程,他的仿真功能非常的实用可以在没有具体硬件的情况下先行开发软件,而丝毫不影响软件的兼容性。
但是有一个问题比较郁闷,就是速度的问题。
大家知道嵌入式系统的CPU运算能力有限,而电脑的cpu.........我的整个项目的gui是在电脑上完成的。
拿到目标系统上面编译.......通过。
经过紧张的下载.....................运行..........显示出了第一个画面,无比的兴奋。
但测试发现极其郁闷而几乎无法解决的问题......目标系统的处理能力只有100mips而我的电脑的cpu是P4 3.0。
速度的差别太大了。
解决这个问题几乎成了我后半段工作的主题。
GUI文件夹存放全部uC/GUI源代码的地方看看它的属性有多达390个文件,全部是.c和.h。
可以看出GUI系统是一个庞大复杂的东西。
我在调试系统的时候跟踪过完整的消息循环再进入了60多个子函数调用后还没有看到希望,就彻底的放弃了跟踪的想法。
下来会具体说明这里面都有些什么东西。
config文件夹uC/GUI的配置文件夹。
里面存放的是uC/GUI的配置头文件。
改动里面的相应的就可以改动uC/GUI的配置。
这个GUI功能十分强大。
一步步移植uCOS-IIandLwIP(四)二、uCOS-II移植嵌入式实时操作系统uCOS-II移植的核心在于任务切换时上下文环境的保存及恢复,针对Cortex-M3内核的单片机,其采用了PendSVHandler中断处理的方式解决这一核心问题。
我们要做的就是在任务切换及中断任务切换过程中开启触发PendSV中断,并在PendSVHandler中实现上下文环境的切换,即保存CPU内部寄存器值和恢复切换任务的相关信息。
为什么要使用PendSV中断实现上下文切换呢?参阅Cortex-M3的一段话。
另一个相关的异常是PendSV(可悬起的系统调用),它和SVC 协同使用。
一方面,SVC异常是必须在执行SVC指令后立即得到响应的(对于SVC异常来说,若因优先级不比当前正处理的高,或是其它原因使之无法立即响应,将上访成硬fault——译者注),应用程序执行SVC时都是希望所需的请求立即得到响应。
另一方面,PendSV则不同,它是可以像普通的中断一样被悬起的(不像SVC那样会上访)。
OS可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作。
悬起PendSV 的方法是:手工往NVIC的PendSV悬起寄存器中写1。
悬起后,如果优先级不够高,则将缓期等待执行。
PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。
例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:- 执行一个系统调用-系统滴答定时器(SYSTICK)中断,(轮转调度中需要)让我们举个简单的例子来辅助理解。
假设有这么一个系统,里面有两个就绪的任务,并且通过SysTick异常启动上下文切换。
如图所示。
上图是两个任务轮转调度的示意图。
但若在产生SysTick 异常时正在响应一个中断,则SysTick异常会抢占其ISR。
在这种情况下,OS 是不能执行上下文切换的,否则将使中断请求被延迟,而且在真实系统中延迟时间还往往不可预知——任何有一丁点实时要求的系统都决不能容忍这种事。
u C/OS-II移植总结RTOS移植牵涉到软件平台—编译器、硬件平台—CPU,移植前需要了解CPU及编译器的一些基本特点。
1、编译器a、堆栈运行原理本次移植的软件平台为CodeVision编译器,它的堆栈由两部分组成:硬件堆栈(HardStack)用来保存中断及函数调用的返回地址,它的大小将影响函数调用嵌套的深度,实际大小应根据中断及函数嵌套的深度来决定,并留有一定的裕度。
硬件堆栈由CPU中的指针SP实现。
软件堆栈(SoftStack)用来分配局部变量及传递参数。
在此次移植中,由CPU中的Y指针模拟实现。
b、堆栈指针所指向的单元是否为可用单元大多数编译器生成的代码,其堆栈指针所指向的单元为可用单元,也就是说在将数据压入堆栈前不用再调整堆栈指针,堆栈指针在上一次使用完后已经调整好了。
前面所说的硬件堆栈(HardStack)即为这种类型。
还有一种堆栈,其指针所指向的单元为不可用单元,在向堆栈压入数据前需调整堆栈指针,软件堆栈(SoftStack)即为这种类型。
软件堆栈设计为这种形式完全是为了适应A VR指令和软件堆栈增长方向与硬件堆栈增长方向相同。
软件堆栈(SoftStack)由Y指针模拟实现,但在A VR的指令集中只有:LD Rd,Y+ LD Rd,–Y ST Y+,Rr ST –Y,Rr要实现向下增长的堆栈就只能使用ST –Y,Rr和LD Rd,Y+。
指针指向的单元已压入数据,因此使用前需调整指针,而ST –Y,Rr正好能完成这个动作。
c、多字节变量在宽度为单字节的存储器中的分配规则多字节变量指定义为int、long int、float、double等类型的变量。
在CodeVision编译器遵循的原则是:变量低字节部分分配在内存的低地址单元,变量高字节部分分配在内存高地址单元。
如:int a a为双字节变量,其低字节保存在内存的0x24H,则高字节保存在内存的0x25H。
了解这些变量在内存中存储形式是为了能够在在线汇编中正确操作它们。
随着集成电路设计与制造技术的发展,FPGA芯片的容量越来越大、性能越来越高,用FPGA构建片上系统成为现实,基于FPGA的嵌入式系统与SOPC(System On a Programmable Chip)设计技术将逐渐成为系统设计的主流技术,正获得越来越广泛地研究。
Microblaze是Xilinx公司一款针对FPGA器件进行了优化设计的软处理器核,有不错的性能且价格低廉,且支持Xilinx全系列的FPGA器件,应该有着广阔的发展前景。
μC/OS-II 是Jean Labrosse先生于1998年推出的一个优秀的开放源码的实时操作系统,具有移植方便、执行效率高、占用空间小、实时性强和可靠性高等优点。
采用μC/OS-II+Microblaze的应用平台对中小嵌入式系统应用来说是十分适合的。
本文基于μC/OS-II在Microblaze上的移植与基于该系统的应用研究,记录移植和使用过程的心得、体会,内容可能会有些零散,希望对有类似应用的朋友有些帮助,也欢迎大家来交流与讨论。
一、主要参考资料①μC/OS-II学习主要参考邵贝贝教授译的《嵌入式实时操作系统μC/OS-II(第2版)》下面是CHINA-PUB的介绍/12618网上也有该书第一版的电子书可以找来学习。
② Micrium公司的Micrium-uCOS-II-V286.ZIP,包括代码与文档,可以从获得。
③ Micrium公司的μC/OS-II and the Xilinx MicroBlaze Processor Application Note可以从获得。
④ Xilinx公司EDK相关文档:/ise/embedded/edk_docs.htm⑤ISE、EDK软件的帮助文档,包括MicroBlaze Processor Reference Guide (mb_ref_guide.pdf)。
⑥ EDK的基本使用可以参考:Xilinx官方的6个EDK实验(中文版).pdf百度文库上有/view/e92e71d184254b35eefd3425.html二、操作系统的配置选项问题在进行Software Platform配置时,一般安装了EDK软件后,操作系统与库设置时可选择的标准选项只有两个:Standalone和Xilkernel。
uCOSii的移植过程详解
C/ OS 是一种多任务实时操作系统。
内核源代码公开、短小精干、可裁剪、执行时间可确定, 可移植性较强, 非常适用于一些中小型嵌入式系统开发。
uC/OS 可以移植到8~ 64 位的不同类型、不同规模的嵌入式系统, 并能在大部分的8 位、16 位、32 位, 甚至64 位的微处理器和DSP上运行[ 1] 。
MCF52235是飞思卡尔公司Co ldf ire 系列32 位单片机解决方案的嵌入式微控制器, 采用的是V2 版本的RISC 内核。
MCF52235 内部有32 KB SRAM 和256 KB FLASH, 并且集成了标准的Coldfire外围设备, 包括三个适合中长距离通信的SCI, 一个I2 C 和一个用于系统内部和外围设备通信的Q SPI。
在60Hz的核心频率下, MCF52235 的处理能力为56 MIPS, 具备较高的性能价格比[ 24] 。
MCF52235 对于移植C/ OS 来说有足够的
RAM 和FLASH, 且有较快的处理速度和较低的成本,所以对于嵌入式应用系统的开发来说, 嵌入C/ OS到MCF52235 微控制器是一个不错的选择。
uC/ OS 的体系结构要实现C/ OS 向MCF52235 的移植, 需要做两方面的工作: 一是重新定义内核的大小和功能; 二是为内核编写与硬件相关的代码。
C/ OS 的文件结构如图1 所示。
可以看到, C/ OS 与CPU 类型无关的C 代码文件COS . C 包括很多文件, 它们是C/ OS 的内核和很多功能函数, 其中前。
一步步移植uCOS-IIandLwIP(三)3、LwIP跑起来在前两小节中,我们详细介绍了lwip移植涉及的核心函数。
至于cc.h、cpu.h、lwipopts.h的中有关数据类型、字节对齐和调试信息的配置,网络资源很丰富,也基本上大同小异,本文就不做介绍。
需要说明的是,前两小节移植借鉴和参阅了网络上许多其他人的成果。
接下来我们要lwip跑起来,先上主程序://Other initiation do not listTimer_Config(); // 10ms interval for lwipLWIP_Init(); //lwip system initwhile(1){LWIP_Pkt_Handle();LWIP_Periodic_Handle(localtime);}各个子程序如下:uint32_t TCPTimer = 0;uint32_t ARPTimer =0;uint32_t DHCPfineTimer =0;uint32_t DHCPcoarseTimer;#define TCP_TMR_INTERVAL 250#define ARP_TMR_INTREVAL 5000#define DHCP_FINE_TIMER_MSECS 500#define DHCP_COARSE_TIMER_MSECS 6000struct netif dm9000if;void LWIP_Init(void){ip_addr_t ipaddr, netmask, gw;lwip_init();IP4_ADDR(&ipaddr,IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR 3);IP4_ADDR(&netmask,NETMASK_ADDR0,NETMASK_ADDR1, NETMASK_ADDR2,NETMASK_ADDR3);IP4_ADDR(&gw,GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_A DDR3);netif_add(&dm9000if,&ipaddr,&netmask,&gw,NULL,etherne tif_init,ethernet_input);netif_set_default(&dm9000if);netif_set_up(&dm9000if);}void LWIP_Pkt_Handle(void){ethernetif_input(&dm9000if); //read data from net interface }/*** @brief LwIP periodic tasks* @param localtime the current LocalTime value* @retval None*/void LWIP_Periodic_Handle( uint32_t localtime){#if LWIP_TCP/* TCP periodic process every 250 ms */if (localtime - TCPTimer >= TCP_TMR_INTERVAL){TCPTimer = localtime;tcp_tmr();}#endif/* ARP periodic process every 5s */if ((localtime - ARPTimer) >= ARP_TMR_INTERVAL){ARPTimer = localtime;etharp_tmr();}#ifdef USE_DHCP/* Fine DHCP periodic process every 500ms */if (localtime - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS) {DHCPfineTimer = localtime;dhcp_fine_tmr();if ((DHCP_state != DHCP_ADDRESS_ASSIGNED) && (DHCP_state != DHCP_TIMEOUT) &&(DHCP_state != DHCP_LINK_DOWN)){/* toggle LED1 to indicate DHCP on-going process */// STM_EVAL_LEDT oggle(LED1);/* process DHCP state machine */LwIP_DHCP_Process_Handle();}}/* DHCP Coarse periodic process every 60s */if (localtime - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS){DHCPcoarseTimer = localtime;dhcp_coarse_tmr();}#endif}LWIP_Init():完成lwip内部初始化及网口的注册;LWIP_Pkt_Handle(void):周期性查询网口是否接收到数据,也可采用中断的方式;LWIP_Periodic_Handle( uint32_t localtime):lwip内核需要周期性调用时间处理函数进行轮询操作,TIMER2提供10ms中断;下载程序后,使用windows的命令行工具ping硬件平台的IP地址,即 ping 192.168.0.10。