久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7911|回復: 0
打印 上一主題 下一主題
收起左側

周立功lpc21xx/lpc22xx(ARM7)系列工程模板中中斷嵌套代碼詳解

[復制鏈接]
跳轉到指定樓層
樓主
ID:72519 發表于 2015-1-23 04:02 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
IRQ.S分析
以下是“IRQ.S分析”的部分摘錄
一直想對中斷嵌套有更深層次的了解。原因就在于一個項目中在中斷頻率較高的情況下,又按鍵中斷觸發,有時候會導致死機。
先來看兩個問題:
1.為什么除了進入復位異常模式外,在別的異常處理模式中都允許FIQ中斷?
答:所以FIQ可以用來處理實時性較高或是系統中至關重要的事。
2.數據訪問中止異常的優先級大于FIQ異常,為什么在數據訪問異常處理模式中,還允許   FIQ中斷呢?這樣不就成了:在高優先級異常處理中允許低優先級的中斷發生嗎?即使這樣,因為FIQ中斷的優先級 < 數據異常中斷優先級,也不會進入FIQ中斷處理程序啊,這樣不就更沒有用處了??
答:在高優先級異常處理中允許低優先級的中斷發生,是可以的。(1)如果CPU不支持中斷嵌套,會丟棄低優先級的中斷。(2)如果CPU支持中斷嵌套,低優先級的中斷會被掛起,待退出高優先級后再處理低級中斷。
    這兩個問題說明了各種異常模式也是有優先級的,并且低優先級異常能被高優先級異常中斷。當CPU不支持嵌套時,會丟棄低優先級中斷,支持嵌套時會掛起,等高優先級處理后再處理低優先級。


優先級

異常

1

復位

2

數據異常終止

3

FIQ

4

IRQ

5

預取異常終止

6

未定義指令

7

SWI



RAM7中斷優先級表
既然不支持嵌套的cpu不能被低優先級的中斷打斷,那么為什么arm7tdmi的中斷處理過程會被其他中斷打斷呢?

... ...

簡單描述下這個中斷處理過程:1.計算返回地址 2.保存環境 3.切換到系統模式 4.實際中斷處理 5.切換回IRQ模式 6.恢復環境 7.返回

    這里的動作就像括號一樣層層包圍著實際中斷處理函數,就是為了讓實際中斷處理函數在系統模式下進行,而非irq模式下。正是在系統模式下,中斷才能被新的IRQ打斷,才會造成類似嵌套的效果。


在一般的中斷處理程序中,需要按照以下步驟進行響應:
1.計算返回地址
2.保存會有改變的寄存器組
3.調用實際中斷響應函數
4.恢復寄存器組
5.返回被中斷處
    為了使arm7這類不支持中斷嵌套的cpu能使用中斷嵌套,必須在進入實際中斷響應函數前將cpu模式切換為sys32系統模式,在處理結束后繼續恢復為IRQ模式。因為sys32模式能被IRQ異常模式打斷,所以在中斷處理的過程中仍然能響應新的中斷。
注:原模板中在“Startup.s”中有如下的語句
;Build the SYS stack
;設置系統模式堆棧
        MSR     CPSR_c, #0xdf
        LDR     SP, =StackUsr
        MOV     PC, R0
為了中斷嵌套,需將“MSR     CPSR_c, #0xdf”語句改為“MSR     CPSR_c, #0x5f”,即在系統模式下允許IRQ中斷。(注部分是自己添加的內容)
    所以arm7這類不支持嵌套的cpu的中斷嵌套的響應流程如下:
1.計算返回地址(注意:此時處理器是在IRQ模式下)
2.保存會有改變的寄存器組
3.切換為sys32系統模式
4.調用實際中斷響應函數
5.切換回IRQ模式
6.恢復寄存器組
7.返回被中斷處
實現代碼如下:
IRQ中斷,先保存前一中斷在sys32模式下的處理程序的寄存器組,然后切換到sys32模式,再進入此中斷的響應程序。當處理完此中斷之后,再恢復前一中斷在sys32模式下的寄存器組,直到中斷處理完之后,恢復成程序的寄存器組。
    因此,可以將中斷看作是隨機的函數調用,需要在進入時保存寄存器組,在退出時恢復寄存器組。因為中斷不同于普通的函數調用,同事發生了模式的變化,所以在保存和恢復寄存器組的時候,應該加上CPSR寄存器。又由于arm7在IRQ模式下不能進行中斷嵌套,所以需要切換到sys32模式進行實際的中斷響應。
