S5P4418 64箇中斷源,按鍵的GPIO口是GPIOB28-30,中斷號爲54;
Interrupt Controller相關寄存器
寄存器 | 功能 |
---|---|
VICIRQSTATUS | R,相關位爲1表示該IRQ中斷髮生且未被屏蔽 |
VICFIQSTATUS | R,相關位爲1表示該FIQ中斷髮生且未被屏蔽 |
VICRAWINTR | R,表示屏蔽之前的中斷狀態 |
VICINTSELECT | 選擇中斷請求類型 |
VICINTENABLE | 寫1中斷使能 |
VICINTENCLEAR | 寫1中斷失能 |
VICSOFTINT | 軟中斷失能,我理解爲可以模擬按鍵 |
VICSOFTINTCLEAR | 軟中斷失能 |
VICPROTECTION | 使能或失能Protection mode |
VICSWPRIORITYMASK | 某些優先級的中斷是否屏蔽 |
VICVECTPRIORITYDAISY | 設置中斷優先級 |
VICVECTADDR0-31 | 表示各個中斷源的ISR(Interrupt service routine) |
VICVECTPRIORITY0 | 各個中斷源的優先級 |
VICADDRESS | 中斷髮生時,對應的ISR函數地址會複製到這個寄存器中 |
VICPERIPHID0-4 | 返回固定的值 |
VICPCELLID1-4 | 返回固定的值 |
GPIO Controller中相關寄存器
寄存器 | 功能 |
---|---|
GPIOxOUTENB | 寫0設置輸入模式 |
GPIOxDETMODE0-1 | 設置事件檢測方式,也可以說中斷觸發方式 |
GPIOxDETMODEEX | 事件檢測方式的擴展位 |
GPIOxINTENB | 中斷使能 |
GPIOxDET | 檢測模式下1表示事件發生,Set “1” to clear the relevant bit. GPIOx[31:0] is used as a Pending register when an interrupt occurs. |
GPIOxDETENB | detected mode使能與使能 |
中斷配置與處理流程
CPSR
的I
位清0,允許IRQ中斷- 設置檢測方式,使能IO口檢測,
GPIOxDETMODE,GPIOxDETENB
- 使能IO口中斷,
GPIOxINTENB
- 選擇IO口中斷類型,
VICINTSELECT
- 設置中斷處理函數地址,
VICVECTADDR
- 使能中斷,
VICINTENABLE
當中斷髮生後,跳到異常向量表,CPSR
的I
位會被置1,硬件將優先級最高的中斷ISR地址放到了VICADDRESS
中。
IRQ模式只能被FIQ模式打斷,FIQ模式下誰也打不斷。所以這款芯片沒有中斷嵌套的情況。
- 設置返回地址,保存現場
- 進入IRQ後取
VICADDRESS
的值,進入中斷處理函數 - 通過
GPIOxDET
判斷是哪個引腳發生了中斷 - 退出中斷函數時,將
GPIOxDET
的值寫回GPIOxDET
以清除相應位,否則會重複進去ISR - 最後向
VICADDRESS
中寫任意值,清除當前中斷
使能GPIO外部中斷
// 首先要修改CPSR寄存器,允許IRQ中斷
void exti_init(){ // 配置中斷
// K1 GPIOB28; K2 GPIOB29; K3 GPIOB30; 按下爲低電平
GPIOBALTFN1 &= ~((3 << 24) | (3 << 26) | (3 << 28)); // 交替函數功能選擇
GPIOBALTFN1 |= ((1 << 24) | (1 << 26) | (1 << 28));
GPIOBOUTENB &= ~((1 << 24) | (1 << 26) | (1 << 28)); // 輸入模式
GPIOBDETMODEEX &= ~((1 << 30) | (1 << 29) | (1 << 28));
GPIOBDETMODE1 &= ~((3 << 28) | (3 << 26) | (3 << 24));
GPIOBDETMODE1 |= ((2 << 28) | (2 << 26) | (2 << 24)); // 下降沿觸發
GPIOBDETENB |= ((1 << 30) | (1 << 29) | (1 << 28)); // 事件檢測使能
GPIOBINTENB |= ((1 << 30) | (1 << 29) | (1 << 28)); // 中斷使能
VICINTENCLEAR_CH1 = 0xFFFFFFFF;
VICINTSELECT_CH1 &= ~(1 << 22); // IRQ
VICVECTADDR_GPIOB = (u32)exti54_ISR;
VICINTENABLE_CH1 = (1 << 22);
// VICSOFTINT_CH1 = (1 << 22); // 生成軟中斷,相當於模擬按鍵
}
void exti54_ISR(){ // ISR
print_cpsr();
if(GPIOBDET & (1 << 28)){ // 按下k1點亮led1
led1_on();
}
if(GPIOBDET & (1 << 29)){ // 按下k2點亮led2
led2_on();
}
if(GPIOBDET & (1 << 30)){ // 按下k3熄滅led
led1_off();
led2_off();
}
GPIOBDET = GPIOBDET; // 相當於清除掛起寄存器
VICADDRESS_CH1 = 0x0; // 必須清除
}
// .starts 啓動文件中保護和恢復現場的操作
_irq:
sub lr, lr, #4
stmdb sp!, {r0-r12, lr}
sub r0, lr, #4 // 傳參
bl except_irq
ldmia sp!, {r0-r12, pc}^
void except_irq(u32 addr){
printf("[%x] Triggered IRQ exceptions\r\n", addr);
((void (*)(void))VICADDRESS_CH1)(); // 具體的中斷函數
}
編譯燒寫上電,死活進不了IRQ,糾結了幾天,瞭解到還有一個叫GIC
的東西。
帖子面向Cortex-A9的ucos移植 中有這樣一句話
因此,ICCICR寄存器的地址爲0XF0000000+0X100,往這個地址寫0則繞過GIC,這樣,多核處理器的中斷就跟我們以前用的單核沒有區別了。
不糾結那麼多,先出效果再說;
#define GICC_CTLR __REG(0xF0000100 + 0x00)
void other_init(){
// cpsie i
__asm__(
"MRS r0, cpsr\n"
"BIC r0, r0, #(1 << 7)\n"
"MSR cpsr, r0\n"
); // 開啓IRQ
GICC_CTLR = 0; // 繞過GIC
}
編譯燒寫上電,OK。成功進入IRQ模式;
下一貼糾結GIC;
順便把串口也改成中斷模式
// 配置中斷
UARTIMSC |= (1 << 4);
VICINTENCLEAR_CH0 = (1 << 7);
VICINTSELECT_CH0 &= ~(1 << 7); // IRQ
VICVECTADDR_UART0 = (u32)uart0_ISR;
VICINTENABLE_CH0 = (1 << 7);