目錄
一,Cortex-A7 中斷系統
Cortex-A7 內核有 8 個異常中斷
復位中斷(Rest), CPU 復位以後就會進入復位中斷, 我們可以在復位中斷服務函數裏面做一些初始化工作,比如初始化 SP 指針、DDR 等等。
未定義指令中斷(Undefined Instruction),如果指令不能識別的話就會產生此中斷。
軟中斷(Software Interrupt,SWI),由 SWI 指令引起的中斷,Linux 的系統調用會用 SWI 指令來引起軟中斷,通過軟中斷來陷入到內核空間。
指令預取中止中斷(Prefetch Abort),預取指令的出錯的時候會產生此中斷。
數據訪問中止中斷(Data Abort),訪問數據出錯的時候會產生此中斷。
IRQ 中斷(IRQ Interrupt),外部中斷,前面已經說了,芯片內部的外設中斷都會引起此中斷的發生。
FIQ 中斷(FIQ Interrupt),快速中斷,如果需要快速處理中斷的話就可以使用此中。
我們常用的就是復位中斷和 IRQ 中斷,Cortex-A 內核 CPU 的所有外部中斷都屬於IQR 中斷。
二,中斷控制器GIC
2.1 GIC框架
GIC 有 4 個版本:V1~V4,V1 是最老的版本,已經被廢棄了。GIC V2 是給 ARMv7-A 架構使用的,比如 Cortex-A7、Cortex-A9、Cortex-A15 等,V3 和 V4 是給 ARMv8-A/R 架構使用的,也就是 64 位芯片使用的。
ARM 針對 GIC V2 開發出了 GIC400 這個中斷控制器 IP 核。當 GIC 接收到外部中斷信號以後就會報給 ARM 內核,但是ARM 內核只提供了四個信號給 GIC 來彙報中斷情況:
VFIQ:虛擬快速 FIQ。
VIRQ:虛擬快速 IRQ。
FIQ:快速中斷 IRQ。
IRQ:外部中斷 IRQ。
GICV2 的邏輯圖如圖所示:
左側部分就是中斷源,中間部分就是 GIC 控制器,最右側就是中斷控制器向處理器內核發送中斷信息。中間 GIC 部分將衆多的中斷源分爲分爲三類:
①、SPI(Shared Peripheral Interrupt),共享中斷,顧名思義,所有 Core 共享的中斷,這個是最
常見的,那些外部中斷都屬於 SPI 中斷(注意!不是 SPI 總線那個中斷) 。比如按鍵中斷、串口中斷等等,這些中斷所有的 Core 都可以處理,不限定特定 Core。
②、PPI(Private Peripheral Interrupt),私有中斷,我們說了 GIC 是支持多核的,每個核肯定有自己獨有的中斷。 這些獨有的中斷肯定是要指定的核心處理, 因此這些中斷就叫做私有中斷。
③、SGI(Software-generated Interrupt),軟件中斷,由軟件觸發引起的中斷,通過向寄存器GICD_SGIR 寫入數據來觸發,系統會使用 SGI 中斷來完成多核之間的通信。
2.2 中斷 ID
中斷源有很多,爲了區分這些不同的中斷源肯定要給他們分配一個唯一 ID,這些 ID 就是中斷 ID。每一個 CPU 最多支持 1020 箇中斷 ID,中斷 ID 號爲 ID0~ID1019。這 1020 個 ID 包含了 PPI、SPI 和 SGI.
ID0~ID15:這 16 個 ID 分配給 SGI。
ID16~ID31:這 16 個 ID 分配給 PPI。
ID32~ID1019:這 988 個 ID 分配給 SPI,像 GPIO 中斷、串口中斷等這些外部中斷。
I.MX6U 的總共使用了 128 箇中斷 ID,加上前面屬於 PPI 和 SGI 的 32 個 ID,I.MX6U 的中斷源共有 128+32=160個。
128 箇中斷 ID 對應的中斷在《I.MX6ULL 參考手冊》的“3.2 Cortex A7 interrupts”小節。
MCIMX6Y2C.h裏的枚舉類型 IRQn_Type,枚舉出了 I.MX6U 的所有中斷。
2.3 GID邏輯分塊
GIC 架構分爲了兩個邏輯塊: Distributor 和 CPU Interface, 也就是分發器端和 CPU 接口端。
例程“9_int”(原子LINUX),core_ca7.h 定義了 GIC 結構體。
結構體第 5 行是 GIC 的分發器端相關寄存器,其相對於 GIC 基地址偏移爲 0X1000,獲取到GIC 基地址以後只需要加上 0X1000 即可訪問 GIC 分發器端寄存器。
結構體第 51 行是 GIC 的 CPU 接口端相關寄存器,其相對於 GIC 基地址的偏移爲 0X2000,獲取到 GIC 基地址以後只需要加上 0X2000 即可訪問 GIC 的 CPU 接口段寄存器。
2.3.1 Distributor( 分發器端)
此邏輯塊負責處理各個中斷事件的分發問題,也就是中斷事件應該發送到哪個 CPU Interface 上去。分發器收集所有的中斷源,可以控制每個中斷的優先級, 它總是將優先級最高的中斷事件發送到 CPU 接口端。 分發器端要做的主要工作如下:
①、全局中斷使能控制。
②、控制每一箇中斷的使能或者關閉。
③、設置每個中斷的優先級。
④、設置每個中斷的目標處理器列表。
⑤、設置每個外部中斷的觸發模式:電平觸發或邊沿觸發。
⑥、設置每個中斷屬於組 0 還是組 1。
2.3.2 CPU Interface(CPU 接口端)
CPU 接口端聽名字就知道是和 CPU Core 相連接的,因此每個 CPU Core 都可以在 GIC 中找到一個與之對應的 CPU Interface。CPU 接口端就是分發器和 CPU Core 之間的橋樑,CPU 接口端主要工作如下:
①、使能或者關閉發送到 CPU Core 的中斷請求信號。
②、應答中斷。
③、通知中斷處理完成。
④、設置優先級掩碼,通過掩碼來設置哪些中斷不需要上報給 CPU Core。
⑤、定義搶佔策略。
⑥、當多箇中斷到來的時候,選擇優先級最高的中斷通知給 CPU Core。
2.4 CP15 協處理器
關於 CP15 協處理器和其相關寄存器的詳細內容請參考下面兩份文檔:
《ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》第 1469 頁“B3.17
Oranization of the CP15 registers in a VMSA implementation” 。
《Cortex-A7 Technical ReferenceManua.pdf》第 55 頁“Capter 4 System Control” 。
CP15 協處理器一般用於存儲系統管理,但是在中斷中也會使用到,CP15 協處理器一共有
16 個 32 位寄存器。CP15 協處理器的訪問通過指令完成
三,中斷使能
3.1 IRQ 和 FIQ 總中斷使能
寄存器 CPSR 的 I=1 禁止 IRQ,當 I=0 使能 IRQ;F=1 禁止 FIQ,F=0 使能 FIQ。
我們還有更簡單的指令來完成 IRQ 或者 FIQ 的使能和禁止.
3.2 ID0~ID1019 中斷使能和禁止
GIC 寄存器 GICD_ISENABLERn 和 GICD_ ICENABLERn 用來完成外部中斷的使能和禁止,對於 Cortex-A7 內核來說中斷 ID 只使用了 512 個。一個 bit 控制一箇中斷 ID 的使能,那麼就需要 512/32=16 個 GICD_ISENABLER 寄存器來完成中斷的使能。同理,也需要 16 個GICD_ICENABLER 寄存器來完成中斷的禁止。其中 GICD_ISENABLER0 的 bit[15:0]對應ID15-0 的 SGI 中斷,GICD_ISENABLER0 的 bit[31:16]對應 ID31-16 的 PPI 中斷。剩下的GICD_ISENABLER1–GICD_ISENABLER15 就是控制 SPI 中斷的。
四,中斷優先級設置
4.1 優先級數
Cortex-A7 最多可以支持 256 個優先級,數字越小,優先級越高!I.MX6U 選擇了 32 個優先級。在使用中斷的時候需要初始化 GICC_PMR 寄存器,此寄存器用來決定使用幾級優先級。
GICC_PMR 寄存器只有低 8 位有效,這 8 位最多可以設置 256 個優先級。
I.MX6U 支持 32 個優先級,所以 GICC_PMR 要設置爲 0b11111000。
4.2 搶佔優先級和子優先級位數設置
搶佔優先級和子優先級各佔多少位是由寄存器 GICC_BPR 來決定的。
寄存器GICC_BPR只有低3位有效, 其值不同, 搶佔優先級和子優先級佔用的位數也不同。
爲了簡單起見,一般將所有的中斷優先級位都配置爲搶佔優先級,比如 I.MX6U 的優先級位數爲 5(32 個優先級), 所以可以設置 Binary point 爲 2, 表示 5 個優先級位全部爲搶佔優先級。
4.3 優先級設置
前面已經設置好了 I.MX6U 一共有 32 個搶佔優先級,數字越小優先級越高。具體要使用某個中斷的時候就可以設置其優先級爲 0~31。某個中斷 ID 的中斷優先級設置由寄存器D_IPRIORITYR 來完成,前面說了 Cortex-A7 使用了 512 箇中斷 ID,每個中斷 ID 配有一個優先級寄存器,所以一共有 512 個 D_IPRIORITYR 寄存器。如果優先級個數爲 32 的話,使用寄存器 D_IPRIORITYR 的 bit7:4 來設置優先級,也就是說實際的優先級要左移 3 位。比如要設置ID40 中斷的優先級爲 5,示例代碼如下:
GICD_IPRIORITYR[40] = 5 << 3;
五,core_ca7.h
core_ca7.h中關於中斷主要有10個函數:
個人理解(如有錯誤,還望留言指正)
I.MX6U 有很多中斷,這裏主要說的是IRQ總中斷,串口中斷啥的都在裏面,有中斷就有中斷源,中斷源由中斷ID配置。GID邏輯分塊是配置中斷模式和中斷優先級的,而中斷模式地址是由 CP15 協處理器獲得。
設置 GICC_PMR,配置優先級個數, I.MX6U 支持 32 級優先級。
設置搶佔優先級和子優先級位數,將所有的位數都設置爲搶佔優先級。
設置指定中斷 ID 的優先級,也就是設置外設優先級。