溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

arm9中斷結(jié)構(gòu)是怎樣的

發(fā)布時間:2021-12-20 10:45:09 來源:億速云 閱讀:151 作者:iii 欄目:互聯(lián)網(wǎng)科技

這篇文章主要講解了“arm9中斷結(jié)構(gòu)是怎樣的”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“arm9中斷結(jié)構(gòu)是怎樣的”吧!

S3C2440的中斷分為兩大類: 外部中斷 和 內(nèi)部中斷.

一 外部中斷

arm9中斷結(jié)構(gòu)是怎樣的

EXTINT[x]: 用來配置各個引腳的中斷觸發(fā)方式 (高電平觸發(fā)、低電平觸發(fā)、下降沿觸發(fā)、上升沿觸發(fā)), 注意該寄存器與中斷源的對應(yīng)關(guān)系

EINTPEND[x]:  xxxPEND的寄存器都是狀態(tài)寄存器, 初始化時先清除標志, 在清除中斷的時候?qū)⒓拇嫫鞯闹蒂x值給本身即可

EINTMSK[x]: 1 屏蔽中斷; 0 未屏蔽

SRCPEND[x]: 1 申請中斷;  0 未申請中斷

EINTFLT0~EINTFLT3: 配置濾波時鐘和濾波寬度

INTMOD[x]: 1: FIQ, 0: IRQ

二 內(nèi)部中斷

內(nèi)部中斷分兩種: 帶子中斷的中斷 和 不帶子中斷的中斷

  1. 不帶子中斷:  發(fā)生中斷后 SRCPEND置位, 如果沒有被 INTMSK屏蔽, 那么繼續(xù)向下一步申請中斷

  2. 帶子中斷: 發(fā)生中斷之后, 先將 SUBSRCPEND 置位, 如果沒有INTSUBMSK屏蔽則向 SRCPEND申請中斷. 如果沒有被INTMSK屏蔽則進一步向下申請中斷

arm9中斷結(jié)構(gòu)是怎樣的

中斷的優(yōu)先級:

ARB_MODEx: 控制中斷優(yōu)先級是否輪轉(zhuǎn)

ARB_SELx: 控制輪轉(zhuǎn)順序

中斷的開啟(xxxMSK):

1 外部中斷: EINT4~23先初始化EINTMSK 和 INTMSK, 如果是EINT0~3直接初始化INTMSK

2 內(nèi)部中斷: 有子中斷先初始化 INTSUBMSK 再初始化 INTMSK, 如果是不帶子中斷的內(nèi)部中斷直接初始化 INTMSK 

中斷的清除(xxxPEND):

1 外部中斷: 如果是EINT4~23 先清除EINTPEND 再清除 INTPEND (注意順序), 如果是 EINT0~3 直接清除SRCPEND.  (不需要清除 INTPEND???)

2 內(nèi)部中斷: 帶子中斷, 先清除 SUBSRCPEND再清除SRCPEND(注意順序);   不帶子中斷直接清除SRCPEND

3 清除中斷是寫 1 清除

三 代碼解析 

@******************************************************************************
@ File:head.S
@ 功能:初始化,設(shè)置中斷模式、管理模式的棧,設(shè)置好中斷處理函數(shù)
@******************************************************************************

.extern     main
.text
.global _start
_start:
@******************************************************************************
@ 中斷向量,本程序中,除Reset和HandleIRQ外,其它異常都沒有使用
@******************************************************************************
    b   Reset

@ 0x04: 未定義指令中止模式的向量地址
HandleUndef:
    b   HandleUndef

@ 0x08: 管理模式的向量地址,通過SWI指令進入此模式
HandleSWI:
    b   HandleSWI

@ 0x0c: 指令預(yù)取終止導(dǎo)致的異常的向量地址
HandlePrefetchAbort:
    b   HandlePrefetchAbort

@ 0x10: 數(shù)據(jù)訪問終止導(dǎo)致的異常的向量地址
HandleDataAbort:
    b   HandleDataAbort

@ 0x14: 保留
HandleNotUsed:
    b   HandleNotUsed

@ 0x18: 中斷模式的向量地址            注意這里由下邊實現(xiàn)
    b   HandleIRQ

@ 0x1c: 快中斷模式的向量地址
HandleFIQ:
    b   HandleFIQ

