微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM硬件平台上基于UCOS移植Lwip网络协议栈

ARM硬件平台上基于UCOS移植Lwip网络协议栈

时间:11-20 来源:互联网 点击:

3.7 中断级任务切换

当系统任务延时时间到或者在中断服务程序里抛出信号量、邮箱等可以产生系统调度的操作时,会执行任务切换,但这种切换是在中断模式下进行的。但底层切换函数是一致的,只不过任务级任务切换时是在SVC模式下进行,中断级任务切换是在中断模式下进行。
下面我们分析中断级任务切换的主要流程和代码:
SUB LR, LR, #4 ; 计算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任务环境
MRS R3, SPSR ; 保存状态
STMFD SP, {R3,SP, LR}^; 保存用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R2, =OSIntNesting ; OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]

SUB SP, SP, #4*3

MSR CPSR_c, #(NoInt :OR: SYS32Mode) ; 切换到系统模式
CMP R1, #1
LDREQ SP, =StackUsr

BL $IRQ_Exception_Function ; 调用c语言的中断处理程序

MSR CPSR_c, #(NoInt :OR: SYS32Mode) ; 切换到系统模式
LDR R2, =OsEnterSum; OsEnterSum,使OSIntExit退出时中断关闭
MOV R1, #1
STR R1, [R2]

BL OSIntExit

LDR R2, =OsEnterSum; 因为中断服务程序要退出,
;所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]

MSR CPSR_c, #(NoInt :OR: IRQ32Mode) ; 切换回irq模式
LDMFD SP, {R3,SP, LR }^ ; 恢复用户状态的R3,SP,LR,
;注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1

ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换

代码主要功能分析:
实现在中断模式下保存系统模式下正在运行任务的各个寄存器到中断模式堆栈,然后执行相应的中断服务程序,中断退出时做任务切换。
下面我们分析实现任务切换的函数OSIntCtxSw。
OSIntCtxSw
;下面为保存任务环境
LDR R2, [SP, #20] ;获取PC
LDR R12, [SP, #16] ;获取R12
MRS R0, CPSR

MSR CPSR_c, #(NoInt :OR: SYS32Mode)
MOV R1, LR
STMFD SP!, {R1-R2} ;保存LR,PC
STMFD SP!, {R4-R12} ;保存R4-R12

MSR CPSR_c, R0
LDMFD SP!, {R4-R7} ;获取R0-R3
ADD SP, SP, #8 ;出栈R12,PC

MSR CPSR_c, #(NoInt :OR: SYS32Mode)
STMFD SP!, {R4-R7} ;保存R0-R3

LDR R1, =OsEnterSum ;获取OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3} ;保存CPSR,OsEnterSum

;保存当前任务堆栈指针到当前任务的TCB
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1]
BL OSTaskSwHook ;调用钩子函数
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4]
上述函数实现了保存上一个被中断任务运行时各个寄存器到任务的堆栈空间里,然后将系统中优先级最高且就绪的任务堆栈里保存的各个寄存器内容恢复到系统模式的各个寄存器中,使任务正常运行。

4.Lwip移植

4.1 lwip简介

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。LwIP是Light Weight (轻型)IP协议,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。

4.2 lwip移植总述

Lwip有无操作系统的支持都可以运行,我们移植是基于UCOS的。
基于UCOS移植Lwip主要包含两个方面的工作:
1. 根据Lwip提供的操作系统模拟层接口编写基于UCOS的实现代码,以实现Lwip和UCOS的完美融合。
2. 根据Lwip提供的底层网卡驱动接口,结合RTL8019AS网卡datasheet编制网卡驱动程序。

4.3移植lwip操作系统模拟层

操作系统模拟层(sys_arch)存在的目的主要是为了方便 LwIP 的移植,它在底层操作系统和LwIP 之间提供了一个接口。这样,我们在移植 LwIP 到一个新的目标系统时,只需修改这个接口即可。不过,不依赖底层操作系统的支持也可以实现这个接口。
sys_arch需要为LwIP提供创建新线程功能,提供信号量 (semaphores) 和邮箱 (mailboxes) 两种进程间通讯方式 (IPC) 。
1. 模拟层需要添加的头文件 cc.h 说明
Lwip使用的数据类型定义:
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned int u32_t;
typedef signed int s32_t;
typedef unsigned int sys_prot_t;
typedef unsigned int mem_ptr_t;
lwip使用的结构体对齐方式声明相关的宏定义:
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_END
为方便操作协议帧数据,lwip协议栈中结构体使用单字节对齐方式。
处理器模式:
#define BYTE_ORDER LITTLE_ENDIAN
我们使用的LPC2220为小端模式处理器,故定义为小端模式。
其他内容主要和调试输出功能有关,这里不进行一一说明。
2. 需要实现的操作系统模拟层函数
- void sys_init(void)

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top