S5P4418裸機開發(十二):IRQ (按鍵中斷) & 串口中斷

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使能與使能

中斷配置與處理流程

  • CPSRI位清0,允許IRQ中斷
  • 設置檢測方式,使能IO口檢測,GPIOxDETMODE,GPIOxDETENB
  • 使能IO口中斷,GPIOxINTENB
  • 選擇IO口中斷類型,VICINTSELECT
  • 設置中斷處理函數地址,VICVECTADDR
  • 使能中斷,VICINTENABLE

當中斷髮生後,跳到異常向量表,CPSRI位會被置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);

工程文件

8_extint_key

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章