Reset:
    ldr sp, =4096           @ 設(shè)置棧指針,以下都是C函數(shù),調(diào)用前需要設(shè)好棧
    bl  disable_watch_dog   @ 關(guān)閉WATCHDOG,否則CPU會不斷重啟

    msr cpsr_c, #0xd2       @ 進入中斷模式
    ldr sp, =3072           @ 設(shè)置中斷模式棧指針

    msr cpsr_c, #0xd3       @ 進入管理模式, reset之后就是管理模式, 所以這里的設(shè)置和reset下的ldr sp, =4096為一個作用, 本條代碼可以省略
    ldr sp, =4096           @ 設(shè)置管理模式棧指針,
                            @ 其實復(fù)位之后,CPU就處于管理模式,
                            @ 前面的“l(fā)dr sp, =4096”完成同樣的功能,此句可省略

    bl  init_led            @ 初始化LED的GPIO管腳
    bl  init_irq            @ 調(diào)用中斷初始化函數(shù),在init.c中
    msr cpsr_c, #0x5f       @ 設(shè)置I-bit=0,開IRQ中斷

    ldr lr, =halt_loop      @ 設(shè)置返回地址
    ldr pc, =main           @ 調(diào)用main函數(shù)
halt_loop:
    b   halt_loop

HandleIRQ:
    sub lr, lr, #4                  @ 計算返回地址
    stmdb   sp!,    { r0-r12,lr }   @ 保存使用到的寄存器
                                    @ 注意,此時的sp是中斷模式的sp
                                    @ 初始值是上面設(shè)置的3072

    ldr lr, =int_return             @ 設(shè)置調(diào)用ISR即EINT_Handle函數(shù)后的返回地址
    ldr pc, =EINT_Handle            @ 調(diào)用中斷服務(wù)函數(shù),在interrupt.c中
int_return:
    ldmia   sp!,    { r0-r12,pc }^  @ 中斷返回, ^表示將spsr的值復(fù)制到cpsr

注意: 1. 這里中斷并不是根據(jù)名字來確定的, 而是根據(jù)中斷向量的地址(0x0 / 0x4 / 0x8 / 0xc / 0x10...). IRQ正是0x18. 只需要在該位置放置一條跳轉(zhuǎn)指令即可實現(xiàn)中斷isr.  這是只要是IRQ都要從這一個入口進入中斷, 然后再檢查到底是哪個源申請了中斷.

芯片在各個模式之下使用的是不同的sp和lr寄存器, reset之后就是管理模式, 所以管理模式的ldr sp, =4096是等價于reset下的那條sp語句

// init.c: 初始化LED及 中斷
#include "s3c24xx.h"

// LED1,LED2,LED4對應(yīng)GPF4、GPF5、GPF6
#define	GPF4_out	(1<<(4*2))
#define	GPF5_out	(1<<(5*2))
#define	GPF6_out	(1<<(6*2))

#define	GPF4_msk	(3<<(4*2))
#define	GPF5_msk	(3<<(5*2))
#define	GPF6_msk	(3<<(6*2))

/*
 * S2,S3,S4對應(yīng)GPF0、GPF2、GPG3
 */
#define GPF0_eint     (0x2<<(0*2))
#define GPF2_eint     (0x2<<(2*2))
#define GPG3_eint     (0x2<<(3*2))

#define GPF0_msk    (3<<(0*2))
#define GPF2_msk    (3<<(2*2))
#define GPG3_msk    (3<<(3*2))

// 關(guān)閉WATCHDOG,否則CPU會不斷重啟
void disable_watch_dog(void)
{
    WTCON = 0;  // 關(guān)閉WATCHDOG很簡單,往這個寄存器寫0即可
}

void init_led(void)
{
    // LED1,LED2,LED4對應(yīng)的3根引腳設(shè)為輸出
    GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);
    GPFCON |= GPF4_out | GPF5_out | GPF6_out;
}

/* 初始化GPIO引腳為外部中斷
 * GPIO引腳用作外部中斷時,默認為低電平觸發(fā)、IRQ方式(不用設(shè)置INTMOD)
 */
