您好,登錄后才能下訂單哦!
這篇文章主要講解了“arm9中斷結構是怎樣的”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“arm9中斷結構是怎樣的”吧!
S3C2440的中斷分為兩大類: 外部中斷 和 內部中斷.
EXTINT[x]: 用來配置各個引腳的中斷觸發方式 (高電平觸發、低電平觸發、下降沿觸發、上升沿觸發), 注意該寄存器與中斷源的對應關系
EINTPEND[x]: xxxPEND的寄存器都是狀態寄存器, 初始化時先清除標志, 在清除中斷的時候將寄存器的值賦值給本身即可
EINTMSK[x]: 1 屏蔽中斷; 0 未屏蔽
SRCPEND[x]: 1 申請中斷; 0 未申請中斷
EINTFLT0~EINTFLT3: 配置濾波時鐘和濾波寬度
INTMOD[x]: 1: FIQ, 0: IRQ
內部中斷分兩種: 帶子中斷的中斷 和 不帶子中斷的中斷
不帶子中斷: 發生中斷后 SRCPEND置位, 如果沒有被 INTMSK屏蔽, 那么繼續向下一步申請中斷
帶子中斷: 發生中斷之后, 先將 SUBSRCPEND 置位, 如果沒有INTSUBMSK屏蔽則向 SRCPEND申請中斷. 如果沒有被INTMSK屏蔽則進一步向下申請中斷
中斷的優先級:
ARB_MODEx: 控制中斷優先級是否輪轉
ARB_SELx: 控制輪轉順序
中斷的開啟(xxxMSK):
1 外部中斷: EINT4~23先初始化EINTMSK 和 INTMSK, 如果是EINT0~3直接初始化INTMSK
2 內部中斷: 有子中斷先初始化 INTSUBMSK 再初始化 INTMSK, 如果是不帶子中斷的內部中斷直接初始化 INTMSK
中斷的清除(xxxPEND):
1 外部中斷: 如果是EINT4~23 先清除EINTPEND 再清除 INTPEND (注意順序), 如果是 EINT0~3 直接清除SRCPEND. (不需要清除 INTPEND???)
2 內部中斷: 帶子中斷, 先清除 SUBSRCPEND再清除SRCPEND(注意順序); 不帶子中斷直接清除SRCPEND
3 清除中斷是寫 1 清除
@****************************************************************************** @ File:head.S @ 功能:初始化,設置中斷模式、管理模式的棧,設置好中斷處理函數 @****************************************************************************** .extern main .text .global _start _start: @****************************************************************************** @ 中斷向量,本程序中,除Reset和HandleIRQ外,其它異常都沒有使用 @****************************************************************************** b Reset @ 0x04: 未定義指令中止模式的向量地址 HandleUndef: b HandleUndef @ 0x08: 管理模式的向量地址,通過SWI指令進入此模式 HandleSWI: b HandleSWI @ 0x0c: 指令預取終止導致的異常的向量地址 HandlePrefetchAbort: b HandlePrefetchAbort @ 0x10: 數據訪問終止導致的異常的向量地址 HandleDataAbort: b HandleDataAbort @ 0x14: 保留 HandleNotUsed: b HandleNotUsed @ 0x18: 中斷模式的向量地址 注意這里由下邊實現 b HandleIRQ @ 0x1c: 快中斷模式的向量地址 HandleFIQ: b HandleFIQ Reset: ldr sp, =4096 @ 設置棧指針,以下都是C函數,調用前需要設好棧 bl disable_watch_dog @ 關閉WATCHDOG,否則CPU會不斷重啟 msr cpsr_c, #0xd2 @ 進入中斷模式 ldr sp, =3072 @ 設置中斷模式棧指針 msr cpsr_c, #0xd3 @ 進入管理模式, reset之后就是管理模式, 所以這里的設置和reset下的ldr sp, =4096為一個作用, 本條代碼可以省略 ldr sp, =4096 @ 設置管理模式棧指針, @ 其實復位之后,CPU就處于管理模式, @ 前面的“ldr sp, =4096”完成同樣的功能,此句可省略 bl init_led @ 初始化LED的GPIO管腳 bl init_irq @ 調用中斷初始化函數,在init.c中 msr cpsr_c, #0x5f @ 設置I-bit=0,開IRQ中斷 ldr lr, =halt_loop @ 設置返回地址 ldr pc, =main @ 調用main函數 halt_loop: b halt_loop HandleIRQ: sub lr, lr, #4 @ 計算返回地址 stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 @ 注意,此時的sp是中斷模式的sp @ 初始值是上面設置的3072 ldr lr, =int_return @ 設置調用ISR即EINT_Handle函數后的返回地址 ldr pc, =EINT_Handle @ 調用中斷服務函數,在interrupt.c中 int_return: ldmia sp!, { r0-r12,pc }^ @ 中斷返回, ^表示將spsr的值復制到cpsr
注意: 1. 這里中斷并不是根據名字來確定的, 而是根據中斷向量的地址(0x0 / 0x4 / 0x8 / 0xc / 0x10...). IRQ正是0x18. 只需要在該位置放置一條跳轉指令即可實現中斷isr. 這是只要是IRQ都要從這一個入口進入中斷, 然后再檢查到底是哪個源申請了中斷.
芯片在各個模式之下使用的是不同的sp和lr寄存器, reset之后就是管理模式, 所以管理模式的ldr sp, =4096是等價于reset下的那條sp語句
// init.c: 初始化LED及 中斷 #include "s3c24xx.h" // LED1,LED2,LED4對應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對應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)) // 關閉WATCHDOG,否則CPU會不斷重啟 void disable_watch_dog(void) { WTCON = 0; // 關閉WATCHDOG很簡單,往這個寄存器寫0即可 } void init_led(void) { // LED1,LED2,LED4對應的3根引腳設為輸出 GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk); GPFCON |= GPF4_out | GPF5_out | GPF6_out; } /* 初始化GPIO引腳為外部中斷 * GPIO引腳用作外部中斷時,默認為低電平觸發、IRQ方式(不用設置INTMOD) */ void init_irq( ) { // S2,S3對應的2根引腳設為中斷引腳 EINT0,ENT2 GPFCON &= ~(GPF0_msk | GPF2_msk); GPFCON |= GPF0_eint | GPF2_eint; // S4對應的引腳設為中斷引腳EINT11 GPGCON &= ~GPG3_msk; GPGCON |= GPG3_eint; // 對于EINT11,需要在EINTMASK寄存器中使能它 EINTMASK &= ~(1<<11); /* * 設定優先級: * ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2 * 仲裁器1、6無需設置 * 最終: * EINT0 > EINT2 > EINT11即K2 > K3 > K4 */ PRIORITY &= ((((~0x01) | (0x3<<7))) | (0x0 << 7)) ; // EINT0、EINT2、EINT8_23使能 INTMSK &= (~(1<<0)) & (~(1<<2)) & (~(1<<5)); }
中斷初始化步驟:
(1) 設置好 IRQ 和 FIQ 的棧
(2) 準備中斷處理函數
1. 異常向量中設置好跳轉函數
2. 中斷服務程序(ISR)
3. 清除中斷
4. 保護現場, 恢復現場
(3) 根據中斷源設置相關外設
外部中斷: 設置引腳為"外部中斷", 設置中斷觸發方式, 開啟對應的屏蔽寄存器, EINTMSK
內部中斷: 將INTSUBMSK開啟
(4)確定中斷的使用方式: IRQ 或 FIQ
FIQ: 在 INTMOD 設置相應的bit為1
IRQ: 在PRIORITY寄存器中設置優先級, 將 INTMSK中設置為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 被按下, 假設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中斷結構是怎樣的”的內容了,經過本文的學習后,相信大家對arm9中斷結構是怎樣的這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。