基于Nios软核CPU的uCOS-II和LwIP移植
- 格式:doc
- 大小:112.00 KB
- 文档页数:11
1 下载LwIP...................................................................................... (2)2 建立一个最基本的工程......................................................................................... (2)3 把LwIP加入工程......................................................................................... (2)4 编写操作系统模拟层相关代码........................................................................................ . (3)操作系统模拟层移植说明――中文翻译..................................................................................... (3)编写操作系统模拟层.................................................................................... (6)准备工作――建立文件、定义数据类型及其它 (6)信号量操作函数................................................................................ (8)邮箱操作函数................................................................................ (13)实现sys_thread_new()函数................................................................................. (20)实现sys_arch_timeouts()函数................................................................................. (22)实现临界保护函数................................................................................ (25)扫尾――结束操作系统模拟层的编写................................................................................. (26)5 LwIP接口――初始设置及网络驱动........................................................................................ (28)准备工作――建立LwIP入口函数文件..................................................................................... (28)ilvInitLwIP().................................................................... (29)ilvSetLwIP()..................................................................... (30)ethernetif_init()――初始化底层界面..................................................................................... (35)ethernetif_init()函数分析................................................................................. (35)low_level_output()――链路层发送函数 (36)low_level_init()――网卡初始化函数...................................................................................38EMACInit()――网卡初始化工作的实际完成者 (40)ethernetif_input()――实现接收线程...................................................................................47low_level_input()――得到一整帧数据.................................................................................49GetInputPacketLen()――获得帧长................................................................................. (50)EMACReadPacket()――复制,从接收缓冲区到pbuf (53)EMACSendPacket()――发送一帧资料................................................................................. (55)编译――及................................................................................. (56)6 ping――结束LwIP的移植......................................................................................... (57)编译、链接整个工程.................................................................................... (57)ping测试...................................................................................... (59)后记......................................................................................... .. (62)本文将指导读者一步步完成LwIP在开发环境下的移植工作,包括底层驱动的编写。
Ucos_II移植总结:之前已经基本算是成功的移植过ucos-II(内存管理部分没有处理),但是由于可恶的硬盘故障,让我的劳动成果付诸东流。
其间的一些移植经验没有及时总结,现在想来颇有点从头再来的悲壮!鉴于之前的教训,这次,边移植边总结,以防重蹈覆辙。
还好之前的移植过程已经解决了部分棘手的难题,现在复现一下权当是复习一下arm和ucos_II了。
这次的移植还是基于SEP4020芯片,其中的一些引导代码和中断处理代码还是照搬已经写好的代码吧,现在已经没有自己动手写的激情了!下面按照自己的移植步骤一步步总结吧:第一步:创建工程,将基本的启动代码照搬过来,建立一个最小系统,能够在开发板上运行成功。
第二步:将ucos-II源代码copy过来。
第三步:对基本的语法错误进行改正。
对工程进行编译,根据提示进行基本语法的改正。
主要包括:INCLUDES.h中头文件的调用第四步:对需要自己手动编写的函数首先要清空,防止编译报错,然后一步步手动编写代码。
1、临界段代码:os_cpu.h中OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()两个宏重新定义为我们自己写的开关中断函数。
Os_cpu_a.s文件添加如下代码:AREA MCUINIT , CODE, READONLYENTRY;/* 开启IRQ中断*/;voidEnableInterrupt(void);{EXPORT EnableInterruptEnableInterruptmrs r0,CPSRbic r0, r0, #0x80 ;set bit7 to 0msr CPSR_cxsf,r0movpc,lr ;Return to caller;};/* 关闭IRQ中断*/;voidDisableInterrupt(void);{EXPORT DisableInterruptDisableInterruptmrs r0,CPSRorr r0, r0, #0x80 ;set bit7 to 1msr CPSR_cxsf,r0movpc,lr ;Return to caller;}END2、OS_CPU_A.S文件代码编写AREA MCUINIT , CODE, READONLYENTRY;/* 开启IRQ中断*/;voidEnableInterrupt(void);{EXPORT EnableInterruptEnableInterruptmrs r0,CPSRbic r0, r0, #0x80 ;set bit7 to 0msr CPSR_cxsf,r0movpc,lr ;Return to caller;};/* 关闭IRQ中断*/;voidDisableInterrupt(void);{EXPORT DisableInterruptDisableInterruptmrs r0,CPSRorr r0, r0, #0x80 ;set bit7 to 1msr CPSR_cxsf,r0movpc,lr ;Return to caller;};任务切换代码OSCTXSWEXPORT OS_TASK_SW_ARMOS_TASK_SW_ARMSTMFD sp!, {lr} ; save pcSTMFD sp!, {lr} ; save lrMRS r14, SPSRSTMFD sp!, {r14} ; save current PSRSTMFD sp!, {r0-r12} ; save register file and ret address ;; OSPrioCur = OSPrioHighRdyIMPORT OSPrioCurIMPORT OSPrioHighRdyLDR r4, =OSPrioCurLDR r5, =OSPrioHighRdyLDRB r6, [r5]STRB r6, [r4]; Get current task TCB addressIMPORT OSTCBCurLDR r4, =OSTCBCurLDR r5, [r4]STR sp, [r5] ; store sp in preempted taskss TCB; Get highest priority task TCB addressIMPORT OSTCBHighRdyLDR r6, =OSTCBHighRdyLDR r6, [r6]LDR sp, [r6] ; get new tasks stack pointer; OSTCBCur = OSTCBHighRdySTR r6, [r4] ; set new current task TCB address;LDMFD sp!, {r0-r12} ; YYY+LDMFD sp!, {r14} ; YYY+; LDR r14, =0x000000D3MSR CPSR_cxsf, r14 ; YYY+;调试时屏掉此句才会跑的通,待解决LDMFD sp!, {lr,pc} ; YYY+;OS启动时开始运行创建的最高优先级任务; void OSStartHighRdy(void); ; Start the task with the highest priority;;EXPORT OSStartHighRdyOSStartHighRdyIMPORT OSTCBCurIMPORT OSTCBHighRdyIMPORT OSRunningLDR r4, =OSTCBCur ; Get current task TCB addressLDR r5, =OSTCBHighRdy ; Get highest priority task TCB addressLDR r5, [r5] ; get stack pointerLDR sp, [r5] ; switch to the new stackSTR r5, [r4] ; set new current task TCB address;OSRunning = 1 'TURE'LDR r4, =0x01 ; Get current task TCB addressLDR r5, =OSRunning ; Get highest priority task TCB addressSTRB r4, [r5];LDMFD sp!, {r0-r12} ; start the new taskLDMFD sp!, {r14} ; get new state from top of the stackMSR CPSR_cxsf, r14 ; CPSR should be SVC32ModeLDMFD sp!, {lr,pc};中断级任务切换EXPORT OSIntCtxSwOSIntCtxSwIMPORT OSTCBCurIMPORT OSPrioCurIMPORT OSTCBHighRdyIMPORT OSPrioHighRdyIMPORT OSTaskSwHookBL OSTaskSwHook;OSTCBCur = OSTCBHighRdyLDR r4, =OSTCBCurLDR r5, =OSTCBHighRdyLDR r6, [r5]STR r6, [r4];OSPrioCur = OSPrioHighRdyLDR r4, =OSPrioCurLDR r5, =OSPrioHighRdyLDRB r6, [r5]STRB r6, [r4];sp = OSTCBHighRdy->OSTCBStkPtrLDR r6, =OSTCBHighRdyLDR r6, [r6]LDR sp, [r6] ; get new tasks stack pointerLDMFD sp!,{r0, r1};在timedly中断服务程序中,函数开始压栈两个寄存器,为保证堆栈中数据一致,需出栈对齐;resume registersLDMFD sp!, {r0-r12} ; start the new taskLDMFD sp!, {r14} ; get new state from top of the stack; LDR r14, =0x000000D3MSR CPSR_cxsf, r14 ; CPSR SVC32Mode调试时屏掉此句才会跑的通,待解决LDMFD sp!, {lr,pc}END中断服务程序代码IRQ_DOstmfd sp!, {r0,r1}ldr r0, =IRQ_R1str r1, [r0]ldmfd sp!, {r0}ldr r1, =IRQ_R0str r0, [r1] ;保存R0和R1寄存器(因为这两个寄存器再后面要用到)add r13, r13, #4 ;restore the sp_irq top to original irq topsub r14, r14, #4mov r0, r14 ;LR_irq(R14)减4并保存在R0mrs r1, spsrorr r1, r1, #0x80 ;将SPSR_irq的中断屏蔽位置‘1’(屏蔽中断),并保存再R1 中msr cpsr_cxsf, r1 ;将模式切换到中断前的模式;---------------------------------------------------------------------------------------------bic r1, r1, #0x80 ;将原先保存的SPSR_irq的R1的中断屏蔽位清零(允许中断)stmfd sp!, {r0}stmfd sp!, {r14}stmfd sp!, {r1} ;依次将R0,R14,R1的值压入中断前模式下的堆栈(当前R0,R14,R1中存放的分别是LR_irq-4,中断前模式下的LR,SPSR_irq)ldr r0, =IRQ_R1ldr r1, [r0]stmfd sp!, {r1}ldr r1, =IRQ_R0ldr r0, [r1]stmfd sp!, {r0}ldmfd sp!, {r0,r1} ;恢复原先保存的R0和R1stmfd sp!, {r0-r12} ;将r0--r12全部压入中断以前模式下的堆栈;; Get current task TCB addressIMPORT OSTCBCurLDR r4, =OSTCBCur;及时保存当前任务中断,因为可能会进行任务切换LDR r5, [r4]STR sp, [r5] ; store sp in preempted taskss TCB;-----------------------------IMPORT int_vector_handlerbl int_vector_handler ;跳转到中断源判断和中断处理程序;----------------------------- ;restore the registerldmfd sp!, {r0-r12} ;恢复原先保存的R0-R12ldmfd sp!, {r14}msr cpsr_cxsf, r14ldmfd sp!, {r14} ;将原先保存的SPSR_irq恢复到CPSR中ldmfd sp!, {pc}3、堆栈初始化函数OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) {unsignedint *stk;opt = opt; /* 'opt' is not used, prevent warning */stk = (unsigned int *)ptos; /* Load stack pointer *//* build a context for the new task */*--stk = (unsigned int) task; /* pc */*--stk = (unsigned int) task; /* lr */*--stk = (0x60000053); /* cpsr IRQ, FIQ disable*/*--stk = 0; /* r12 */*--stk = 0; /* r11 */*--stk = 0; /* r10 */*--stk = 0; /* r9 */*--stk = 0; /* r8 */*--stk = 0; /* r7 */*--stk = 0; /* r6 */*--stk = 0; /* r5 */*--stk = 0; /* r4 */*--stk = 0; /* r3 */*--stk = 0; /* r2 */*--stk = 0; /* r1 */*--stk = (unsigned int) pdata; /* r0 */// *--stk = (0x0); /* spsr IRQ, FIQ disable */return ((void *)stk);}4、timertick函数void Timer_IRQ_Service1(void){U32 dummyread;U8 y;dummyread = *(RP)TIMER_T1ISCR;/* timerflag = 1;*///OSIntNesting = OSIntNesting + 1;clear_reg( TIMER_T1CR, 0);//关闭通道1中断OSTimeTick ();set_reg( TIMER_T1CR, 0);//使能通道1中断OS_ENTER_CRITICAL();if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked */y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);if (OSPrioHighRdy != OSPrioCur) { /* No CtxSw if current task is highest rdy */OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];OSCtxSwCtr++; /* Increment context switch counter *///OS_TASK_SW(); /* Perform a context switch */OSIntCtxSw();}}OS_EXIT_CRITICAL();}第五步:对移植好的代码进行调试。
1、引言为了实现嵌入式系统终端连入互联网,而有必要为其引入了网络功能。
μC/OS II 是一个源代码开放的实时操作系统,但是它只是一个实时的任务调度及通信内核,并没有集成TCP/IP 通信协议,为了实现网络功能,需要在μC/OS II 移植一个轻量级的TCP/IP 通信协议LwIP。
本文主要论述μC/OS II 下通信协议LwIP 的移植以及测试。
2、LwIP 简介LwIP ( light weight IP)是瑞士计算机科学院的Adam Dunkels 等开发的一套开放TCP/IP 协议栈源代码。
LwIP 既可以移植到操作系统上,又可以在无操作系统的情况下独立运行。
LwIP 实现的重点是在保持TCP/IP 协议主要功能的基础上减少对RAM 的占用,这使LwIP 适合在低端嵌入式系统中使用。
其主要特点如下:(1)支持多网络接口下IP 转发;(2)支持ICMP 协议;(3)包括试验性扩展的UDP;(4)包括简单的拥塞控制,RTT 估算和快速恢复和快速转发的TCP;(5)提供专门的内部回调接口(Raw API)用于提高应用程序性能;(6)可选择的Berkeley 接口API;3、LwIP 协议栈移植到μC/OS II 操作系统的具体实现3.1 嵌入式系统结构和LwIP 接口整个嵌入式系统的结构如图 1 所示,由ARM 微处理器、网卡、网络设备驱动、μC/OSII 操作系统、LwIP 协议栈和应用程序组成。
图 1 嵌入式系统结构图LwIP 在设计时为了适应不同的操作系统,并没有在代码中使用和某个特定的操作系统相关的系统调用和数据结构,而是在LwIP 和操作系统之间提供了一个接口层(sys_arch interface),该接口主要实现的功能包括数据类型的定义、存储模式的选择、任务间的同步、时间和内存的管理等。
因此,完成LwIP 在μC/OS II 移植,我们就是要通过修改这个接口层来实现。
同时,还要根据自己所要实现的具体目的,可以对LwIP 协议栈进行一定的裁减。
LwIP协议栈在NIOS II系统中的移植
李良仁;彭雪峰
【期刊名称】《机电技术》
【年(卷),期】2009(032)004
【摘要】本文介绍了LwIP在NIOS II开发环境下的移植工作,包括底层驱动的编写.系统设计采用SmartSOPC多功能开发平台,使用 uC/OS-II作为底层操作系统,围绕uC/OS-II进行LwIP的移植,最后,通过编写RTL8019AS在LwIP下的驱动程序,完成LwIP在RTL8019AS芯片上的移植.
【总页数】4页(P25-28)
【作者】李良仁;彭雪峰
【作者单位】九江职业技术学院,江西,九江,332007;九江职业技术学院,江西,九江,332007
【正文语种】中文
【中图分类】TP393
【相关文献】
1.基于ARM嵌入式系统的LWIP协议栈移植 [J], 郭连智;夏路易
2.基于Nios软核CPU的μC/OS-Ⅱ和LwIP移植 [J], 李正军
3.LwIP在嵌入式Nios Ⅱ软核处理器上的移植及应用 [J], 元泽怀
4.LwIP在NiosII下的移植及在智能家居中的应用 [J], 熊杰;汪涛
5.基于TMS570微控制器的LwIP协议栈移植与实现 [J], 冯伟; 吕亚方; 滕飞; 王亮亮
因版权原因,仅展示原文概要,查看原文内容请购买。
实验五 uc/OS-II实时操作系统在Nios II中的运行一. 实验目的:了解在NIOSII中使用uc/OSII实时操作系统的基本方法。
二. 实验说明:uc/OS-II已经在世界范围内得到广泛的使用,包括手机、路由器、集线器、不间断电源、飞行器、医疗设备及工业控制等。
实际上,uc/OS-II已经通过了非常严格的测试,并且得到了美国航空航天管理局(FAA)的安全认证,可以用于飞机、航天器等与人性命攸关的控制系统中1。
因此,uc/OS-II在工业等实时性需求比较强的领域应用非常广泛,我们的学习套间提供了在NiosII系统中运行uc/OS-II的例子(“ucosII_test”),该例子定义了两个任务:Task1和Task2,两个任务交替执行。
例子虽然简单,但可以作为uc/OS-II在NiosII系统中运行的演示。
同学们可以参考NiosII的软件开发手册以及uc/OS-II的发明人——Jean J. Labrosse的著作“MicroC/OS-II The Real-Time Kernel”(Second Edition)的中译本《嵌入式实时操作系统uc/OS-II》(第二版,邵贝贝等译),研究和设计出功能更强、更符合实际应用的程序。
一、 参考前面的方法建立一个工程软件工程;二、 打开工程的.syslib工程属性,按下图所示修改编译属性:在“System Library Contents”的“RTOS:”下拉框选择“MicroC/OS-II”,以及右边的程序段都选择SDRAM,因为使用了操作系统,内部ram比较小会容不下,在这里我们选择SDRAM作为uc/OSII的运行环境。
MicroC/OS-II的各个选项的配置可以通过点击“RTOS Options…”按钮进行选择和配置,如下图所示:1《嵌入式实时操作系统uc/OS-II》(第二版)具体操作和配置按照需要和参考ALTERA的软件开发手册。
本例子采用默认配置。
一步步移植uCOS-IIandLwIP(一)STM32F103ZE下移植uCOS-II and LwIP 汇总本文主要记录嵌入式实时操作系统uCOS-II(Ver 2.85)和轻量型TCP/IP协议栈LwIP(Ver 1.4.1)在32bit单片机STM32F103ZE上的移植过程,并列举几个simple examples说明两者工作原理。
本文的叙述原则是“用到什么知识点,就查阅相关资料”,对于其它延伸知识点不再概述。
所需物资:- 硬件开发平台,本平台网卡为DM9000A- uCOS-II(Ver 2.85)源码,可直接从Micrium官网下载uCOS 在cortex-M3上的移植例程uCOSII-ST-STM32F103ZE-SK - LwIP(Ver 1.4.1)源码,下载链接LwIP1.4.1一、Lwip移植TCP/IP协议分为网络链路层、网络层、传输层和应用层四个部分,网络链路层主要涉及底层硬件驱动的编写,另外三个上次协议一般采用协议栈的方式软件实现。
要实现与其它网络设备通信,首当其冲的是要移植好底层网卡驱动。
LwIP协议栈已经为我们提供了网络链路底层接口,我们要做到主要工作涉及到以下几个方面:- 单片机与网卡DM9000芯片的通信;- 完善LwIP协议栈文件ethernetif.c接口函数,该部分的难点在于实现LwIP规定的struct pbuf类型的数据包与网卡数据之间相互转换;- 上层软件协议的simple explain;1、网卡DM9000底层驱动的编写首先查阅DM9000的Datasheet(建议直接从芯片官网上查找,一般会有该芯片的Application note or Demo)本文主要是运用DM9000的16-bit mode,其总线形式类似与intel 8080总线,涉及读写指令和数据的控制引脚为CS#、IOW#、IOR#、CMD,数据总线引脚SD0~SD15,中断引脚INT。
STM32F107上移植声明XX如是说——尊重他人劳动成果,也是一种美德……转载请注明出处闲话稍说这篇笔记旨在讲解LwIP在uCOS-II的上的过程,着重讲述移植的整个流程,不拘泥于细节。
从头至尾一步一步的完成移植工作。
本篇目标是能够ping通目标板,PC机与目标机建立一个初步的连接,至于说其他的应用服务,暂时不予讲述。
友情提示:要想顺利完成LwIP移植,你需具备:1、有一定的C语言基础和数据结构的知识;2、熟悉uCOS-II,了解信号量,消息邮箱等通信方式;3、知道LwIP是何物,能用来干什么硬件平台STM32硬件平台某开发板或你自己设计的硬件我使用是自己的STM32F107VC+DP83848板子IDE环境EWARM-IAR V5.4uCos-II V2.86LwIP V1.3.2目录Day Day Up笔记之uCOS-II+LwIP在STM32F107上移植 (1)声明 (1)闲话稍说 (1)目录 (1)直奔主题 (3)1、巧妇备米 (3)1.1、下载STM32F107_ETH_LwIP例程 (3)1.2、基础工程的建立 (3)2、文件结构 (3)4.2、对应的函数原型声明: (11)4.3、在BSP_Init()中调用BSP_EthernetInit() (11)4.3、相关宏定义: (12)4.4、包含stm32_eth.h头文件: (12)5、编写操作系统模拟层代码 (12)5.1、sys_arch.txt的中文翻译 (12)5.2、编写模拟层代码 (16)A、在\LwIP\port下新建sys_arch.c文件,添加到工程的LwIP\port下 (16)B、在\LwIP\port下新建arch文件夹,新建一个sys_arch的.h头文件,还有cc.h (16)C、在cc.h下定义常用数据类型,服务于模拟层接口函数和底层协议。
添加如下代码: (16)D、留意到#include "cpu.h"没?这可不是uC/OS-II源码中的那个cpu.h, (18)D、编写sys_arch.h (18)E、编写信号量操作函数 (19)F、编写邮箱操作函数 (22)G、初始化sys_arch层 (25)H、编写sys_arch_timeouts函数 (26)I、编写thread_t sys_thread_new函数 (27)K、添加sys_arch.c所需的头文件及变量定义等 (28)5.3、组织编写LwIP接口函数 (29)A、新建两个文件,分别命名为:LwIP.c、LwIP.h。
UCOS-II的详细移植笔记两种处理器的移植比较(S1C33209S3C44BOX)UC/OS-II的详细移植笔记两种处理器的移植比较(S1C33209&&S3C44BOX) [原创 2007-05-20 23:03:21] 字号:大中小UC/OS-II的移植步骤分析zqcumt 07-4-15关于UC/OS-II的移植网上介绍的已经很多了,比较流行的几款处理器(例如ARM)在网上都可以直接下载移植好的代码。
由于最近选修了一门嵌入式系统的课,用的处理器是EPSON公司的S1C33系列,做实验的时候要进行操作系统的移植,这个周末花了一天半的时间学习了一下,因为毕业设计的时候做过ARM上的移植,于是将两者比较了一下,给出一般的移植要点。
由于将来实验还要设计到GUI的移植以及文件系统的移植和网络协议的移植,我会将自己的学习笔记都记录下来。
大家下载到源码后,针对Intel 80x86的代码在uCOS-II\Ix86L目录下。
代码是80x86实模式,且在编译器大模式下编译的。
移植部分的代码可在下述文件中找到:OS_CPU.H, OS_CPU_C.C, 和OS_CPU_A.ASM。
大家可以参考这个例子,对它进行修改。
INCLUDES.H 是主头文件,在所有后缀名为.C的文件的开始都包含INCLUDES.H文件。
使用INCLUDES.H的好处是所有的.C文件都只包含一个头文件,程序简洁,可读性强。
缺点是.C文件可能会包含一些它并不需要的头文件,额外的增加编译时间。
与优点相比,多一些编译时间还是可以接受的。
用户可以改写INCLUDES.H文件,增加自己的头文件,但必须加在文件末尾。
/////////////////////////////////////////////////////////////////// ////////////一、(1)OS_CPU.H文件的移植 (针对S1C33209)//////////////////////////////////////////////////////////////////////////OS_CPU.H 文件中包含与处理器相关的常量,宏和结构体的定义。
一步步移植uCOS-IIandLwIP(二)2、ethernetif.c函数接口编写ethernetif.c文件主要涉及5个接口函数的编写:static void low_level_init(struct netif *netif);static err_t low_level_output(struct netif *netif,struct pbuf *p);static struct pbuf * low_level_input(struct netif *netif);err_t ethernetif_input(struct netif *netif);err_t ethernetif_init(struct netif *netif);(1)low_level_init(struct netif *netif)从函数的声明可以看出,我们的主要工作是对struct netif定义的netif初始化,查阅LwIP源文件找到struct netif结构体的定义(删除条件编译后的基本定义):struct netif {/** pointer to next in linked list */struct netif *next;/** IP address configuration in network byte order */ip_addr_t ip_addr;ip_addr_t netmask;ip_addr_t gw;/** This function is called by the network device driver* to pass a packet up the TCP/IP stack. */netif_input_fn input;/** This function is called by the IP module when it wants* to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. */netif_output_fn output;/** This function is called by the ARP module when it wants* to send a packet on the interface. This function outputs* the pbuf as-is on the link medium. */netif_linkoutput_fn linkoutput;/** This field can be set by the device driver and could point* to state information for the device. */void *state;/** maximum transfer unit (in bytes) */u16_t mtu;/** number of bytes used in hwaddr */u8_t hwaddr_len;/** link level hardware address of this interface */u8_t hwaddr[NETIF_MAX_HWADDR_LEN];/** flags (see NETIF_FLAG_ above) */u8_t flags;/** descriptive abbreviation */char name[2];/** number of this interface */u8_t num;};其中typedef err_t (*netif_input_fn)(struct pbuf *p,struct netif *inp);typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr);typedef err_t (*netif_linkoutput_fn)(struct netif *netif,struct pbuf *p);在这里我们将DM9000底层的MAC地址及初始化写入该函数内,其代码如下:static void low_level_init(struct netif *netif){/* set MAC hardware address length */netif->hwaddr_len = ETHARP_HWADDR_LEN;/* set MAC hardware address */netif->hwaddr[0] = MAC_ADDR0;netif->hwaddr[1] = MAC_ADDR1;netif->hwaddr[2] = MAC_ADDR2;netif->hwaddr[3] = MAC_ADDR3;netif->hwaddr[4] = MAC_ADDR4;netif->hwaddr[5] = MAC_ADDR5;/* maximum transfer unit */netif->mtu = 1500;/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;/* Do whatever else is needed to initialize interface. */DM9000_Init();}(2) struct pbuf * low_level_input(struct netif netif)该函数主要是用来实现将网卡中接收到的数据转换为LwIP定义的struct pbuf类型的数据包,便于协议栈数据处理。
一步步移植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 是不能执行上下文切换的,否则将使中断请求被延迟,而且在真实系统中延迟时间还往往不可预知——任何有一丁点实时要求的系统都决不能容忍这种事。
ϞՈࢿỡඓẋ᫇᪙┨ᥝϾ ҹৢ ៥Ո ᓔথᵓϞඌѢᲕᕫ↨ṇࣷᅮњ ϔাᢍᕫ ᰃϔϾϡ⏝Ոᓔᬒ⑤ۅՈ णᩲᷜ ᛇᡞႮᏅᇍ Ոࢿỡˊᢧݭߎᴹ ԚᰃϵѢ᳔ẕ↨ṇᖭ Ոࢿỡгᰃ߽ϬϮԭᯊⒸخՈ Ҟݭདњৰϔᾬߚ Ո ܜϞᴹ བᵰᆊ᳝݈ᱧ៥ݡᕔϟݭ ៥Ոࢿỡখњ ᡀᰨմՈҷۅ ᆊৃҹএᡀᰨմՈ ϞࢿỡՈ᭛তҷۅᑨϬᖗᕫᰃ̢ᩥਜ਼ᴎᄺ┦˄ ! " # $ " ˅Ո% & ' " ᓔথՈϔ༫ϬѢጠܹᓣிඣՈᓔᬒ⑤ҷۅ($ णᩲᷜDŽ) ᮶ৃҹࢿỡࠄ᪡ிඣϞ জৃҹ᮴᪡ிඣՈᚙމϟưএẔᜐ) ՈĽᗻབϟ˖ᬃᣕตචষϟՈ Ḱথ* ᬃᣕ $+ णᩲ, ࣙᣀᅲɀᗻᠽሩՈՈ-' ˄Ϭ᠋᭄णᩲ˅ࣙᣀ⓿าࠊˈ.((Ԅਜ਼ᖿợᘶᖿợḰথՈ($ ˄Ӵṗࠊणᩲ˅/ ᦤկϧ⒬Ոݙᾬಲ᫇ষ˄.& % ˅ϬѢᦤʌᑨϬ࣏ᑣᗻ࿁0 ৃọᢽՈ1 ষ% ˄ඃ࣏ᚙމϟ˅2 ᳔ᮄՈČᴀЁᬃᣕᮄČᴀЁࡴњՈ # & " Ոᬃᣕᬃᣕ'3$ णᩲ ࡼᗕߚ‑ ഄഔɴตϞ᳔ᮄՈČᴀᰃ4 0Ոẟ࣏ൟणᩲᷜՈ ϔჰ᳝ᮍᓣणᩲՈ↣ϔሖᰃϔϾऩưẟ࣏ ⏂ᲳሖᰃϔϾẟ࣏ ሖᰃϔϾẟ࣏ ሖᰃϔϾẟ࣏ ẝḋՈད໘ᰃตචणᩲՈ↣ϔሖ῁☢ᐌ⏙᱄ ҷۅՈ᫇᪙ˊᢧ῁☢ᐌᆍᯧ Ԛᰃ᳔Ոണ໘᭄ᲬሖӴỖᯊӮᓩ᰻Ϟϟ᭛ߛᤶ " 5 !ᇍѢᬊϔϾ($ " ᡅᓩ᰻, " 5 ! Ңตवȥࡼ࣏ᑣࠄ⏂Ჳሖẟ࣏ Ң⏂Ჳሖẟ࣏ࠄ ሖẟ࣏ Ң ሖẟ࣏ࠄ($ ẟ࣏ ỞᐌᇍѢ᪡ிඣᴹ᪸ ӏࡵߛᤶᰃᡅ⌾᯽ᯊⒸՈ ẋEՈ " 5 !ᰃϡৃপՈ * ϔᮍᓣᰃ($ णᩲᷜ᪡ிඣݙḌᔧЁ ᑨϬ࣏ᑣỞẋ᪡ிඣՈிඣ᫇Ϭ & णᩲᷜᴹẟᜐỞᩳẝḋ($ Ոणᩲᷜህ└ᅮѢĽᅮՈ᪡ிඣݙḌњ བ " ህᰃẝᮍᓣ, Ո 6᠔᳝ णᩲᷜ῁ϔϾẟ࣏ᔧЁ ẝḋ णᩲᷜህ᪡ிඣݙḌߚᓔњ ໐ᑨϬሖ࣏ᑣ᮶ৃҹᰃऩưՈẟ࣏гৃҹȯН ẟ࣏Ё བᵰᑨϬ࣏ᑣᰃऩưՈẟ࣏ৃҹỞẋ᪡ிඣՈὲੵ ⍜ᙃⓣ߫ ẟ࣏ẟᜐỞᩳབᵰᑨϬሖ࣏ᑣȯН ẟ࣏Ё ὧᑨϬሖ࣏ᑣህ߽Ϭݙᾬಲ᫇ߑ᭄ষ .& % णᩲᷜỞᩳ ᇍѢ ᴹ᪸ẟ࣏ህᰃϔϾிඣӏࡵ Ո ᪻খϟ ЁৃҹࠄᭈϾ णᩲᷜ῁ৠϔϾӏࡵ 7 ! & Ё ᑨϬሖ࣏ᑣ᮶ৃҹᰃưএՈӏࡵ བЁՈ # 7 ! & ! 7 ! & гৃҹ 7 ! & Ё བᎺϞᢖ Ё߽Ϭݙᾬಲ᫇ߑ᭄ষ .& % णᩲᷜỞᩳ* ) $ẝϾ-ֲЁ៥ϬՈܰӊᑇৄᰃ , 5 ϞՈࢿỡตϞ᳝ᕜմ☢ᐌ᪪ሑՈ᩶ᢧࢿỡҷۅ ៥ህϡᬶปњ ◄ᡅ᪸ᯢՈϔ⚍ᰃ ӮЎ↣ϾตචẢࡼᗕߚ‑ϔѯֵোₓ & ! " ⍜ᙃⓣ߫ + & 8 ᔧẢᮁᓔᯊӮߴᥝẝѯ & ! " 8 ໐- 9* ϡᬃᣕ & ! " 8 Ոߴ┨ ᠔ҹᡅọᢽϔѯṇʌČᴀՈ ៥ϬՈᰃ 9* /* ) Ո᪡ிඣᇕញሖ & " & " &) ЎњỆᑨϡৠՈ᪡ிඣ ҷۅЁ≵᳝ՓϬᶤϔϾ᪡ிඣּ݇Ոிඣ᫇Ϭ᭄ᵘ ໐ᰃ ᪡ிඣПⒸࡴњϔϾ᪡ிඣᇕញሖ ᪡ிඣᇕញሖЎ᪡ிඣ᳡ࡵ ᅮᯊ ẟ࣏ৠℹ ⍜ᙃӴỖ ᦤկњϔϾඣϔՈষ Ёẟ࣏ৠℹՓϬ & ! " ⍜ᙃӴỖ₋Ϭ: 5: ݊ᅲ ՈᅲɴЁ៥ӀՓϬՈᰃ+ & 8 ᴹᅲɴ ЁՈ: 5: ϟ☦ᆊৃҹࠄẝϔ⚍; & " & " & Ոॳҷۅ< Ё ໐ԧՈ᪡ிඣּ݇Ոҷۅ & ! 7& ! Ё᪡ிඣᇕញሖՈЏᡅߑ᭄བϟ6= 7 " = ிඣ߱ྟ࣪7 ! & 7 7 ! & 7" = > # " " = >& = >& " ߯ᓎϔϾᮄẟ࣏7 57 7 57" = ߯ᓎϔϾὲੵ= 7 57# 7 57 5 ₎ᬒᑊߴ┨ϔϾὲੵ= 7 57 7 57 5 = > & & থễϔϾ⍜ᙃࠄὲੵ= 7 57# ! 7 57 5 = >> ᕙὲੵЁՈ⍜ᙃ7 7 7 7" 7 " ߯ᓎϔϾֵোₓ= 7 7# 7 7 ₎ᬒᑊߴ┨ϔϾֵোₓ= 7 7 "& 7 7 থễϔϾֵোₓ= 7 7 & 7 7 ᕙϔϾֵোₓ= 7 ,*7 7 7!&" ! = >& ᪂าϔϾ᱉ᯊџӊ= 7 " 7 7!&" ! = >& ߴ┨ϔϾ᱉ᯊџӊ<݇Ѣ᪡ிඣᇕញሖՈֵᙃৃҹⓉᪿ Ո ֲᔩϟ☦Ո 7& ! 5 ᭛ӊ* * ) ϞՈࢿỡ* * ிඣ߱ྟ࣪7 " ᖙ/ णᩲᷜӏࡵ 7 ! & ߯ᓎࠡᝯ᫇Ϭ? # " +%@78-A-A *? # " +%@78-A-A7AB(. A *# C; 7A4AB(> 8D ЁᣛџӊࠊഫՈᣛ⍌= > =8A" E+%@78-A-A7AB(. A FD ⍜ᙃⓣ߫+%@78-A-A7AB(. A ⍜ᙃⓣ߫Ё᳔⍜ᙃ᭄G (87'A $. > 87'A $.D# 87'A $. 7 57 D ৃᢅ ЁՈ 5݊ᅲᰃ Ո⍜ᙃⓣ߫& !& 8 + E+%@78-A-A > H # (87'A $. FD= 7 " =C7 D7 A D8 + I ; + $ & = > 8 + +%@78-A-A H # (87'A $. J A D Ў⍜ᙃⓣ߫߯ᓎݙᄬߚऎ" & ##7 7 ## I D" 7 # = &߱ྟ࣪ ᅮᯊџӊᜬ ԧᅲɴখϟ☦তᅆ# I D K)L 7(% M7+%@D C7 E F " 5 I B-))DGG* * * ߯ᓎϔϾ ּ݇ᮄẟ࣏6ЁՈẟ࣏ህᰃ ЁՈӏࡵ ߯ᓎϔϾᮄẟ࣏Ոҷۅབϟ6? # " )L 7 (M7 NA > * ּ݇ӏࡵՈේᷜᇣ ৃҹḍᚙމႮᏅ᪂า ᓔথᵓϞ᳝ +Ո & ᠔ҹ᪂ϔ⚍г≵᳝݇ி6&5 " # &? # " )L 7(% M7+%@/ ּ݇Ոӏࡵ᳔᭄ֲ# # &? # " )L 7 (%.(7 . ;/ ּ݇ӏࡵՈ᰻ྟӬܜ൫ ᴀ՟ЁӬܜ൫ৃҹҢ /9 ⊼ᛣ 7 ! & ᠔᳝ ּ݇ẟ࣏Ё ᑨ᪩ᰃӬܜ൫᳔ʌՈ ᴀ՟ЁህᰃӬܜ൫/བᵰϬ᠋◄ᡅ߯ᓎ ᮴݇ӏࡵ བ & ӏࡵϡᡅՓϬ/9 ՈӬܜ൫; 7 (M )L 7(% M7 (ME)L 7(% M7+%@FE)L 7 (M7 NAFD ּ݇ẟ࣏Ոේᷜऎ7 7 7 ## D7 ! & 7 7 ! & 7" = > # " " = >& = >& "C# 7 7 ## K )L 7(% M7+%@ C; (& $ & # " " = > 5 J)L 7(% M7 (ME 7 7 ## FE)L 7 (M7 NA9 F)L 7 (%.(7 . ; 7 7 ## D7 7 ## D" DG C. B( O & # &" P P O DGGҢҷۅЁৃҹߎ 7 ! & ᑨ᪩ᰃ᳔ܜ߯ᓎՈ* * , ) ЁՈᅮᯊџӊ णᩲЁᕜᯊ῁ᡅϬࠄᅮᯊ ᅮᯊՈᅲɴгᰃ णᩲᷜЁϔϾₑᡅՈᾬߚ ЁᅮᯊџӊՈ᭄ᵘབϟ7 C7 >" 5 D ᣛϟϔϾᅮᯊᵘ,*7 D ᅮᯊᯊⒸ7 7!&" !D ᅮᯊᯊⒸࠄৢᠻᜐՈߑ᭄= >& D ᅮᯊᯊⒸࠄৢᠻᜐߑ᭄Ոখ᭄GD7 C7 >" 5 DGD7 7 E)L 7(% M7+%@FD) ЁՈᅮᯊџӊᜬՈᵘབϟ ↣Ͼ ּ݇ՈӏࡵՈϔி߫ᅮᯊџӊඈ៤ϔϾऩ⏂ᜬ ↣Ͼ⏂ᜬՈ᰻ྟᣛ⍌ᄬ 7 Ոᇍᑨᜬ-Ёߑ᭄ 7& !7 ẘಲᇍᑨѢᔧࠡӏࡵՈᣛᅮᯊџӊ⏂ᜬՈ᰻ྟᣛ⍌ ᪩ᣛ⍌ᄬ 7 E+%@7)L 7(% M FЁ7 " 7 D7 > 7& !7 =C7 7 D07 ## D; 7($1 7 & 7 D" 7 " 5 I B-))DቻপᔧࠡӏࡵՈӬܜ൫I ; (& 8 ; 7 . ;7 A)Q J 7 & 7 D7 I 7 & 7 ; ($1 D## I 7 9 )L 7 (%.(7 . ;D߸ᮁᔧࠡӏࡵӬܜ൫ᰃϡᰃ ּ݇ӏࡵ Ӭܜ൫/9# ## K RR ## SI )L 7(% M7+%@C" J" 7 DG" J 7 E ## FDG⊼ᛣ6ᴼᰨմࢿỡՈҷۅᴀߑ᭄᳝ϔϾ ᴼᰨմՈࢿỡᡞϞ☦ߑ᭄ЁՈ; 7($1 7 & 7 ᅮН៤њܼሔবₓ Փᴀߑ᭄៤ЎњϔϾϡৃₑܹߑ᭄៥гᰃẟᜐབϟ⌟᪙ᯊথɴњẝϾ៥ՈᓔথᵓϞ᪂าՈ ഄഔᰃ * 0 /៥ " Ո ज़ষݙẔᜐ" * 0 / T * T ϡⒸᮁϬ⑃ᑺЎ* Ո᭄ẟᜐ " ⌟᪙ৠᯊՓϬ # ᅶ᠋ḳӊඝ * 0 /ϟṁϔϾकܚ࣏ᑣৠᯊݡՓϬ " Ả * 0 /ষ2 ! ষ ᕔ᪩ষݭ᭄⌟᪙ ! ࡳ࿁Ẕᜐϔ↉ᯊⒸҹৢ ᓔথᵓẟܹϡݡડᑨ ៥ᔧᯊгᰃඓẋ⑃ᯊⒸՈߚᵤᠡথɴᰃЎԢӬܜ൫ӏࡵẔᜐ 7& !7 ᯊᝯʌӬܜ൫ӏࡵᠧᮁᬍݭњ 7 & 7 Ոؐ Ң໐Փ 7& !7 ẘಲՈᣛ⍌⏝᪳ ẟ໐ᇐႸிඣ⅏⏅ߑ᭄ 7 ඝᔧࠡӏࡵࡴϔϾᅮᯊџӊ6= 7 ,*7 7 7!&" ! = >&C7 > D7 > > DI 7 & +A+ 7 U 7( +A;-( D Ўᅮᯊџӊߚ‑ݙᄬ# II B-)) C"DG9S" 5 I B-))D9S! I !D9S& I & D9S I DI 7& !7 D ẘಲᔧࠡӏࡵᅮᯊџӊ⏂ᜬ᰻ྟᣛ⍌# 9S" 5 II B-)) C བᵰ⏂ᜬЎाָࡴ᪩ᅮᯊџӊ9S" 5 I D"DGབᵰ⏂ᜬϡЎा ᇍᅮᯊџӊẟᜐᥦᑣ ⊼ᛣᅮᯊџӊЁՈ ᄬټՈᰃᴀџӊᯊⒸּᇍѢࠡϔџӊՈᯊⒸՈᏂؐ# 9S" 5 9S S C9S" 5 9S 9I D9S" 5 I 9S" 5 D9S" 5 I DG C# I 9S" 5 D PI B-))D I 9S" 5 C9S 9I 9S D# 9S" 5 II B-)) RR9S" 5 9S S 9S C# 9S" 5 PI B-)) C9S" 5 9S 9I 9S DG9S" 5 I 9S" 5 D9S" 5 I D& DGGGGߑ᭄ 7 " Ңᔧࠡӏࡵᅮᯊџӊ⏂ᜬЁߴ┨ϔϾᅮᯊџӊ= 7 " 7 7!&" ! = >&C7 > D7 > =7 > DI 7& !7 D ẘಲᔧࠡӏࡵᅮᯊџӊ⏂ᜬ᰻ྟᣛ⍌ # 9S" 5 II B-)) བᵰ⏂ᜬЎाָẘಲC"DGᶹᡒᇍᑨᅮᯊџӊᑊҢ⏂ᜬЁߴ┨# I 9S" 5 =7 I B-))D PI B-))D =7 I I 9S" 5 C# 9S! II ! JJ 9S& II &C> L !&= & & ! >> -" " # = " ># =7 II B-))9S" 5 I 9S" 5 D=7 9S" 5 I 9S" 5 D> # " ! & " & # ! " & " 5 ># 9S" 5 PI B-))9S" 5 9S I 9S D7# +A+ 7 U 7( +A;-( D"DGG"DG* * ,V 5:Ոᅲɴ65Ո߯ᓎ7 57 7 57" =C7 A D87'A $. 8' DҢ⍜ᙃⓣ߫ݙᄬߚऎЁᕫࠄϔϾݙᄬഫ8' I ; + W 8 + J A D# A II ; 7B;7A.. C߯ᓎϔϾ⍜ᙃⓣ߫8' 9S 8I; 8$ & J 8' 9S =8A" E F +%@78-A-A7AB(. A D# 8' 9S 8 PI B-)) C" 8' DGG" U 7+1;@7B-))DG* থϔᴵ⍜ᙃඝ: 5:" = > " =B " I 5########D= 7 57 7 57 5 = > & &CB( - D# P & && & I = > J =B " DI ; 8 59S 8 & & DG Ё བᵰ; 8 ; 7A4AB( > = " = > ЁՈ IIB-)) Ӯẘಲϔᴵ; 7A..7 ; (7B-))7 (.⏝᪳ ໐ ЁӮ᫇Ϭ 7 57 5 B-)) থễϔᴵा⍜ᙃ ៥Ӏᴀߑ᭄ЁᡞB-))ব៤ϔϾᐌₓᣛ⍌ 5########, Ң: 5:Ёᪿপϔᴵ⍜ᙃ? # " U 7%.$37( +A;-( 5########= 7 57# ! 7 57 5 = >>C,*7 D7 > D7 > D7 7!&" !D= >& D& & "6I 7& !7 D ẘಲᔧࠡӏࡵᅮᯊџӊ⏂ᜬ᰻ྟᣛ⍌# P RR P 9S" 5 C བᵰᅮᯊџӊ⏂ᜬЎा7& !7 57# ! 5 D ᮴᱉ᯊᕙ⍜ᙃG C# 9S" 5 9S S Cབᵰ᱉ᯊџӊ⏂ᜬϡЎा ໐ϨৰϔϾ᱉ᯊџӊՈ PIᏺ᱉ᯊᕙ⍜ᙃⓣ߫ ᱉ᯊᯊⒸѢ᱉ᯊџӊ⏂ᜬЁৰϔϾ᱉ᯊџӊՈI 7& !7 57# ! 5 9S" 5 9S Dৢ☦ߚᵤЁৃҹࠄ 7& !7 57# !᫇Ϭњ ЁՈ; 8 " ிඣ᫇ϬҢ⍜ᙃⓣ߫Ёᪿপ⍜ᙃབᵰ: 5:⍜ᙃⓣ߫ϡЎा ӏࡵএࠏẘಲ ৺߭ӏࡵẟܹ⓿าᗕ◄ᡅₑ⚍᪸ᯢՈᰃ 7& !7 57# !Ոẘಲؐ 6བᵰ 7& !7 57# !Ў᱉ᯊẘಲ I U 7%.$37( +A;-(བᵰ 7& !7 57# !Ўᬊࠄ⍜ᙃ໐ẘಲI ᬊࠄ⍜ᙃᯊࠏՈᯊⒸ9ᠻᜐ 7& !7 57# !ᯊࠏՈᯊⒸ ऩԡᰃ↿ϵѢ Ёӏࡵ᫇Ϭ; 8 " ிඣ᫇Ϭẟܹ⓿าᗕ ࠄᬊࠄ⍜ᙃₑᮄᓔྟᠻᜐ ẝ↉ᯊⒸ≵᳝ᩴᔩϟᴹ ᠔ҹ៥Ӏᡅऩׂᬍ Ո⑤ҷۅ ৢ☦៥ӀӮࠄG Cབᵰᅮᯊџӊ⏂ᜬϡЎा ໐ϨৰϔϾᅮᯊџӊՈ II ᜬ߾᪩џӊՈᅮᯊ ᯊⒸࠄI U 7%.$37( +A;-(DG# II U 7%.$37( +A;-( CϔϾᅮᯊџӊՈᅮᯊᯊⒸࠄI 9S" 5 D9S" 5 I 9S" 5 D! I 9S!D& I 9S& D7# +A+ 7 U 7( +A;-( DҢݙᄬЁ₎ᬒ᪩ᅮᯊџӊ ᑊᠻᜐ᪩ᅮᯊџӊЁՈߑ᭄# ! PI B-)) C! & DGЎᅮᯊџӊЁՈᅮᯊᯊⒸࠄ້ᰃЎ 7& !7 7# !᱉ᯊࠄ໐ᠻᜐࠄ ẝₐ ẘಲᴀߑ᭄ᓔ༈ₑᮄᕙ 5Ո⍜ᙃ& & "DG Cབᵰ 7& !7 57# !᮴᱉ᯊᬊࠄ⍜ᙃẘಲ߭ࠋᮄᅮᯊџӊ⏂ᜬЁᅮᯊџӊՈ ؐ# KI 9S" 5 9S C9S" 5 9S 9I DG C9S" 5 9S I DGGGG,*7 7& !7 57# ! 7 57 5 = >> & & ,*7C,*7 A D07 7 D Ё Ոऩԡᰃ Ոऩԡᰃ7 I D# PI C7 I > ; 7( $M 7 A.7 A$ D# 7 K7 I D# 7 S 0//,/7 I 0//,/DGབᵰ & &PIB-))ህẘಲ⍜ᙃᣛ⍌# & & PI B-)) C> & & I ; 8 " 59S 8 07 7 J A DG C; 8 " 59S 8 07 7 J A DGẝₐׂᬍњ ЁՈ; 8 " ிඣ᫇ϬॳᴹՈ= >; 8 " ; 7A4AB( > = " B( 0- B( - >Ոẘಲؐা᳝ϸ6ᬊࠄ⍜ᙃህẘಲ; 7B;7A.. ᱉ᯊ߭ẘಲ; 7( +A;-(ẝₐܜᇚ Ң ԡ᭄ᬍব៤њ 0ԡ᭄ ; 8 " > = " B( 0- > ₑᮄᅮНњ; 7( +A;-( Ёॳ᳝? # " ; 7( +A;-( *ᬍЎ ? # " ; 7( +A;-(9ẘಲؐՈᛣНгᬍবњ བᵰ᱉ᯊẘಲ; 7( +A;-(བᵰᬊࠄ⍜ᙃ ߭ẘಲ; ($1$ 9S; ($1' ׂᬍᾬߚҷۅབϟ# PI = > C > ' & & X>; ($1$ 9S; ($1+ I = > D; ($1$ 9S; ($1 & I ; 7 (%(7.'UD; ($1$ 9S; ($1A= " I ; 7A4AB( > D> I ; ($1$ 9S; ($1' D H!&" H Y* , * *; 7A@ (7$. ( $%) D" D > . " & = >G݇Ѣ Ո; (1$ 9S; ($1' ՈН᪻ᶹⓉ Ոк# A II ; 7( +A;-( CI U 7%.$37( +A;-(DG C# > & & II = > J =B "> & & I B-))DऩԡḰᤶ Ң 9SI 7 9 A > ; 7( $M 7 A.7 A$ DG" DG& ! " Ոᅲɴ 5ିԐ ẝₐህϡݡₑњᴹ⑤*。
基于Nios软核CPU的uCOS-II 和LwIP移植Altera公司推出的Nios软核CPU是一种可配置的通用精简指令集计算RISC(Reduced Instruction Set Computing)嵌入式处理器。
它可以与各种外设相结合,构成一个定制的可编程片上系统SOPC(System on Programable Chip)。
嵌入式实时操作系统uC/OS-II是一个非常优秀的实时操作系统RTOS(Real Time Operating System),其性能已得到广泛认可。
uC/OS-II的特点有:公开的源代码、可移植、可裁剪、可固化、抢占式内核。
TCP/IP是Interenet的基本协议。
嵌入式设备要与Internet网络交换信息,就必须支持TCP/IP协议。
尽管uC/OS-II是一个开放源码的RTOS,但是目前它的第三方TCP/IP支持都是商业化的,很少给出源代码。
用户需要付费才能获得。
通过在Nios上移植uC/OS-II和开放源码的TCP/IP协议栈-LwIP轻量级网络协议(Light-weight Internet Protocol),就可以实现uC/OS-II的网络功能,并建立一套嵌入式网络开发平台。
该系统模型示于图1。
uC/OS-II在Nios上的移植uC/OS-II可以看作是一个多任务的调度器,在这个任务调度器上添加了和多任务操作系统相关的一些系统服务,如信号量、邮箱、消息队列等。
uC/OS-II的设计分为与处理器类型无关的代码、与处理器类型相关的代码和与应用程序有关的配置代码三部分。
这也是uC/OS-II具有良好的可移植性的原因。
移植工作主要集中在多任务切换的实现上。
这部分代码主要是用来保存和恢复处理器现场(即相关寄存器),因此不能用c语言,只能使用特定处理器的汇编语言完成。
在Nios上移植uC/OS-II非常简单,只需修改三个和Nios体系结构相关的文件即可。
下面分别介绍这三个文件的移植工作。
ucos+lwip应用心得与体会经过几天调试除掉几个bug以后,ucos+lwip在我的44b0+8019开发板上终于跑得比较稳定了.一只觉得lwip是一个不错的开放源码的tcp/ip 协议栈,想把自己对lwip的移植和理解写出来.但是由于最近比较忙,lwip的移植也是利用业余时间做的,今天写好了第一部分(lwip的 process model)先贴上来,如果大家有兴趣我再接着往下写.另外我的移植参看了skyeye扬晔大侠的代码,大家可以去看看扬晔大侠的lwip在ucos上移植的文章和代码.lwIP是瑞士计算机科学院(Swedish Institute of Computer Science)的Adam Dunkels等开发的一套用于嵌入式系统的开放源代码TCP/IP协议栈,ucos+lwip应用心得[社区]。
Lwip既可以移植到操作系统上,又可以LwIP的特性如下:(1)支持多网络接口下的IP转发(2)支持ICMP协议(3)包括实验性扩展的的UDP(用户数据报协议)(4)包括阻塞控制,RTT估算和快速恢复和快速转发的TCP(传输控制协议)(5)提供专门的内部回调接口(Raw API)用于提高应用程序性能(6)可选择的Berkeley接口API(多线程情况下)(7)在最新的版本中支持ppp(8)新版本中增加了的IP fragment的支持.(9)支持DHCP协议,动态分配ip地址.现在网上最新的版本是V0.6.41.lwip的进程模型(process model)tcp/ip协议栈的process model一般有几种方式.1.tcp/ip协议的每一层是一个单独进程.链路层是一个进程,ip 层是一个进程,tcp层是一个进程.这样的好处是网络协议的每一层都非常清晰,代码的调试和理解都非常容易.但是最大的害处数据跨层传递时会引起上下文切换(context switch).对于接收一个TCP segment要引起3次context switch(从网卡驱动程序到链路层进程,从链路层进程到ip层进程,从ip层进程。
μC/OS-II在几种处理器上的移植介绍
μC/OS-II 操作系统是一种抢占式多任务、单内存空间、微小内核的嵌入式操作系统,具有高效紧凑的特点。
它执行效率高,占用空间小,可移植性强,实时性能良好且可扩展性强。
采用μC/OS-II 实时操作系统,可以有效地对任务进行调度;对各任务赋予不同的优先级可以保证任务及时响应;采用实
时操作系统,降低了程序的复杂度,方便程序的开发和维护。
μC/OS-11 非常适合应用在一些小型的嵌入式产品应用场合,在家用电器、机器人、工业控制、航空航天、军事科技等领域有着广泛的应用。
单片机、ARM、FPGA 与μC/OS-II 操作系统相结合,实现一些具体功能,是目前嵌入式应用中比较常见的。
在这些应用中,基础性的工作就是操作系统的移植。
本文选取使用较多的51 单片机、LPC2210、NiosII 三种处理器进行介绍。
1 μC/OS-II 操作系统移植条件
μC/OS-II 操作系统的大部分源代码都是用C 语言书写的,但仍需使用汇编语言来完成一些和处理器相关的操作,例如读写处理器、寄存器时只能使用汇编语言来实现。
因此,将μC/OS-II 操作系统移植到目标处理器上,需要从硬件和软件两方面来考虑。
硬件方面,目标处理器需满足以下条件:
①处理器的C 编译器能产生可重入代码;
②用C 语言可以开/关中断;
③处理器支持中断,并且能够产生定时中断(通常在10~1 000 Hz 之间);
④处理器能够支持容纳一定量数据的硬件堆栈;
⑤处理器有将堆栈指针和其他寄存器读出和存储到堆栈或内存中的指令。
一步步移植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。
LwIP协议栈在NIOS_系统中的移植LwIP协议栈在NIOS II系统中的移植李良仁彭雪峰(九江职业技术学院,江西九江 332007)摘要:本文介绍了LwIP在NIOS II开发环境下的移植工作,包括底层驱动的编写。
系统设计采用SmartSOPC多功能开发平台,使用uC/OS-II作为底层操作系统,围绕uC/OS-II进行LwIP的移植,最后,通过编写RTL8019AS在LwIP 下的驱动程序,完成LwIP在RTL8019AS芯片上的移植。
关键词:NIOS II LwIP RTL8019AS 移植中图分类号:TP393 文献标识码:A 文章编号:1672-4801(2009)04-025-04前言LwIP即轻型TCP/IP协议栈,其实现的关键是在提供全部TCP/IP 的同时减少了资源的使用,LwIP被设计用于具有存储容量有限的嵌入式系统,并实现了较为完备的IP、ICMP、UDP、TCP、DHCP、ARP,标准套接字API。
LwIP 为NIOS II 处理器提供对以太网连接栈的快速、开源的访问。
Altera 的LwIP 端口使用uC/OS-II多线程环境,NIOS II 处理器系统也必须包含以太网接口,LwIP驱动程序采用中断驱动,所以必须保证以太网组件的中断被连接。
Altera 的LwIP接口是基于HAL 的通用以太网设备模型。
目前,大部分文献都是根据这个模型,编写新的驱动程序,以支持任意目标以太网MAC,偏重于应用。
本文阐述LwIP 协议栈及其在NIOS II系统上的移植原理,在此基础通过编写RTL8019AS在LwIP下的驱动程序,完成LwIP在RTL8019AS芯片上的移植。
1 LwIP协议介绍与许多其它的TCP/IP实现一样,LwIP也是以分层的协议为参照——设计实现TCP/IP。
每一个协议作为一个模块被实现,同时还提供了几个函数作为协议的入口点。
尽管这些协议是被独立实现的,但是有些层却不是这样,这样做的目的是为了在处理速度与内存占用率方面提升性能。
Altera公司推出的Nios软核CPU是一种可配置的通用精简指令集计算RISC(Reduced Instruction Set Computing)嵌入式处理器。
它可以与各种外设相结合,构成一个定制的可编程片上系统SOPC(System on Programable Chip)。
嵌入式实时操作系统uC/OS-II是一个非常优秀的实时操作系统RTOS(Real Time Operating System),其性能已得到广泛认可。
uC/OS-II的特点有:公开的源代码、可移植、可裁剪、可固化、抢占式内核。
TCP/IP是Interenet的基本协议。
嵌入式设备要与Internet网络交换信息,就必须支持TCP/IP协议。
尽管uC/OS-II是一个开放源码的RTOS,但是目前它的第三方TCP/IP支持都是商业化的,很少给出源代码。
用户需要付费才能获得。
通过在Nios上移植uC/OS-II和开放源码的TCP/IP协议栈-LwIP轻量级网络协议(Light-weight Internet Protocol),就可以实现uC/OS-II的网络功能,并建立一套嵌入式网络开发平台。
该系统模型示于图1。
uC/OS-II在Nios上的移植uC/OS-II可以看作是一个多任务的调度器,在这个任务调度器上添加了和多任务操作系统相关的一些系统服务,如信号量、邮箱、消息队列等。
uC/OS-II的设计分为与处理器类型无关的代码、与处理器类型相关的代码和与应用程序有关的配置代码三部分。
这也是uC/OS-II具有良好的可移植性的原因。
移植工作主要集中在多任务切换的实现上。
这部分代码主要是用来保存和恢复处理器现场(即相关寄存器),因此不能用c语言,只能使用特定处理器的汇编语言完成。
在Nios上移植uC/OS-II非常简单,只需修改三个和Nios体系结构相关的文件即可。
下面分别介绍这三个文件的移植工作。
1.1 OS_CPU.H文件数据类型定义这部分的移植是和所用的编译器相关的,我们使用的编译器是nios-elf-gcc。
需要定义的数据类型包括无符号和有符号的8位、16位和32位整型变量等。
堆栈单位因为处理器现场的寄存器在任务切换时都将被保存在当前运行任务的堆栈中,所以OS_STK数据类型应该与处理器的寄存器长度一致。
typedef unsigned int OS_STK;堆栈增长方向堆栈由高地址向低地址增长,这和选择的编译器有关。
#define OS_STK_GROWTH 1宏定义(包括开、关中断的宏定义,以及进行任务切换的宏定义)#define OS_ENTER_CRITICAL() disable_interrupt();#define OS_EXIT_CRITICAL() enable_interrupt()#define OS_TASK_SW() OSCtxSw1.2 OS_CPU_C.C文件该文件必须实现任务初始化时的堆栈设计,也就是在堆栈增长方向上如何定义每个需要保存的寄存器的位置。
我们将堆栈空间设计为按任务堆栈空间由高至低依次保存寄存器ra、ISTATUS、r1~r31。
该文件还需要实现几个操作系统规定的hook函数。
通常都实现为空函数。
1.3 OS_CPU A.S文件(由汇编语言实现)(1)OSStartHighRdy()函数此函数是在OSStart()多任务启动后,负责从最高优先级任务的TCB控制块中获得该任务的堆栈指针sp,通过sp依次将CPU现场恢复。
这时系统就将控制权交给用户创建的该任务进程,直到该任务被阻塞或者被其他更高优先级的任务抢占CPU。
该函数仅仅在多任务启动时被执行一次,用来启动优先级最高的任务执行,以后多任务的调度和切换就由下面的函数来实现。
(2)OSCtxSw()函数任务级的上下文切换。
它是当任务因被阻塞而主动请求CPU 调度时被执行的。
它的工作是先将当前任务的CPU现场保存到该任务堆栈中,然后获得最高优先级任务的堆栈指针,从该堆栈中恢复此任务的CPU现场,使之继续执行。
(3)OSIntCtxSw()函数中断级的任务切换,它是在ISR(中断服务例程)中执行任务切换。
当发现有高优先级任务就绪,则在中断退出后并不返回被中断任务,而是直接调度就绪的最高优先级任务执行。
这样做的目的是能够尽快地让高优先级的任务得到响应,保证系统的实时性。
它的原理基本上与任务级的切换相同,但是由于进入中断时已经保存过被中断任务的CPU现场,因此这里就不用再保存。
(4)OSTickISR()函数时钟中断处理函数。
它的主要任务是负责处理时钟中断,调用系统实现的OSTimeTick函数,如果有等待时钟信号的高优先级任务,则需要在中断级别上调度其执行。
(5)OS_ENTER_CRITICAL()函数和OS_EXIT_CRITICAL()函数分别是进入临界区和退出临界区的宏指令。
主要用于在进入临界区之前关中断,在退出临界区的时候恢复原来的中断状态。
2 LwIPLwIP是Light-weight Internet Protocol的缩写,即轻量级网络协议。
LwIP是瑞典计算机科学院的Adam Dunkels等开发的用于嵌入式系统的TCP/IP协议栈。
LwIP实现的重点是在保持TCP/IP协议主要功能的基础上减少对RAM的占用,一般它只需要几十KByte的RAM和40K左右的ROM就可以运行,适于在嵌入式系统中使用。
在LwIP中,所有TCP/IP协议栈都在一个进程当中。
应用层程序既可以是单独的进程,也可以驻留在TCP/IP进程中。
如果是单独的进程,可以通过操作系统的邮箱、消息队列等和TCP/IP进程进行通讯;如果驻留TCP/IP进程中,那么利用内部回调函数接口(Raw API)和TCP/IP协议栈通讯。
对uC/OS-II来说,进程就是一个任务。
LwIP的进程模型 (Process Model)示于图2。
在图2中,整个TCP/IP 协议栈都在同一个任务(tcpip_thread)中。
应用层程序既可以是独立的任务(图中的tftp_thread和cpecho_thread),也可以在tcpip_thread中利用内部回调函数接口和TCP/IP协议栈通讯。
3 LwIP在uC/OS-II上的移植在设计LwIP时,就考虑到移植问题,所有与操作系统、编译器相关的部分被独立出来,放在/src/arch目录下。
因此,LwIP在uC/OS-II上的实现就是修改这个目录下的文件。
下面分别说明相应文件的实现。
3.1 与CPU或编译器相关的include文件在LwIP/src/arch/include/arch目录下,cc.h、cpu.h、perf.h中有一些与CPU 或编译器相关的定义,如数据长度、字的高低位顺序等。
这应该与用户实现uC/OS-II时定义的参数一致。
通常,c语言的结构体(struct)是4字节对齐的,但是在处理数据包的时候,LwIP是通过结构体中不同数据的长度来读取相应的数据的,所以,一定要在定义struct的时候使用_packed关键字,让编译器放弃struct的字节对齐。
LwIP也考虑到了这个问题,所以,在它的结构体定义中有几个PACK_STRUCT_xxx宏,在移植的时候添加编译器所对应的_packed关键字。
比如在nios-eft-gcc上对应的定义为:#define PACK_STRUCT_FIELD(x) x_attribute_((packed))#define PACK_STRUCT_STRUCT _attribute_((packed))3.2 sys_arch操作系统相关部分sys_arch.h[c]中的内容是与OS相关的一些结构和函数,主要可以分为四个部分:3.2.1 sys_sem_t 信号量LwIP中需要使用信号量进行通信,所以在sys_arch中应实现信号量结构体和处理函数:struct sys_sem_tsys_sem_new() //创建一个信号量结构sys_sem_free() //释放一个信号量结构sys_sem_signal() //发送信号量sys_arch_sem_wait() //请求信号量由于uC/OS-II已经实现了信号量OS_EVENT的各种操作,并且功能和LwIP上面几个函数的功能是完全一样的,所以只要把uC/OS-II的函数重新封装成上面的函数就可以了。
3.2.2 sys_mbox_t消息LwIP使用消息队列来缓冲、传递数据报文,因此要在sys_arch中实现消息队列结构sys_mbox_t以及相应的操作函数:sys_mbox_new() //创建一个消息队列sys_mbox_free() //释放一个消息队列sys_mbox_post() //向消息队列发送消息sys_arch_mbox_fetch() //从消息队列中获取消息uC/OS-II虽然实现了消息队列结构OS_Q及其操作,但是uC/OS-II没有对消息队列中的消息进行管理,因此不能直接使用,必须在uC/OS-II的基础上重新实现。
为了实现对消息的管理,我们定义了以下结构:typedef struct{OS_EVENT *pQ:void *pvQEntries[MAX_QUEUE_ENTRIES];}sys_mbox_t;typedef PQ_DESCR sys_mbox_t; //LwIP中的mbox是UCOS的消息队列该结构包括OS_EVENT类型的队列指针(pQ)和队列内的消息(pvQEntries)两部分,对队列本身的管理利用uC/OS-II自己的消息队列相关函数来完成,然后使用uC/OS-II中的内存管理模块实现对消息的创建、使用和删除,两部分综合起来便实现了LwIP的消息队列功能。
3.2.3 sys_arch_timeout函数LwIP中每个与外界网络连接的线程都有自己的timeout属性,即等待超时时间。
这个属性表现为每个线程都对应一个sys_timeout结构体队列,它包括这个线程的timeout时间长度,以及超时后应调用的timeout函数,该函数会做一些释放连接、回收资源的工作。
timeout结构体已经在sys.h中定义好了,而且对结构体队列的数据操作也由LwIP负责,我们所要实现的是如下函数:struct sys_timeouts *sys_arch_timeouts(void)这个函数的功能是返回目前正处于运行状态的线程所对应的timeout队列指针。
timeout队列属于线程的属性,因此是与操作系统相关的函数,只能由用户实现。
3.2.4 sys_thread_new创建新线程函数LwIP可以是单线程运行,即只有一个tcpip线程(tcpip_thread),负责处理所有的TCP(Transmission Control Protocol:传输控制协议)或UDP(User Datagram Protocol:用户数据报协议)连接,各种网络程序都通过tcpip线程与网络交互。