void init_irq( )
{
    // S2,S3對應(yīng)的2根引腳設(shè)為中斷引腳 EINT0,ENT2
    GPFCON &= ~(GPF0_msk | GPF2_msk);
    GPFCON |= GPF0_eint | GPF2_eint;

    // S4對應(yīng)的引腳設(shè)為中斷引腳EINT11
    GPGCON &= ~GPG3_msk;
    GPGCON |= GPG3_eint;

    // 對于EINT11,需要在EINTMASK寄存器中使能它
    EINTMASK &= ~(1<<11);

    /*
     * 設(shè)定優(yōu)先級:
     * ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2
     * 仲裁器1、6無需設(shè)置
     * 最終:
     * EINT0 > EINT2 > EINT11即K2 > K3 > K4
     */
    PRIORITY &= ((((~0x01) | (0x3<<7))) | (0x0 << 7)) ;

    // EINT0、EINT2、EINT8_23使能
    INTMSK   &= (~(1<<0)) & (~(1<<2)) & (~(1<<5));
}

中斷初始化步驟:

(1) 設(shè)置好 IRQ 和 FIQ 的棧

(2) 準備中斷處理函數(shù)

    1. 異常向量中設(shè)置好跳轉(zhuǎn)函數(shù)

    2. 中斷服務(wù)程序(ISR)

    3. 清除中斷

    4. 保護現(xiàn)場, 恢復(fù)現(xiàn)場

(3) 根據(jù)中斷源設(shè)置相關(guān)外設(shè)

  1. 外部中斷: 設(shè)置引腳為"外部中斷", 設(shè)置中斷觸發(fā)方式, 開啟對應(yīng)的屏蔽寄存器, EINTMSK

  2. 內(nèi)部中斷: 將INTSUBMSK開啟

(4)確定中斷的使用方式: IRQ 或 FIQ

  1. FIQ: 在 INTMOD 設(shè)置相應(yīng)的bit為1

  2. IRQ: 在PRIORITY寄存器中設(shè)置優(yōu)先級, 將 INTMSK中設(shè)置為0 (FIQ不受INTMSK影響)

(5) 置位 CPSR中的 I-bit(IRQ) 或 F-bit(FIQ)

#include "s3c24xx.h"

void EINT_Handle()
{
    unsigned long oft = INTOFFSET;//INTPND[X]為1,則INTOFFSET為x 
    unsigned long val;
    
    switch( oft )
    {
        // S2被按下
        case 0: 
        {   
            GPFDAT |= (0x7<<4);   // 所有LED熄滅
            GPFDAT &= ~(1<<4);      // LED1點亮
            break;
        }
        
        // S3被按下
        case 2:
        {   
            GPFDAT |= (0x7<<4);   // 所有LED熄滅
            GPFDAT &= ~(1<<5);      // LED2點亮
            break;
        }

        // K4被按下
        case 5:
        {   
            GPFDAT |= (0x7<<4);   // 所有LED熄滅
            GPFDAT &= ~(1<<6);      // LED4點亮                
            break;
        }
        
        //K1 或 K2 被按下, 假設(shè)K1 k2 接在EINT8~23, 查詢INTPEND[5]之后還要查詢EINTPEND[x]來確定EINT8~EINT23
        case 5:
        {
            GPBDAT |= (0x0f << 5);//所有LED熄滅
            
            //需要進一步判斷是k1 還是 k2, 或是 同時按下
            val = EINTPEND;
            if (val & (1 << 11))
            {
                GPBDAT &= ~(1 << 6);//K2
            }
            if (val & (1 << 19))
            {
                GPBDAT &= ~(1 << 5);//K1
            }
            break;
        }

        default:
            break;
    }

    //清中斷
    if( oft == 5 )  //如果是外部中斷則要多清除EINTPEND這個寄存器 
        EINTPEND = (1<<11);   // EINT8_23合用IRQ5,SRCPND[5], INTPND[5]
        
    SRCPND = 1<<oft;
    INTPND = 1<<oft;
}

這里oft表示INTOFFSET寄存器的值, INTPND[x]為1, oft就是x. 該值為5表示 EINT8-23的中斷源, 這時再查看 EINTPEND來確定到底是哪個引腳.

感謝各位的閱讀,以上就是“arm9中斷結(jié)構(gòu)是怎樣的”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對arm9中斷結(jié)構(gòu)是怎樣的這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

arm
AI