基于Nios软核CPU的uCOS-II和LwIP移植

合集下载

uCOS平台下的LwIP移植非常详细

uCOS平台下的LwIP移植非常详细

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在开发环境下的移植工作,包括底层驱动的编写。

LwIP在嵌入式Nios Ⅱ软核处理器上的移植及应用

LwIP在嵌入式Nios Ⅱ软核处理器上的移植及应用
移 植 L P, 此 , 使 用 L P, 须 建 立 基 于 wI 因 要 wI 必
IC/ — U RTOS 的 C/  ̄ OS 上 C++项 目 .l r对 As I 件 抽 象 层 HA 通 wl o I硬 L
件 用 网 络 设 备 模 式 的 . 过 这 个 模 式 , 们 可 以 圆 琏 通 我
元 泽 怀
( 庆 学 院 电 子 信 息 与 机 电 工 程 学 院 ,广 东 肇 庆 肇 56 6) 2 0 1
摘 要 : o I 专 门 为 S C1 t的 一 种 软 核 CP , 以 I 核 的 形 式 提 供 给 嵌 入 式 设 计 者 . 的 可 配 置 特 Nis 是 I OP  ̄ ̄ U 它 P 它
网络协议lwiplightweightintemetprotoc01即轻量级网络协议是一种专门针对嵌入式系统应用而设计的网络通信协议lwip实现的重点是在保持tcpip协议主要功能的基础上减少对ram的占用一般它只需要几十kbyte的ram和40kbyte左右的rom就可以运行非常适合在以niosii处理器为核心的系统中使用
数 据 通 道 的 嵌 入 式 系 统 微 处 理 器 I 核 , 用 a a n 线 结 构 P软 采 vl 总 o 通 信 接 V , 有 增 强 的 内 存 调 试 和 软 件 功 能 , 可 以 与 各 种 外 I带 它 设 相 结 合 , 成 一 个 可 定 制 的 可 编 程 片 上 系 统 S C( ytm 构 OP S s e On a Po rmal hp)网 络 协 议 L P( ih i t It n t rga be C i . wI Lg t we h ne e g r
关 键 词 : wl L P;Nis I o I;嵌 入 式 系 统 ; IC/ I x OS I

ucos_II移植总结

ucos_II移植总结

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();}第五步:对移植好的代码进行调试。

基于μC/OS—Ⅱ的LwIP协议栈的移植与改进

基于μC/OS—Ⅱ的LwIP协议栈的移植与改进
2 0 1 2年 8月 2 8日收 到
源十分有限的嵌入式系统中。
传统的 T C P / I P进 程 模 型 有 两 种 : 一 种 是 每 个 协议都 是一 个单独 的进 程 , 另 外 一 种是 所 有 的 协 议 都 驻 留在 操 作 系 统 内核 里 。 前 一 种 模 型 的优 势 是
关键词
T C / O S 文献标志码
A R M A
中图法分类号
T P 3 9 3 . 0 4 ;
在 网络迅 猛发 展 的今 天 , 以太 网 以其 优 良的性
能和灵活性迅速普及。通讯 、 消费电子等各式各样 的嵌入式设备要接人 以太 网, 都需要部分或是完整 地实现 T C P / I P协议, 而 目前嵌 人式系统大部分使 用经济 型 处理 器 , 受 内存 和速 度 限制 , 不 适 合将 T C P / I P 协议直接移植到此类嵌 入式 系统 。现介 绍
系统 中。介绍并分析轻量级 T C P / I P协议 栈 L w l P一 ( L i g h t w e i g h t I n t e r n e t P r o t o c o 1 ) 在A R M 7中的移植方法 , 并针 对嵌入 式系统
对 实时性的要求对协议 的实时性进行 了改进。
5 1 7
很 大 。后一 种 是 w i n d o w s采 用 的 方 式 , 应 用 程 序 通
大的不同是 P B U F — R O M 的数据存储在 p b u f 子系统
不 能管 理 的存 储 区。P B U F — P O O L是 从 p b u f 池中申
过系统调用与协议栈通信 , 所以减少 了进程切换的 开销 , 但 由于与内核密切关联 , 可移植性较差 。

μCOS-II-下-LwIP-协议栈的移植和测试

μCOS-II-下-LwIP-协议栈的移植和测试

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系统中的移植

LwIP协议栈在NIOS II系统中的移植

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], 冯伟; 吕亚方; 滕飞; 王亮亮
因版权原因,仅展示原文概要,查看原文内容请购买。

NiosII下UCOS和移植Linux教程(中文)

NiosII下UCOS和移植Linux教程(中文)

实验五 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(一)

一步步移植uCOS-IIandLwIP(一)

一步步移植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。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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线程与网络交互。

相关文档
最新文档