當發生中斷嵌套時,程序是怎么工作的呢?
-程序0正在正常運行,突然被中斷1打斷后,進入到中斷處理程序。
-保存程序0當中的寄存器組,然后切換到sys32模式,進行中斷1的實際響應。
-此時又允許被中斷,中斷1處理過程中,又被中斷2打斷。
-中斷2響應時候,保存中斷1中斷的寄存器組,進入sys32模式進行中斷2的響應
-當中斷2響應結束后,恢復到中斷1在sys32模式下的響應程序的寄存器狀態
-當中斷1響應結束后,恢復到程序0的寄存器狀態。
要讀懂源碼,還得看ARM匯編偽指令宏的應用。
【轉】ARM匯編偽指令宏的用法詳解(MACRO MEND)


宏是一段獨立的程序代碼,它是通過偽指令定義的,在程序中使用宏指令即可調用宏。當程序被匯編時,匯編程序將對每個調用進行展開,用宏定義取代源程序中的宏指令。

MACRO、MEND

語法格式:

MACRO

[$ label] macroname{ $ parameter1, $ parameter,……    }

指令序列

MEND

MACRO偽操作標識宏定義的開始,MEND標識宏定義的結束。用MACRO及MEND定義一段代碼,稱為宏定義體,這樣在程序中就可以通過宏指令多次調用該代碼段。其中, $ label在宏指令被展開時,label會被替換成相應的符號,通常是一個標號。在一個符號前使用$表示程序被匯編時將使用相應的值來替代$后的符號。macroname為所定義的宏的名稱。$parameter為宏指令的參數。當宏指令被展開時將被替換成相應的值,類似于函數中的形式參數,可以在宏定義時為參數指定相應的默認值。

宏指令的使用方式和功能與子程序有些相似,子程序可以提供模塊化的程序設計、節省存儲空間并提高運行速度。但在使用子程序結構時需要保護現場,從而增加了系統的開銷,因此,在代碼較短且需要傳遞的參數較多時,可以使用宏匯編技術。

首先使用MACRO和MEND等偽操作定義宏。包含在 MACRO 和 MEND 之間的代碼段稱為宏定義體,在MACRO偽操作之后的一行聲明宏的原型(包含宏名、所需的參數),然后就可以在匯編程序中通過宏名來調用它。在源程序被匯編時,匯編器將宏調用展開,用宏定義體代替源程序中的宏定義的名稱,并用實際參數值代替宏定義時的形式參數。宏定義中的$label是一個可選參數。當宏定義體中用到多個標號時,可以使用類似$label.$internallabel的標號命名規則使程序易讀。

MACRO 、 MEND 偽操作可以嵌套使用。

使用示例:

MACRO

$HandlerLabel HANDLER $HandleLabel ;宏的名稱為HANDLER,有1個參數$HandleLabel

$HandlerLabel

sub sp,sp,#4 ;decrement sp(to store jump address)

stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)

ldr     r0,=$HandleLabel;load the address of HandleXXX to r0

ldr     r0,[r0] ;load the contents(service routine start address) of HandleXXX

