Chinaunix首页 | 论坛 | 博客
  • 博客访问: 699765
  • 博文数量: 255
  • 博客积分: 5000
  • 博客等级: 大校
  • 技术积分: 2811
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-09 13:29
个人简介

IT业行者,行者无疆

文章分类

全部博文(255)

文章存档

2011年(121)

2010年(134)

我的朋友

分类: 嵌入式

2010-09-27 09:17:15

ARM在UC/OS II的移植日记(连载6)

 
http://fangheng1005.blog.163.com/blog/static/32912972008530104252472/

最近在学习TCP/IP协议,很是复杂,以前也没有正式的看过人家写过的代码,所以学习还是有一定的难度的,不过有信心,呵呵,所以最近很难,不过我要加紧把ARM相关的文章写完,然后计划在很快的时间内写一篇TCP/IP协议的移植代码及原理,如何使用等等,好的,来进行今天的移植工作吧。

IRQ.s文件    

 INCLUDE  ..\..\arm\irq.inc   ; Inport the head file 引入头文件

这个文件是一个很关键的头文件,里面有嵌入式中断的代码,实现了中断如何嵌套,下面会进行详细的分析

    CODE32

通知这个是32位的代码,因为在进入异常之后ARM内核是要进行32位模式的,所以这里的代码必须是32位的代码,否则后果将是相当的严重的,不是危言耸听哦,呵呵。

    AREA    IRQ,CODE,READONLY

不用再解析了吧?看连载5有


;
;

;
;
IRQ_Handler HANDLER IRQ_Exception  ;//需要系统管理的嵌套的中断在这里定义


;
;
Timer0_Handler  HANDLER Timer0_Exception

 

需要操作系统管理的中断必须再这里定义,这里定义了一个宏,专为中断嵌套编写的一个宏,因为ARM内核在进入中断之后默认是禁止中断的,故我们要通过一种技术实现中断的嵌套。

    END
;

 

 

 

IRQ.inc文件

NoInt       EQU 0x80

USR32Mode   EQU 0x10
SVC32Mode   EQU 0x13
SYS32Mode   EQU 0x1f
IRQ32Mode   EQU 0x12
FIQ32Mode   EQU 0x11

以上是定义一些常量
;引入的外部标号在这声明
IMPORT  OSIntCtxSw                      ;任务切换函数
IMPORT  OSIntExit                       ;中断退出函数
IMPORT  OSTCBCur
IMPORT  OSTCBHighRdy
IMPORT  OSIntNesting                    ;中断嵌套计数器
IMPORT  StackUsr
IMPORT  OsEnterSum

凡是在这个文件里使用的标号,且没有在这个文件定义的必须用 IMPORT  关键词进行修饰

    CODE32

    AREA    IRQ,CODE,READONLY

    MACRO
$IRQ_Label HANDLER $IRQ_Exception_Function

代表这里是定义一个宏

        EXPORT  $IRQ_Label                      ; 输出的标号
IMPORT  $IRQ_Exception_Function         ; 引用的外部标号

$IRQ_Label

只要你定义了需要系统管理的中断,那么只要这些中断发生之后都会第一时间进入这段代码,我们可以这么理解,其实zlg的中断潜入实现的方法是这样的,就是当中断发生的时候,统一进入一个入口代码,然后在这个入口代码做一些环境的保护,然后重新允许中断,执行用户需要的中断服务函数,这个函数是在系统模式开中断执行的,所以这里是可以进入中断的,这个服务函数执行完了之后,再返回到这段代码,进行一些环境的恢复,然后就是是否切换任务啦,等等的动作,要根据 UC/OS的要求来书写中断返回的代码。
       SUB     LR, LR, #4                      ; 计算返回地址

计算返回地址,就是中断的返回地址啦
       STMFD   SP!, {R0-R3, R12, LR}           ; 保存任务环境

