打印

LPC2103 怎么开关全局中断

[复制链接]
4663|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
6019赵文|  楼主 | 2010-3-19 18:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
S3C2440| | 2010-3-19 18:08 | 只看该作者
user模式下是不允许改变cprs的I和F两个位的,要转换到特权模式下。
一般是使用软件中断来实现,自己定义SWI函数,使用4个中断号分别对应IRQ/FIQ的Enable和Disable。
然后在启动代码里把SWI Handle的内容修改,处理流程大概如下:
1. 入栈,保护LR和接下来要用到的通用寄存器
2. 读取spsr,判断调用SWI指令的是ARM状态还是Thumb状态
3. 根据第2点的结果计算SWI指令的地址(ARM下是LR-4,Thumb下是LR-2),把该地址的内容读出来
   (既是SWI指令的机器码)
4. 根据第3点的结果获得中断号(ARM下是第23~0位,Thumb下是7~0位)
5. 由中断号来跳转到对应的处理程序,进行开/关中断操作(既是修改spsr的I和F位)
6. 出栈,恢复第1点保护的通用寄存器的LR(LR出栈时直接给PC就能返回user了)

使用特权

评论回复
板凳
6019赵文|  楼主 | 2010-3-19 18:09 | 只看该作者
LS兄弟讲的很清楚,可是我还是不知道该具体怎么设置。
小弟以前是做单片机的,搞ARM还不到三个月。
能不能再讲的详细点,最好写上程序,让我复制粘贴就OK了,呵呵!

使用特权

评论回复
地板
QQAI| | 2010-3-19 18:10 | 只看该作者
用的是什么编译器?在GCC里面有这个函数的汇编原型,可以直接用,后移植到ADS、KEIL下都正常。

使用特权

评论回复
5
S3C2440| | 2010-3-19 18:10 | 只看该作者
下面是realview MDK自带的example

T_Bit           EQU     0x20

                PRESERVE8                      ; 8-Byte aligned Stack
                AREA    SWI_Area, CODE, READONLY
                ARM

                EXPORT  SWI_Handler
