1.設備一上電,中斷向量表作爲第一段執行程序
2.初始化異常向量表基地址協處理器(默認是0,修改後異常跳轉時,PC值=基地址+向量表位置偏移)
3.禁用MMU內存管理單元
4.分配棧空間,初始化各個模式下的棧空間(user棧初始化放在最後)
5.跳轉到main執行程序
假設產生中斷時,CPU當中正在執行一段程序(正常情況),突然之間產生外部中斷,整個CPU的相應以及處理流程:
1.CPU相應流程(CPU自己完成)
1)複製備份CPSR到SPSR_IRQ
2)配置CPSR寄存器
設置工作狀態爲arm態
修改工作模式爲IRQ模式
禁用相應中斷(IRQ)
3)保存返回地址到LR_IRQ
4)設置PC到異常向量表中的IRQ處理項(0x18)
2.根據異常向量表中的跳轉語句跳轉到IRQ_Handle處理程序(程序員寫的)
1)調整LR的值,爲異常結束返回做準備
2)入棧保護寄存器數據
3)跳轉到IRQ_Handle處理函數
4)出棧恢復數據
5)返回退出異常程序,並恢復CPSR
1.誰產生的中斷
2.什麼時候產生中斷
3.中斷怎麼到達SOC
4.產生的中斷交給哪個CPU去處理
5.同時產生多箇中斷時,怎麼處理
6.當一個IRQ中斷正在處理的時候,又來了同類型的一箇中斷怎麼辦
中斷控制器GIC的作用
1.當多箇中斷同時產生的時候,中斷管理器將對這些中斷進行排隊,將優先級最高的轉發給CPU處理,其他再進行排隊等待
2.當一箇中斷正在處理的時候,外設又產生另一箇中斷,中斷管理器會對這個中斷進行記憶,等上一個響應完成後再去響應下一個
3**.爲每一箇中斷分配一個CPU去處理**
4.爲每個中斷選擇一箇中斷類型(FIQ或IRQ)
5.CPU不能區分是哪個外設產生的中斷,但CPU可以通過查詢中斷管理器來獲取當前中斷的中斷號
6.在中斷管理器中我們可以任意打開或關閉一箇中斷
7.爲每一箇中斷分配一個優先級
1.閱讀硬件原理圖,得到K2與SOC之間的對應連接關係:GPX1_1
2.查找用戶手冊,將GPX1_1配置爲中斷功能。
//選擇GPIO引腳功能爲EINT GPX1.CON |= (0xf<<4);
3.配置EXT_INT41CON寄存器,選擇觸發中斷條件(電平、邊沿)
//設置中斷信號檢測:↓下降沿 EXT_INT41_CON &= ~(0x7<<4); EXT_INT41_CON |= (2<<4);
4.配置EXT_INT41_MASK寄存器,開啓按鍵中斷,使之能夠到達GIC
//使能GPIO對中斷的檢測 EXT_INT41_MASK &= ~(1<<1);
5.配置GIC中斷管理器,對K2按鍵中斷進行管理配置(第9章節)
從9.1.1獲取到GIC支持的中斷類型和功能,從Figure 9-1 瞭解到中斷大致物理結構;從Table 9-2瞭解到GIC對每個中斷源的編號管理(ID);中斷原理部分閱讀9.4.1章節,具體配置看9.4.2章節.
//中斷白名單(中斷使能):SPI中斷號25,全局中斷號57 ICDISER.ICDISER1 |= (1<<25);
1)使能中斷源
設置ICDISER寄存器使能對應ID中斷源,使之能夠到達GIC(9.4.1.2章節)
這裏要注意,ICDISER和ICDICER的功能是一樣,在ICDISER中寫是使能,在ICDICER寫1是禁用
2)中斷掛起狀態設置和清除(在本次實驗中不需要設置)
設置ICDISPR寄存器掛起中斷,設置ICDICPR寄存器清除掛起(每次結束中斷時需要清除)
3)選擇處理中斷CPU
配置ICDIPTR寄存器,選擇CPU0處理k2按鍵中斷。
//爲中斷分配處理的CPU0 ICDIPTR.ICDIPTR14 &= ~(0xff<<8); ICDIPTR.ICDIPTR14 |= (1<<8);
5)設置中斷門檻 配置ICCPMR寄存器,爲到達CPU的中斷設置一箇中斷優先級過濾門檻
//設置優先級別屏蔽門檻 CPU0.ICCPMR = 255;
6)打開CPU0的接口中斷開關
ICCICR
//使能CPU接口中斷 CPU0.ICCICR = 1;
7)打開GIC
ICDDCR
6.中斷處理函數
1)獲取中斷號
目的是讓CPU中運行處理程序識別是哪一個中斷源產生的中斷
int irq_num = 0; //讀取中斷號 irq_num = CPU0.ICCIAR & 0x3ff;
2)根據中斷號選擇處理程序
switch(irq_num) { case 57: //按鍵K2 //3、切換蜂鳴器狀態 pwm_change(); printf("in do_irq\n"); //清除GPx1_1中斷標記 EXT_INT41_PEND |= (1<<1); break; }
3)清除中斷標記
EXT_INT41_PEND寫1清零
ICDICPR寫1清0
ICCEOIR寫中斷號清除中斷
//清除GIC中斷標記 CPU0.ICCEOIR |= irq_num;
代碼:
#include "exynos_4412.h" void pwm_init(void) { //1、選擇引腳功能pwmTOU0輸出功能 GPD0.CON &= ~(0xf<<0); GPD0.CON |= (2<<0); //2、一級分頻:249 PWM.TCFG0 &= ~(0xff<<0); PWM.TCFG0 |= (249<<0); //3、二級分頻:4 PWM.TCFG1 &= ~(0xf<<0); PWM.TCFG1 |= (2<<0); //4、設置週期:1000Hz,佔空比50% PWM.TCNTB0 = 100; PWM.TCMPB0 = PWM.TCNTB0 / 2; //5、手動更新TCNT和TCMP PWM.TCON |= (1<<1); PWM.TCON &= ~(1<<1); //6、開啓自動重裝載 PWM.TCON |= (1<<3); } void pwm_change(void) { //7、啓動定時器 PWM.TCON ^= (1<<0); if(PWM.TCON & 1) printf("pwm is open!\n"); else printf("pwm is close!\n"); } void key_init(void) { /****************GPIO配置*****************/ //1、選擇GPIO引腳功能爲EINT GPX1.CON |= (0xf<<4); //2、設置中斷信號檢測:↓下降沿 EXT_INT41_CON &= ~(0x7<<4); EXT_INT41_CON |= (2<<4); //3、使能GPIO對中斷的檢測 EXT_INT41_MASK &= ~(1<<1); /****************GIC配置*****************/ //4、中斷白名單(中斷使能):SPI中斷號25,全局中斷號57 ICDISER.ICDISER1 |= (1<<25); //5、使能GICD調度器檢測中斷信號 ICDDCR = 1; //5、爲中斷分配處理的CPU0 ICDIPTR.ICDIPTR14 &= ~(0xff<<8); ICDIPTR.ICDIPTR14 |= (1<<8); //6、設置優先級別屏蔽門檻 CPU0.ICCPMR = 255; //7、使能CPU接口中斷 CPU0.ICCICR = 1; } void delay(unsigned int time) { int i; for(; time>0; time--) { for(i=2000; i>0; i--) { ; } } } void do_irq(void) { int irq_num = 0; //1、讀取中斷號 irq_num = CPU0.ICCIAR & 0x3ff; //2、識別中斷源,選擇執行對應處理程序 switch(irq_num) { case 57: //按鍵K2 //3、切換蜂鳴器狀態 pwm_change(); printf("in do_irq\n"); //清除GPx1_1中斷標記 EXT_INT41_PEND |= (1<<1); break; } //清除GIC中斷標記 // CPU0.ICCEOIR |= (CPU0.ICCIAR & 0x3ff); CPU0.ICCEOIR |= irq_num; delay(300); } int main(void) { /*1初始化按鍵*/ key_init(); pwm_init(); while(1) { ; } return 0; }