str     r0,[sp,#4]      ;store the contents(ISR) of HandleXXX to stack

ldmfd   sp!,{r0,pc}     ;POP the work register and pc(jump to ISR)

MEND

;在程序中調用該宏

HandlerFIQ      HANDLER HandleFIQ ;通過宏的名稱HANDLER調用宏,其中宏的標號為HandlerFIQ,參數為HandleFIQ

HandlerIRQ      HANDLER HandleIRQ

HandlerUndef    HANDLER HandleUndef

HandlerSWI     HANDLER HandleSWI

HandlerDabort   HANDLER HandleDabort

HandlerPabort   HANDLER HandlePabort

也許我們會問想格式中的[$ label]到底有什么作用?

當宏定義體內部跳轉時,這個參數會起到至關重要的作用。要想在宏內部跳轉,就必須在宏定義體內部有程序標號如(LOOP),如果不使用參數($ label),當在一個程序段內調用兩次宏的時候,編譯器就會出現錯誤,因為當匯編時產生了兩個相同名字的程序標號。

例子:   

宏的定義體:

MACRO

$PM        DELAY $CanShu

$PM

LDR     R7,=$CanShu   ;

;LDR  R7,[R7] ;此時參數是一個立即數  如果是變量的話 是會用到這一句

$PM.LOOP

SUBS R7,R7,#0X01

BNE   $PM.LOOP

MEND

在程序段中的使用:(使用兩次)

... ...

AA    DELAY 0X000005F0

... ...

BB    DELAY 0X00000FF0

...

此時調用多次,編譯器就不會出現問題,例子中的AA和BB僅僅是一個標號,用戶可以自行書寫,因為在宏指令唄展開時,這個符號在匯編時將使用相應的值替代,0x00000FF0是一個參數 在此處是一個立即數,用戶可自行使用為變量等。

現在進行源碼分析
源碼文件:IRQ.inc
;/****************** Copyright (c)**************************
;**                               廣州周立功單片機發展有限公司
;**                                     研    究    所
;**                                        產品一部
;**
;**                              
;**
;**--------------文件信息--------------------------------
;**文   件   名: IRQ.inc
;**創   建   人: 陳明計
;**最后修改日期: 2004年8月27日
;**描        述: 定義IRQ匯編接口代碼宏
;**
;**--------------歷史版本信息------------------------------
;** 創建人: 陳明計
;** 版  本: v1.0
;** 日 期: 2004年8月27日
;** 描 述: 原始版本
;**
;**--------------當前版本修訂------------------------------
;** 修改人:
;** 日 期:
;** 描 述:
;**
;**----------------------------------------------------------
;************************************** /

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

    CODE32
    AREA    IRQ,CODE,READONLY
    MACRO
$IRQ_Label HANDLER $IRQ_Exception_Function
        EXPORT  $IRQ_Label                       ; 輸出的標號
        IMPORT  $IRQ_Exception_Function         ; 引用的外部標號
$IRQ_Label
        SUB     LR, LR, #4                        ; 計算返回地址
;分析,在執行此指令時,處理器是由于產生了IRQ中斷被迫從其它模式切換到IRQ模式的,此時的PC值是被中斷了的其它模式下的預取指令的地址(由3級流水線導致),是當前執行指令的地址+8(RAM狀態下,Thumb下為+4),當已進入中斷時,LR里面裝的是PC,所以下一條要執行的指令地址就是LR-4(RAM狀態下)。
        STMFD   SP!, {R0-R3, R12, LR}           ; 保存任務環境
;這里為什么只把R0-R3,R12,LR保存呢,其它不用嗎,是這樣的,我們可以從你裝的ADS1.2目錄下的PDF文件夾里面的ADS_DeveloperGuide_D.PDF文件的2.2就可以發現R4-R11裝的是局部變量,在進行函數跳轉時,編譯器它會自動保護它們的。

MRS     R3, SPSR                         ; 保存狀態
        STMFD   SP, {R3, SP, LR}^               ; 保存用戶狀態的R3,SP,LR,注意不能回寫
                                                                         ; 如果回寫的是用戶的SP,所以后面要調整SP
;分析,1.先看看SPSR,在7中模式中,用戶模式和系統模式沒有SPSR,其它模式各有自己的SPSR,它的作用是保存異常發生前的CPSR的值。2.再看看“^”,當在STM中使用時,表示加載的寄存器列表“{R3, SP, LR}”是用戶模式的寄存器,而不是當前模式的寄存器,3.關于回寫,即如果語句是STMFD   SP!, {R3, SP, LR}^,就是多一個感嘆號,對于這個“!”,本人理解是跟C語言的指針后跟“++”或“—”類似,至于是“++”還是“—”取決于STM后面的模式標識。
《ARM嵌入式系統基礎教程——周立功等編著》中有如下一段:
LDF和STM——多寄存器加載/存儲指令(P83)
指令格式:
STM{cond}<模式>  Rn{!},reglist{^}
當Rn在寄存器列表中且使用后追“!”時,對于STM指令,若Rn為寄存器列表中的最低數字寄存器,則會將Rn的初值保存;其它情況下Rn的加載值和存儲值不可預知。(P84)
但看源文件后面的注釋“; 如果回寫的是用戶的SP,所以后面要調整SP”,說明回寫的話保存的是用戶的SP初值,不解???既然跟了“^”,說明兩個SP并非同一個寄存器,“!”跟“^”到底誰是老大,誰說了算啊??
再看“IRQ.S分析”一文中的解釋:
因為寄存器列表中包涵有SP,且第一個操作數寄存器也是SP,雖然意義上不是同一個SP,但是此時如果使用:STMFD   SP!, {R3, SP, LR}^ 回寫SP是不行的,編譯就不會通過,違反了ARM匯編的規則設置。所以要寫成:STMFD   SP, {R3, SP, LR}^   然后后面(注意:好像還不能立刻減回來,要隔個一兩句再減,不然可能有警告!)再把SP減回來:SUB     SP, SP, #4*3而 STMFD   SP!, {R3,LR}^ 用ADS編譯可能會有一個警告,但是功能是對的。
我用H-JTAG + S3C2410 仿真看過
對于出棧的情況也是一樣。
        LDR     R2,  =OSIntNesting               ; OSIntNesting++
        LDRB    R1, [R2]
        ADD     R1, R1, #1
        STRB    R1, [R2]
;分析:以上幾行代碼功能是實現中斷嵌套計數器OSIntNesting +1操作
        SUB     SP, SP, #4*3
;分析:這里就是源文件的注釋“; 如果回寫的是用戶的SP,所以后面要調整SP”的實現,即調整堆棧指針SP的位置。
        MSR     CPSR_c, #(NoInt | SYS32Mode)    ; 切換到系統模式
;分析:只有切換到系統模式,讓后面的服務程序在系統模式下運行,才能實現嵌套,那再一次開中斷又再哪兒進行呢??請看$IRQ_Exception_FunctionC語言要實現中斷嵌套的代碼規則。
        CMP     R1, #1
        LDREQ   SP, =StackUsr
;分析:以上兩句是判斷是否是第一次進入中斷,如果是第一次進入中斷則設定系統模式的堆棧指針。
        BL      $IRQ_Exception_Function         ; 調用c語言的中斷處理程序
;這一句就不再多說了。

;重點說說IRQ_Exception_Function該怎么寫,以下是一個模板,見《μC/OSII下的ARM7中斷過程分析及優化方法》一文。

3 中斷的優化

  改寫μC/OSII 內核中 HANDLER 宏可以實現ARM的中斷嵌套,這樣做雖然提高了系統的實時性,但損害了系統運行的穩定性和可移植性。通過對中斷過程的分析,下面給出一種編寫中斷服務程序的模板,充分利用ISR執行在特權模式——系統模式這一特點來實現中斷嵌套的條件。中斷服務程序模板如下:

void ISR(void)

{

  OS_ENTER_CRITICAL();//在中斷服務程序中關中斷

      /*清中斷標志*/                //防止沒有清中斷標志使得中斷多次進入

      /*禁止低優先級中斷*/         //禁止低優先級中斷

  S_EXIT_CRITICAL();       //在中斷服務程序中開中斷

      VICVectAddr=0;              //將中斷服務程序的入口地址置0

      /*用戶的C語言代碼*/          //進行用戶在中斷中要做的工

}