为什么只保存这几个参数??你可以参照ADS编译器的函数调用过程中的参数传递过程,R0-R3是用来函数调用中传递参数的,R12是进行运算用的,LR是函数调用中返回地址保存的。这里的SP值是要更新,就是SP保存好之后SP的指针自动调整
MRS     R3, SPSR                        ; 保存状态

在进入IRQ中断后,原来那个模式下的CPSR会复制到IRQ中断的SPSR中,所以这里保护的是CPSR的值
STMFD   SP, {R3, SP, LR}^               ; 保存用户状态的R3,SP,LR,注意不能回写

记住,这里有一个^标号,这里的SP还是IRQ模式的SP,但是大括号里面的数据是系统模式的寄存器,所以这段代码的意思是保护系统模式的CPSR值,SP 值,就是系统模式的SP,还有LR值,系统模式的LR值与这里IRQ模式的LR值是不一样的,因为我们的中断服务函数是在系统模式下开中断执行的,所以必须保护系统模式的LR值,否则会使中断返回后出错的,这里IRQ模式的SP是不回写的。

我们来解释另一个问题,IRQ_STACK_LEGTH         EQU         9*8             ;every layer need 9 bytes stack , permit 8 layer .每层嵌套需要9个字堆栈,允许8层嵌套

还记得这段代码吗??为什么一个中断嵌套就9个字,在上面的指令中总共使用了9个IRQ模式的SP空间,呵呵,看明白了吧??

                                               ; 如果回写的是用户的SP,所以后面要调整SP
LDR     R2,  =OSIntNesting              ; OSIntNesting++
LDRB    R1, [R2]
ADD     R1, R1, #1
STRB    R1, [R2]

实现OSIntNesting++,这个变量是操作系统管理中断的依据,要求在中断中必须加1

        SUB     SP, SP, #4*3

上面保护了三个字的数据还没有调整SP指针呢。这里调整

        MSR     CPSR_c, #(NoInt | SYS32Mode)    ; 切换到系统模式
CMP     R1, #1

这个指令很关键,实现了中断的嵌套。R1中保存的是OSIntNesting的当前值,已经进行了加1处理,当OSIntNesting这个变量是1的时候,所以这是第一层的中断,第一层中断才执行下面的指令,堆栈初始化,如果不是第一层就不需要了,因为已经在第一层初始化过了
   LDREQ   SP, =StackUsr

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

这个才是用户,也就是我们中断服务函数了,返回后执行下面的代码

        MSR     CPSR_c, #(NoInt | SYS32Mode)    ; 切换到系统模式

防止在中断服务函数中修改了ARM的模式,代码能走到这所以已经没有中断嵌套了,这是最后一层中断
  LDR     R2, =OsEnterSum                 ; OsEnterSum,使OSIntExit退出时中断关闭
MOV     R1, #1
STR     R1, [R2]

OsEnterSum 赋值1,为什么是1呢??感觉这是zlg没有作用的代码,这是因为在OSIntExit函数中,调用了关中断宏,记得这个关中断宏吗?里面有对OsEnterSum 的操作,这里的目的是为了实现调用OSIntExit函数后不要误开了中断。

        BL      OSIntExit

        LDR     R2, =OsEnterSum                 ; 因为中断服务程序要退出,所以OsEnterSum=0

        MOV     R1, #0
STR     R1, [R2]

为了防止出现其他的错误,必须强行的置零

        MSR     CPSR_c, #(NoInt | 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

比较OSTCBHighRdy和OSTCBCur,如果不相等则代表要马上进行任务切换了

        ADD     SP, SP, #4*3                    ; 调整SP的值,因为在上面恢复了三个用户模式的数据
MSR     SPSR_cxsf, R3

复制CPSR的值到SPSR中,因为IRQ中断返回的时候是会进行SPSR复制到CPSR的动作的
        LDMEQFD SP!, {R0-R3, R12, PC}^          ; 不进行任务切换
LDR     PC, =OSIntCtxSw                 ; 进行任务切换
MEND

宏定义结束

    END
;

(待续连载7)

阅读(646) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~