SWI_Handler   

                STMFD   SP!, {R12, LR}         ; Store R12, LR
                MRS     R12, SPSR              ; Get SPSR
                STMFD   SP!, {R8, R12}         ; Store R8, SPSR
                TST     R12, #T_Bit            ; Check Thumb Bit
                LDRNEH  R12, [LR,#-2]          ; Thumb: Load Halfword
                BICNE   R12, R12, #0xFF00      ;        Extract SWI Number
                LDREQ   R12, [LR,#-4]          ; ARM:   Load Word
                BICEQ   R12, R12, #0xFF000000  ;        Extract SWI Number

                LDR     R8, SWI_Count
                CMP     R12, R8
                BHS     SWI_Dead               ; Overflow
                ADR     R8, SWI_Table
                LDR     R12, [R8,R12,LSL #2]   ; Load SWI Function Address
                MOV     LR, PC                 ; Return Address
                BX      R12                    ; Call SWI Function  

                LDMFD   SP!, {R8, R12}         ; Load R8, SPSR
                MSR     SPSR_cxsf, R12         ; Set SPSR
                LDMFD   SP!, {R12, PC}^        ; Restore R12 and Return

SWI_Dead        B       SWI_Dead               ; None Existing SWI

SWI_Cnt         EQU    (SWI_End-SWI_Table)/4
SWI_Count       DCD     SWI_Cnt

                IMPORT  __SWI_0
                IMPORT  __SWI_1
                IMPORT  __SWI_2
                IMPORT  __SWI_3
SWI_Table
                DCD     __SWI_0                ; SWI 0 Function Entry
                DCD     __SWI_1                ; SWI 1 Function Entry
                DCD     __SWI_2                ; SWI 2 Function Entry
                DCD     __SWI_3                ; SWI 3 Function Entry
;               ...
SWI_End


                END


自己添加4个SWI函数就行了(但要注意这段代码是保护了spsr的),类似于这样:
__SWI_0   ;disable IRQ
          MRS    r0,spsr
          ORR    r0,r0,#I_bit
          MSR    spsr_c,r0
          MOVS   PC,LR


自己要定义I_bit和F_bit,还要保护r0.我也不确定能不能用,你最好试一下吧

使用特权

评论回复
6
6019赵文|  楼主 | 2010-3-19 18:11 | 只看该作者
我用的是Keil。
感谢两位的帮助!
我试试先。

使用特权

评论回复
7
QQAI| | 2010-3-19 19:32 | 只看该作者
本帖最后由 QQAI 于 2010-3-19 19:34 编辑

我用的就是realview MDK 3.24版本的,但没有看到S3C2440l兄讲的example。
GCC没有用过。

使用特权

评论回复
8
S3C2440| | 2010-3-19 19:35 | 只看该作者
startup.s里对swi的处理做些修改:把原来的SWI_Handler注释掉,import swi_handler(新标号在swi.s中)。你可能是没有修改startup.s
中的swi处理程序入口,导致进入死循环。

                AREA    RESET, CODE, READONLY
                ARM

Vectors         LDR     PC, Reset_Addr         
                LDR     PC, Undef_Addr
                LDR     PC, SWI_Addr
                LDR     PC, PAbt_Addr
                LDR     PC, DAbt_Addr
                NOP                            ; Reserved Vector  
;               LDR     PC, IRQ_Addr
                LDR     PC, [PC, #-0x0FF0]     ; Vector from VicVectAddr
                LDR     PC, FIQ_Addr

IMPORT SWI_Handler

Reset_Addr      DCD     Reset_Handler
Undef_Addr      DCD     Undef_Handler
SWI_Addr        DCD     SWI_Handler
PAbt_Addr       DCD     PAbt_Handler
DAbt_Addr       DCD     DAbt_Handler
                DCD     0                      ; Reserved Address  
IRQ_Addr        DCD     IRQ_Handler
FIQ_Addr        DCD     FIQ_Handler

Undef_Handler   B       Undef_Handler
;SWI_Handler     B       SWI_Handler
PAbt_Handler    B       PAbt_Handler
DAbt_Handler    B       DAbt_Handler
IRQ_Handler     B       IRQ_Handler
FIQ_Handler     B       FIQ_Handler


新建的swi.s文件如下
I_Bit           EQU     0x80
F_Bit           EQU     0x40
T_Bit           EQU     0x20

                AREA    SWI_Area, CODE, READONLY
                ARM
PRESERVE8

EXPORT SWI_Handler            ; 供startup.s调用

SWI_Handler STMFD SP!, {R8, R12, LR}
MRS R12, SPSR
TST R12, #T_Bit            ; 判断是SWI指令是处于哪种状态下
                LDREQ   R12, [LR,#-4]          ; ARM:   Load Word
                BICEQ   R12, R12, #0xFF000000  ; 获取中断号
LDRNEH  R12, [LR,#-2]          ; Thumb: Load Halfword
                BICNE   R12, R12, #0xFF00      ; 获取中断号
LDR     R8, SWI_Count
                CMP     R12, R8                ; 判断中断号是否溢出
                BHS     SWI_Overflow
                ADR     R8, SWI_Table
                LDR     R12, [R8,R12,LSL #2]   ; Load SWI Function Address
                MOV     LR, PC                 ; Return Address
                BX      R12                    ; Call SWI Function  
                LDMFD   SP!, {R8, R12, PC}^        ; Restore R12 and Return

SWI_Overflow    B       SWI_Overflow               ; None Existing SWI

SWI_Cnt         EQU    (SWI_End-SWI_Table)/4
SWI_Count       DCD     SWI_Cnt


SWI_Table
                DCD     __SWI_0                ; SWI 0 Function Entry
                DCD     __SWI_1                ; SWI 1 Function Entry
SWI_End

; Enable IRQ
__SWI_0 MRS R0, SPSR
BIC R0, R0, #I_Bit
MSR SPSR_c, R0
BX LR

; Disable IRQ
__SWI_1 MRS R0, SPSR
ORR R0, R0, #I_Bit
MSR SPSR_c, R0
BX LR

END




在main函数前定义swi函数
void __swi(0) IRQ_Enable( void );
void __swi(1) IRQ_Disable( void );

然后就可以直接IRQ_Enable( )和IRQ_Disable( )来开关中断了。

使用特权

评论回复
9
huzixian| | 2010-3-19 19:38 | 只看该作者
清看门狗时必须关闭中断,否则程序会莫名其妙的复位。这是我当时遇到的第一个问题,解决办法是不用看门狗。

使用特权

评论回复
10
linux1| | 2010-3-19 19:39 | 只看该作者
本帖最后由 linux1 于 2010-3-19 19:44 编辑

LZ注意


进入一个中断后要关闭全局中断,如果两个中断同时来的话程序会跑飞。
   这样写可能不准确,我当时的问题是用了两个中断,一个是timer0的定时5mS中断,另一个是RTC的秒中断,然后程序会跑飞,但并不是每次运行程序就跑飞,有时候运行一天也没事,但批量以后会表现出来。解决办法是用5mS中断累计1秒,然后读RTC的寄存器。

使用特权

评论回复
11
年轻不在| | 2010-3-19 19:40 | 只看该作者
本帖最后由 年轻不在 于 2010-3-19 19:42 编辑

LZ注意片上RTC功耗不稳定,并不是手册上宣称的uA_级,一块纽扣电池(CR1220)一般一两个月甚至一二十天就用完了。而RTC的电源引脚必须接3.3V,电池用完后芯片就不能启动,客户就抱怨产品坏了。解决办法是RTC的电源引脚接3.3V,增加一个DS1302,每次程序启动后先把1302的时间读到RTC中,然后在RTC中读取时间,这样读内部的时钟速度上会快一点,也更加稳定。

使用特权

评论回复
12
思行合一| | 2010-3-19 19:41 | 只看该作者
LZ注意烧写软件“LPC2000 Flash Utility”很差的。晶振是11.0592M时软件上的波特率要用57600,晶振是10M时软件上的波特率要用38400。

使用特权

评论回复
13
shanghaiowen| | 2015-1-30 11:30 | 只看该作者
说得挺详细,正好在写SWI_HANDLER,对理解有帮助

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

350

主题

1515

帖子

1

粉丝