由于Handler宏中已將LR、SPSR、返回地址和發生中斷前的堆棧指針等寄存器入棧保存,所以接下來要做的就只剩下開關中斷的工作。由于 在進入C中斷處理程序之前進入的是關中斷系統模式,所以必須在C語言中重新打開中斷,而C語言是不能進行寄存器操作的,因此必須調用軟中斷 OS_EXIT_CRITICAL()重新打開中斷。在開中斷之前,要判斷將全局變量OsEnterSum減1后是否為0,所以必須在調用開中斷之前調用 軟中斷OS_ENTER_CRITICAL()將OsEnterSum變成1。在臨界區中可以進行一些處理,如清中斷標志、關低優先級中斷等。進行C語言 中斷服務程序之后要將VICVectAddr置位為0,這是ARM7處理器核的要求必須進行這樣的編寫,否則會導致一些錯誤(如不能第2次進入中斷等)。

實例:

void IRQ_FIFOP(void)
{
    uint32 temp, temp32;

    temp=VICIntEnable;                           // 保存中斷信息
    VICIntEnClr=(1<<16);                        // 禁止當前中斷
    EnableIRQ();                                      // 打開IRQ中斷
    VICVectAddr=0x00;                           // 清除中斷邏輯,以便VIC可以響應更高優先級IRQ中斷

    while( (EXTINT&0x04)!=0 )                 //EINT2 1<<16
    {

          MACISR();

          EXTINT = 0x0F;                           // 清除EINT0中斷標志
    }
  
    VICIntEnable=temp;                           //恢復中斷使能

}

  
MSR     CPSR_c, #(NoInt | SYS32Mode)    ; 切換到系統模式
;因為在執行C語言的中斷響應函數時,還可以響應中斷,處理的模式會發生變化,所以在函數執行完時強制返回到系統模式,做好中斷退出的準備。
;以下的代碼還需結合uCOS來分析。
        LDR     R2, =OsEnterSum                 ; OsEnterSum,使OSIntExit退出時中斷關閉
        MOV     R1, #1
        STR     R1, [R2]
;以上3句語句是給OsEnterSum賦值為1。為什么賦值為1呢?試想想,中斷是怎么嵌套進去的?再一次中斷是在執行$IRQ_Exception_Function函數中有可能(如果發生)被嵌套進去,利用C語言中的括號原理:中斷1—>{中斷2—>(中斷3—>())},這里的大括號就相當于第一次$IRQ_Exception_Function函數執行,當程序跑出$IRQ_Exception_Function時,大括號結束了。所以OsEnterSum只能是1了。
        BL      OSIntExit
