ARM處理器7種工作模式:
- 特權模式(Privileged Models): 除用戶模式(usr)外,其他模式均為特權模式,ARM內部寄存器和一些片內外設在硬體設計上只允許(或者可選為只允許)特權模式下訪問。此外,特權模式可以自由的切換處理器模式,而用戶模式不能直接切換到別的模式。
- 異常模式(Exception Models):特權模式中除系統(system)模式之外,其他五種工作模式皆為異常模式,它們除了可以通過在特權下的程式切換進入外,也可以由特定的異常進入。比如硬體產生中斷信號進入中斷異常模式,讀取沒有許可權資料進入中止異常模式,執行未定義指令時進入未定義指令中止異常模式。其中管理模式也稱為超級使用者模式,是為作業系統提供軟中斷的特有模式,正是由於有了軟中斷,使用者程式才可以通過系統調用切換到管理模式。
- 使用者模式(USER):使用者模式是使用者程式的工作模式,它運行在作業系統的使用者態,它沒有許可權去操作其它硬體資源,只能執行處理自己的資料,也不能切換到其它模式下,要想訪問硬體資源或切換到其它模式只能通過軟中斷或產生異常。
- 系統模式:系統模式是特權模式,不受使用者模式的限制。使用者模式和系統模式共用一套寄存器,作業系統在該模式下可以方便的訪問使用者模式的寄存器,而且作業系統的一些特權任務可以使用這個模式訪問一些受控的資源。
- 一般中斷模式:一般中斷模式也叫普通中斷模式,用於處理一般的中斷要求,通常在硬體產生中斷信號之後自動進入該模式,該模式為特權模式,可以自由訪問系統硬體資源。
- 快速中斷模式:快速中斷模式是相對一般中斷模式而言的,它是用來處理對時間要求比較緊急的插斷要求,主要用於高速資料傳輸及通道處理中。
- 管理模式:管理模式是CPU上電後預設模式,因此在該模式下主要用來做系統的初始化,軟中斷處理也在該模式下,當使用者模式下的使用者程式請求使用硬體資源時通過軟體插斷進入該模式。
- 終止模式:中止模式用於支援虛擬記憶體或記憶體保護,當使用者程式訪問非法位址,沒有許可權讀取的記憶體位址時,會進入該模式,linux下程式設計時經常出現的segment fault通常都是在該模式下拋出返回的。
- 未定義模式:未定義模式用於支援硬體輔助處理器的軟體模擬,CPU在指令的解碼階段不能識別該指令操作時,會進入未定義模式。
- R0~R7在所有模式下都可以使用的共有暫存器
- R8-R12 則會依照模式去切換Bank Register
- 除了用戶模式和系統模式共用一組R13,R14,其餘每種模式都私有自己的R13,R14
- R13為堆疊指標Stack Pointer Rgsiter,保存目前處理器模式的堆疊的堆疊頂端,例如stmdb sp!, { r0-r12,lr } @ 保存使用到的暫存器
- R14為Link Register,保存副程式的返回位址,執行BL指令時,R14中得到R15的備份,例如 ldr lr, =int_return @ 設置調用ISR即EINT_Handle函數後的返回地址
- R15為PC(Program Counter),PC值 = 當前程式執行位置 + 8位元組
- 除了R0~R15暫存器外,還有CPSR(Current Program Status Register),用於標示目前CPU處於何種工作模式,和標示各種狀態
- 在異常模式下,CPU還有一個SPSR(Saved Process Status Registers),在進入異常模式時,保存前一個工作模式的CPSR值,退出異常模式時,將SPSR的值恢復到CPSR中
Interrupt Process Diagram:
- 由上圖可知硬體中斷訊號可分為內部中斷來源與外部中斷來源,匯總到SRCPND,MASK做中斷遮蔽(IRQ),Priority設定中斷優先順序(IRQ),INTPAND用來Panding 中斷訊號,最後進入CPU,FIQ快中斷訊號,經由MODE來管控,最後進入CPU
- 由上圖可知中斷訊號產生流程,所需設置中斷控制器內部的各個暫存器
- 暫存器操作方式,參考S3C2440A 手冊
interrupt controller register |
Priority Generating Block:
- Priority: 固定不變的優先權最高 REQ0, 最低 REQ5,透過設定ARB_SELX可調整優先權REQ1~REQ4排列順序;
- 設定ARM_MODEX 為0,優先權為固定順序,設定ARM_MODEX 為1,為可自動變化順序。
實驗:將開發版上三個按鍵設成中斷功能,當按下某按鍵時,中斷服務程式點亮對應的LED。
關鍵程式碼:
@******************************************************************************
@ File:head.S
@ 功能:初始化,設置中斷模式、管理模式的棧,設置好中斷處理函數
@******************************************************************************
.extern main
.text
.global
_start
_start:
@interrupt vector table
@0x00
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
bl disable_watch_dog
msr cpsr_c, #0xd2 @CPU切換到IRQ模式
ldr sp, =3072 @sp(IRQ模式下) register 起始位置
msr cpsr_c, #0xd3 @CPU切換到管理模式
ldr sp, =4096 @sp(管理模式下) register 起始位置
bl init_led
bl init_irq
msr cpsr_c, #0x53 @設I-bit=0,開IRQ中斷,切換到管理模式(svc)
ldr lr, =halt_loop
ldr pc, =main
halt_loop:
b halt_loop
HandleIRQ:
sub lr, lr, #4 @保存返回值,PC值返回中斷前前一個的PC值
stmdb sp!, {r0-r12, lr}
ldr lr, =int_return
ldr pc, =EINT_Handle
int_return:
ldmia sp!, {r0-r12, pc}^
===========================================
init.c
#include "s3c24xx.h"
#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));
#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));
void disable_watch_dog(void)
{
WTCON = 0; // OFF WATCHDOG
}
void init_led(void)
{
GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);
GPFCON |= GPF4_out | GPF5_out | GPF6_out);
}
void init_irq(void)
{
// S2,S3 設為中斷腳位
GPFCON &= ~(GPF0_msk | GPF2_msk);
GPFCON |= (GPF0_eint | GPF2_eint);
// S4 設為中斷腳位
GPGCON &= ~GPG3_msk;
GPGCON |= GPG3_eint;
// 中斷 enable
EINTMASK &= ~(1<11); // EINT11,外部中斷,需在EINTMASKE致能
INTMASK &= (~(1<<0) & ~(1<<2) & ~(1<<5));
// 書本有誤,更正如下
// 設定優先權,ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,
// 即EINT0 > EINT2
// EINT11 ARBITER1負責,無優先順序,不須設定優先權,因此ARBITER1、
// ARBITER6 不用設置
PRIORITY &= (~(0x01) & ~(0x03<<7));
}
=========================================
interrupt.c
#include "s3c24x0"
void EINT_Handle()
{
unsigned long oft = INTOFFSET;
switch(oft)
{
// S2 按下
case 0:
GPFDAT |= (0x7<<4); // 所有LED熄滅
GPFDAT &= ~(1<<4); // LED2 ON
break;
case 2:
GPFDAT |= (0x7<<4);
GPFDAT &= ~(1<<5);
break;
case 5:
GPFDAT |= (0x7<<4);
GPFDAT &= ~(1<<6);
break;
default:
break;
}
// 清中斷,清除順序要注意,從源頭清
if(oft == 5) EINTPEND = (1<<11);
SRCPND = 1 << oft;
INTPND = 1 << oft;
}
====================================
總結一下心得:首先需要詳細了解CPU工作模式、暫存器,在切換工作模式時,要了解如何保存CPU工作狀態與返回,CPU操作都透過ARM組語,組語要熟一點(尤其是LDR這很費神),接著是要了解s3c2440中斷流程、中斷控制器的暫存器使用方式,如何實作中段向量表、中斷服務程式。
參考資料:
- 嵌入式Linux應用開發完全手冊
- 中斷小知識: http://wenku.baidu.com/view/1f20246ba98271fe910ef92b.html
- http://blog.csdn.net/mr_raptor/article/details/6556157
- http://blog.csdn.net/mr_raptor/article/details/6556163
- http://blog.csdn.net/mr_raptor/article/details/6556186
- http://blog.csdn.net/mr_raptor/article/details/6556195
- http://blog.csdn.net/mr_raptor/article/details/6556258
- http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/webhelp/cpsr.html
- http://blog.csdn.net/cs_ing/article/details/8520606
- http://blog.sina.com.cn/s/blog_932ba3b90101mlh8.html
- http://blog.csdn.net/abclixu123/article/details/7471822
- http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/htmls/why_arm7_pc_8.html
- http://blog.csdn.net/axx1611/article/details/2335410
- http://blog.csdn.net/gameit/article/details/17464389
No comments:
Post a Comment