;這句關鍵說說OSIntExit與OsEnterSum有何干?OSIntExit里面會調用OS_EXIT_CRITICAL()函數,而OS_EXIT_CRITICAL()是在Os_cpu.h中通過軟件中斷來實現的(__swi(0x03) void OS_EXIT_CRITICAL(void)),再看看軟件中斷代碼:
void SWI_Exception(int SWI_Num, int *Regs)

……
case 0x03:          /* 開中斷函數OS_EXIT_CRITICAL(),參考os_cpu.h文件 */
            if (--OsEnterSum == 0)
            {
                __asm
                {
                    MRS     R0, SPSR
                    BIC     R0, R0, #NoInt
                    MSR     SPSR_c, R0
                }
            }
            break;
……

在代碼中如果--OsEnterSum == 0就給把中斷關了。那豈不是以后就永遠沒發響應中斷了?關鍵是周工的東東使用了uCOS的

#define     OS_CRITICAL_METHOD     2            /* 選擇開、關中斷的方式 */,所以以后能不能再響應中斷去看看uCOS。
        LDR     R2, =OsEnterSum                 ; 因為中斷服務程序要退出,所以OsEnterSum=0
        MOV     R1, #0
        STR     R1, [R2]
;以上3句為OsEnterSum賦值0,為什么要賦值0呢?因為最后一個中斷要退出了,當然沒得數可計了啊!
        MSR     CPSR_c, #(NoInt | IRQ32Mode)    ; 切換回irq模式
;切換到IQR中斷模式,恢復用戶模式的參數。

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                 ; 進行任務切換
    MEND
    END
;/*********************************************************************************************************
;**                            End Of File
;********************************************************************************************************/

不好意思有點亂哦!!!
源碼文件:IRQ.s
;/******************** Copyright (c)*************************
;**            Guangzou ZLG-MCU Development Co.,LTD.
;**                       graduate school
;**                  
;**
;**--------------File Info-------------------------------------------------------------------------------
;** File Name: IRQ.s
;** Last modified Date:  2004-06-14
;** Last Version: 1.1
;** Descriptions: The irq handle that what allow the interrupt nesting.
;**
;**-----------------------------------------------------------------------------------
;** Created By: Chenmingji
;** Created date:   2004-09-17
;** Version: 1.0
;** Descriptions: First version
;**
;**-----------------------------------------------------------------------------------
;** Modified by:
;** Modified date:
;** Version:
;** Descriptions:
;**
;************************************************************ /

               INCLUDE         ..\..\arm\irq.inc            ; Inport the head file 引入頭文件
    CODE32
    AREA    IRQ,CODE,READONLY
;/* 以下添加中斷句柄,用戶根據實際情況改變 */
;/* Add interrupt handler here,user could change it as needed */

;/*中斷*/
;/*Interrupt*/
IRQ_Handler    HANDLER IRQ_Exception

;/*定時器0中斷*/
;/*Time0 Interrupt*/
Timer0_Handler  HANDLER Timer0_Exception
    END
;/*********************************
;**                            End Of File
;********************************* /



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美午夜一区二区三区免费大片 | 日日爱夜夜操 | 欧美成年人视频在线观看 | 一区二区三区免费 | 一区二区视频 | 亚洲国产欧美在线人成 | 中文字幕一区在线观看视频 | 欧美a区| av天天爽| 中文字幕亚洲视频 | 午夜精品视频 | 欧美成人激情 | www久久 | 久久九| av二区三区 | 欧美午夜精品久久久久免费视 | 一区二区三区欧美 | 国产成人精品在线播放 | 精品一区二区av | 久久久久国产一区二区三区四区 | 国产成人福利视频 | 欧美日韩国产一区二区三区 | 狠狠操狠狠搞 | 伊人久久精品一区二区三区 | 中文字幕在线视频网站 | 日本精品在线一区 | 香蕉视频在线播放 | 日韩一二三区视频 | 国产清纯白嫩初高生在线播放视频 | 久久大陆 | 精品日韩一区 | 一级a性色生活片久久毛片 一级特黄a大片 | 久久久久久久亚洲精品 | 国产福利91精品一区二区三区 | 99精品视频免费在线观看 | 国产视频一区在线 | 99精品久久久国产一区二区三 | 黄色高清视频 | 精品一级电影 | 国产精品一区视频 | 色吧综合 |