GPIO外部中斷處理—基於I.MX6UL嵌入式SoC


1、前言

在前面的文章《GPIO按鍵輸入—基於I.MX6UL嵌入式SoC》中,鏈接如下:

https://www.cnblogs.com/Cqlismy/p/12500760.html

實現了GPIO的通用輸入功能,還介紹了GPIO實現按鍵功能的實例,在該實例中,按鍵是否按下,是通過不斷讀取GPIO的電平來進行判斷的,如果該GPIO讀取到低電平,也就是按鍵處於按下狀態了,GPIO讀取到高電平,則按鍵是處於松開狀態的,但是,在實際項目開發中,並不會使用這樣的按鍵驅動,對於GPIO按鍵功能的實現,一般是使用GPIO的外部中斷原理去實現,GPIO除了能實現基本的輸入/輸出功能以外,還能夠產生ARM Core中斷。

本篇文章將使用GPIO的外部中斷功能來實現一個簡單的按鍵驅動,按鍵的另一端接入到I.MX6UL嵌入式SoC的GPIO上,當按鍵處於松開狀態時,GPIO處於高電平狀態,當按鍵按下后,GPIO處於低電平狀態,並且觸發ARM Core中斷,然后處理器跳轉到按鍵的中斷服務處理函數執行,進行按鍵按下的事件上報。

關於ARM GIC中斷相關的知識,可以參考文章《ARM Cortex-A7中斷系統基礎知識》,鏈接如下:

https://www.cnblogs.com/Cqlismy/p/12549087.html

本文對這方面的知識就不再詳細介紹了。

 

2、GPIO外部中斷處理程序

GPIO外部中斷處理實例的大致編程思路如下所示:

  • 使能相應的按鍵GPIO引腳外設時鍾;
  • GIC中斷控制器初始化;
  • 設置IO口的復用模式為GPIO,設置IO口引腳的電氣屬性;
  • 設置GPIO的方向為輸入,配置GPIO的中斷觸發方式為低電平觸發,並使能GPIO中斷功能;
  • 實現GPIO外部中斷的中斷服務處理程序,進行按鍵事件的處理。

由於在GPIO外部中斷處理程序中需要使用到GIC中斷控制器,先移植NXP官方為I.MX6UL提供的SDK包中的core_ca7.h文件,該文件主要是訪問CP15協處理器寄存器和GIC中斷控制的一些底層驅動函數,需要拷貝到工程目錄的imx6ul目錄下,修改后的文件內容如下:

/* Copyright (c) 2009 - 2015 ARM LIMITED
   Copyright (c) 2016, Freescale Semiconductor, Inc.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
   ---------------------------------------------------------------------------*/

#ifndef __CORE_CA7_H
#define __CORE_CA7_H

#include "types.h"

#define FORCEDINLINE  __attribute__((always_inline))

#define __ASM            __asm                                      /*!< asm keyword for GNU Compiler */
#define __INLINE         inline                                     /*!< inline keyword for GNU Compiler */
#define __STATIC_INLINE  static inline

/* following defines should be used for structure members */
#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */

#define __STRINGIFY(x) #x

#define __MCR(coproc, opcode_1, src, CRn, CRm, opcode_2)                          \
    __ASM volatile ("MCR " __STRINGIFY(p##coproc) ", " __STRINGIFY(opcode_1) ", " \
                    "%0, " __STRINGIFY(c##CRn) ", " __STRINGIFY(c##CRm) ", "      \
                    __STRINGIFY(opcode_2)                                         \
                    : : "r" (src) )

#define __MRC(coproc, opcode_1, CRn, CRm, opcode_2)                               \
  ({                                                                              \
    uint32_t __dst;                                                               \
    __ASM volatile ("MRC " __STRINGIFY(p##coproc) ", " __STRINGIFY(opcode_1) ", " \
                    "%0, " __STRINGIFY(c##CRn) ", " __STRINGIFY(c##CRm) ", "      \
                    __STRINGIFY(opcode_2)                                         \
                    : "=r" (__dst) );                                             \
    __dst;                                                                        \
  })

__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_APSR(uint32_t apsr)
{
  __ASM volatile ("MSR apsr, %0" : : "r" (apsr) : "cc");
}

__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CPSR(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, cpsr" : "=r" (result) );
  return(result);
}

__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CPSR(uint32_t cpsr)
{
  __ASM volatile ("MSR cpsr, %0" : : "r" (cpsr) : "cc");
}

__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPEXC(void)
{
  uint32_t result;

  __ASM volatile ("VMRS %0, fpexc" : "=r" (result) );
  return result;
}

__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPEXC(uint32_t fpexc)
{
  __ASM volatile ("VMSR fpexc, %0" : : "r" (fpexc));
}

/*******************************************************************************
 *                 Register Abstraction
  Core Register contain:
  - CPSR
  - CP15 Registers
 ******************************************************************************/

/* Core Register CPSR */
typedef union
{
  struct
  {
    uint32_t M:5;                        /*!< bit:  0.. 4  Mode field */
    uint32_t T:1;                        /*!< bit:      5  Thumb execution state bit */
    uint32_t F:1;                        /*!< bit:      6  FIQ mask bit */
    uint32_t I:1;                        /*!< bit:      7  IRQ mask bit */
    uint32_t A:1;                        /*!< bit:      8  Asynchronous abort mask bit */
    uint32_t E:1;                        /*!< bit:      9  Endianness execution state bit */
    uint32_t IT1:6;                      /*!< bit: 10..15  If-Then execution state bits 2-7 */
    uint32_t GE:4;                       /*!< bit: 16..19  Greater than or Equal flags */
    uint32_t _reserved0:4;               /*!< bit: 20..23  Reserved */
    uint32_t J:1;                        /*!< bit:     24  Jazelle bit */
    uint32_t IT0:2;                      /*!< bit: 25..26  If-Then execution state bits 0-1 */
    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */
    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */
    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */
    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */
    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} CPSR_Type;

/* CPSR Register Definitions */
#define CPSR_N_Pos                       31U                                    /*!< CPSR: N Position */
#define CPSR_N_Msk                       (1UL << CPSR_N_Pos)                    /*!< CPSR: N Mask */

#define CPSR_Z_Pos                       30U                                    /*!< CPSR: Z Position */
#define CPSR_Z_Msk                       (1UL << CPSR_Z_Pos)                    /*!< CPSR: Z Mask */

#define CPSR_C_Pos                       29U                                    /*!< CPSR: C Position */
#define CPSR_C_Msk                       (1UL << CPSR_C_Pos)                    /*!< CPSR: C Mask */

#define CPSR_V_Pos                       28U                                    /*!< CPSR: V Position */
#define CPSR_V_Msk                       (1UL << CPSR_V_Pos)                    /*!< CPSR: V Mask */

#define CPSR_Q_Pos                       27U                                    /*!< CPSR: Q Position */
#define CPSR_Q_Msk                       (1UL << CPSR_Q_Pos)                    /*!< CPSR: Q Mask */

#define CPSR_IT0_Pos                     25U                                    /*!< CPSR: IT0 Position */
#define CPSR_IT0_Msk                     (3UL << CPSR_IT0_Pos)                  /*!< CPSR: IT0 Mask */

#define CPSR_J_Pos                       24U                                    /*!< CPSR: J Position */
#define CPSR_J_Msk                       (1UL << CPSR_J_Pos)                    /*!< CPSR: J Mask */

#define CPSR_GE_Pos                      16U                                    /*!< CPSR: GE Position */
#define CPSR_GE_Msk                      (0xFUL << CPSR_GE_Pos)                 /*!< CPSR: GE Mask */

#define CPSR_IT1_Pos                     10U                                    /*!< CPSR: IT1 Position */
#define CPSR_IT1_Msk                     (0x3FUL << CPSR_IT1_Pos)               /*!< CPSR: IT1 Mask */

#define CPSR_E_Pos                       9U                                     /*!< CPSR: E Position */
#define CPSR_E_Msk                       (1UL << CPSR_E_Pos)                    /*!< CPSR: E Mask */

#define CPSR_A_Pos                       8U                                     /*!< CPSR: A Position */
#define CPSR_A_Msk                       (1UL << CPSR_A_Pos)                    /*!< CPSR: A Mask */

#define CPSR_I_Pos                       7U                                     /*!< CPSR: I Position */
#define CPSR_I_Msk                       (1UL << CPSR_I_Pos)                    /*!< CPSR: I Mask */

#define CPSR_F_Pos                       6U                                     /*!< CPSR: F Position */
#define CPSR_F_Msk                       (1UL << CPSR_F_Pos)                    /*!< CPSR: F Mask */

#define CPSR_T_Pos                       5U                                     /*!< CPSR: T Position */
#define CPSR_T_Msk                       (1UL << CPSR_T_Pos)                    /*!< CPSR: T Mask */

#define CPSR_M_Pos                       0U                                     /*!< CPSR: M Position */
#define CPSR_M_Msk                       (0x1FUL << CPSR_M_Pos)                 /*!< CPSR: M Mask */


/* CP15 Register SCTLR */
typedef union
{
  struct
  {
    uint32_t M:1;                        /*!< bit:     0  MMU enable */
    uint32_t A:1;                        /*!< bit:     1  Alignment check enable */
    uint32_t C:1;                        /*!< bit:     2  Cache enable */
    uint32_t _reserved0:2;               /*!< bit: 3.. 4  Reserved */
    uint32_t CP15BEN:1;                  /*!< bit:     5  CP15 barrier enable */
    uint32_t _reserved1:1;               /*!< bit:     6  Reserved */
    uint32_t B:1;                        /*!< bit:     7  Endianness model */
    uint32_t _reserved2:2;               /*!< bit: 8.. 9  Reserved */
    uint32_t SW:1;                       /*!< bit:    10  SWP and SWPB enable */
    uint32_t Z:1;                        /*!< bit:    11  Branch prediction enable */
    uint32_t I:1;                        /*!< bit:    12  Instruction cache enable */
    uint32_t V:1;                        /*!< bit:    13  Vectors bit */
    uint32_t RR:1;                       /*!< bit:    14  Round Robin select */
    uint32_t _reserved3:2;               /*!< bit:15..16  Reserved */
    uint32_t HA:1;                       /*!< bit:    17  Hardware Access flag enable */
    uint32_t _reserved4:1;               /*!< bit:    18  Reserved */
    uint32_t WXN:1;                      /*!< bit:    19  Write permission implies XN */
    uint32_t UWXN:1;                     /*!< bit:    20  Unprivileged write permission implies PL1 XN */
    uint32_t FI:1;                       /*!< bit:    21  Fast interrupts configuration enable */
    uint32_t U:1;                        /*!< bit:    22  Alignment model */
    uint32_t _reserved5:1;               /*!< bit:    23  Reserved */
    uint32_t VE:1;                       /*!< bit:    24  Interrupt Vectors Enable */
    uint32_t EE:1;                       /*!< bit:    25  Exception Endianness */
    uint32_t _reserved6:1;               /*!< bit:    26  Reserved */
    uint32_t NMFI:1;                     /*!< bit:    27  Non-maskable FIQ (NMFI) support */
    uint32_t TRE:1;                      /*!< bit:    28  TEX remap enable. */
    uint32_t AFE:1;                      /*!< bit:    29  Access flag enable */
    uint32_t TE:1;                       /*!< bit:    30  Thumb Exception enable */
    uint32_t _reserved7:1;               /*!< bit:    31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} SCTLR_Type;

#define SCTLR_TE_Pos                     30U                                    /*!< SCTLR: TE Position */
#define SCTLR_TE_Msk                     (1UL << SCTLR_TE_Pos)                  /*!< SCTLR: TE Mask */

#define SCTLR_AFE_Pos                    29U                                    /*!< SCTLR: AFE Position */
#define SCTLR_AFE_Msk                    (1UL << SCTLR_AFE_Pos)                 /*!< SCTLR: AFE Mask */

#define SCTLR_TRE_Pos                    28U                                    /*!< SCTLR: TRE Position */
#define SCTLR_TRE_Msk                    (1UL << SCTLR_TRE_Pos)                 /*!< SCTLR: TRE Mask */

#define SCTLR_NMFI_Pos                   27U                                    /*!< SCTLR: NMFI Position */
#define SCTLR_NMFI_Msk                   (1UL << SCTLR_NMFI_Pos)                /*!< SCTLR: NMFI Mask */

#define SCTLR_EE_Pos                     25U                                    /*!< SCTLR: EE Position */
#define SCTLR_EE_Msk                     (1UL << SCTLR_EE_Pos)                  /*!< SCTLR: EE Mask */

#define SCTLR_VE_Pos                     24U                                    /*!< SCTLR: VE Position */
#define SCTLR_VE_Msk                     (1UL << SCTLR_VE_Pos)                  /*!< SCTLR: VE Mask */

#define SCTLR_U_Pos                      22U                                    /*!< SCTLR: U Position */
#define SCTLR_U_Msk                      (1UL << SCTLR_U_Pos)                   /*!< SCTLR: U Mask */

#define SCTLR_FI_Pos                     21U                                    /*!< SCTLR: FI Position */
#define SCTLR_FI_Msk                     (1UL << SCTLR_FI_Pos)                  /*!< SCTLR: FI Mask */

#define SCTLR_UWXN_Pos                   20U                                    /*!< SCTLR: UWXN Position */
#define SCTLR_UWXN_Msk                   (1UL << SCTLR_UWXN_Pos)                /*!< SCTLR: UWXN Mask */

#define SCTLR_WXN_Pos                    19U                                    /*!< SCTLR: WXN Position */
#define SCTLR_WXN_Msk                    (1UL << SCTLR_WXN_Pos)                 /*!< SCTLR: WXN Mask */

#define SCTLR_HA_Pos                     17U                                    /*!< SCTLR: HA Position */
#define SCTLR_HA_Msk                     (1UL << SCTLR_HA_Pos)                  /*!< SCTLR: HA Mask */

#define SCTLR_RR_Pos                     14U                                    /*!< SCTLR: RR Position */
#define SCTLR_RR_Msk                     (1UL << SCTLR_RR_Pos)                  /*!< SCTLR: RR Mask */

#define SCTLR_V_Pos                      13U                                    /*!< SCTLR: V Position */
#define SCTLR_V_Msk                      (1UL << SCTLR_V_Pos)                   /*!< SCTLR: V Mask */

#define SCTLR_I_Pos                      12U                                    /*!< SCTLR: I Position */
#define SCTLR_I_Msk                      (1UL << SCTLR_I_Pos)                   /*!< SCTLR: I Mask */

#define SCTLR_Z_Pos                      11U                                    /*!< SCTLR: Z Position */
#define SCTLR_Z_Msk                      (1UL << SCTLR_Z_Pos)                   /*!< SCTLR: Z Mask */

#define SCTLR_SW_Pos                     10U                                    /*!< SCTLR: SW Position */
#define SCTLR_SW_Msk                     (1UL << SCTLR_SW_Pos)                  /*!< SCTLR: SW Mask */

#define SCTLR_B_Pos                      7U                                     /*!< SCTLR: B Position */
#define SCTLR_B_Msk                      (1UL << SCTLR_B_Pos)                   /*!< SCTLR: B Mask */

#define SCTLR_CP15BEN_Pos                5U                                     /*!< SCTLR: CP15BEN Position */
#define SCTLR_CP15BEN_Msk                (1UL << SCTLR_CP15BEN_Pos)             /*!< SCTLR: CP15BEN Mask */

#define SCTLR_C_Pos                      2U                                     /*!< SCTLR: C Position */
#define SCTLR_C_Msk                      (1UL << SCTLR_C_Pos)                   /*!< SCTLR: C Mask */

#define SCTLR_A_Pos                      1U                                     /*!< SCTLR: A Position */
#define SCTLR_A_Msk                      (1UL << SCTLR_A_Pos)                   /*!< SCTLR: A Mask */

#define SCTLR_M_Pos                      0U                                     /*!< SCTLR: M Position */
#define SCTLR_M_Msk                      (1UL << SCTLR_M_Pos)                   /*!< SCTLR: M Mask */

/* CP15 Register ACTLR */
typedef union
{
  struct
  {
    uint32_t _reserved0:6;               /*!< bit: 0.. 5  Reserved */
    uint32_t SMP:1;                      /*!< bit:     6  Enables coherent requests to the processor */
    uint32_t _reserved1:3;               /*!< bit: 7.. 9  Reserved */
    uint32_t DODMBS:1;                   /*!< bit:    10  Disable optimized data memory barrier behavior */
    uint32_t L2RADIS:1;                  /*!< bit:    11  L2 Data Cache read-allocate mode disable */
    uint32_t L1RADIS:1;                  /*!< bit:    12  L1 Data Cache read-allocate mode disable */
    uint32_t L1PCTL:2;                   /*!< bit:13..14  L1 Data prefetch control */
    uint32_t DDVM:1;                     /*!< bit:    15  Disable Distributed Virtual Memory (DVM) transactions */
    uint32_t _reserved3:12;              /*!< bit:16..27  Reserved */
    uint32_t DDI:1;                      /*!< bit:    28  Disable dual issue */
    uint32_t _reserved7:3;               /*!< bit:29..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} ACTLR_Type;

#define ACTLR_DDI_Pos                    28U                                     /*!< ACTLR: DDI Position */
#define ACTLR_DDI_Msk                    (1UL << ACTLR_DDI_Pos)                  /*!< ACTLR: DDI Mask */

#define ACTLR_DDVM_Pos                   15U                                     /*!< ACTLR: DDVM Position */
#define ACTLR_DDVM_Msk                   (1UL << ACTLR_DDVM_Pos)                 /*!< ACTLR: DDVM Mask */

#define ACTLR_L1PCTL_Pos                 13U                                     /*!< ACTLR: L1PCTL Position */
#define ACTLR_L1PCTL_Msk                 (3UL << ACTLR_L1PCTL_Pos)               /*!< ACTLR: L1PCTL Mask */

#define ACTLR_L1RADIS_Pos                12U                                     /*!< ACTLR: L1RADIS Position */
#define ACTLR_L1RADIS_Msk                (1UL << ACTLR_L1RADIS_Pos)              /*!< ACTLR: L1RADIS Mask */

#define ACTLR_L2RADIS_Pos                11U                                     /*!< ACTLR: L2RADIS Position */
#define ACTLR_L2RADIS_Msk                (1UL << ACTLR_L2RADIS_Pos)              /*!< ACTLR: L2RADIS Mask */

#define ACTLR_DODMBS_Pos                 10U                                     /*!< ACTLR: DODMBS Position */
#define ACTLR_DODMBS_Msk                 (1UL << ACTLR_DODMBS_Pos)               /*!< ACTLR: DODMBS Mask */

#define ACTLR_SMP_Pos                    6U                                      /*!< ACTLR: SMP Position */
#define ACTLR_SMP_Msk                    (1UL << ACTLR_SMP_Pos)                  /*!< ACTLR: SMP Mask */


/* CP15 Register CPACR */
typedef union
{
  struct
  {
    uint32_t _reserved0:20;              /*!< bit: 0..19  Reserved */
    uint32_t cp10:2;                     /*!< bit:20..21  Access rights for coprocessor 10 */
    uint32_t cp11:2;                     /*!< bit:22..23  Access rights for coprocessor 11 */
    uint32_t _reserved1:6;               /*!< bit:24..29  Reserved */
    uint32_t D32DIS:1;                   /*!< bit:    30  Disable use of registers D16-D31 of the VFP register file */
    uint32_t ASEDIS:1;                   /*!< bit:    31  Disable Advanced SIMD Functionality */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} CPACR_Type;

#define CPACR_ASEDIS_Pos                 31U                                    /*!< CPACR: ASEDIS Position */
#define CPACR_ASEDIS_Msk                 (1UL << CPACR_ASEDIS_Pos)              /*!< CPACR: ASEDIS Mask */

#define CPACR_D32DIS_Pos                 30U                                    /*!< CPACR: D32DIS Position */
#define CPACR_D32DIS_Msk                 (1UL << CPACR_D32DIS_Pos)              /*!< CPACR: D32DIS Mask */

#define CPACR_cp11_Pos                   22U                                    /*!< CPACR: cp11 Position */
#define CPACR_cp11_Msk                   (3UL << CPACR_cp11_Pos)                /*!< CPACR: cp11 Mask */

#define CPACR_cp10_Pos                   20U                                    /*!< CPACR: cp10 Position */
#define CPACR_cp10_Msk                   (3UL << CPACR_cp10_Pos)                /*!< CPACR: cp10 Mask */


/* CP15 Register DFSR */
typedef union
{
  struct
  {
    uint32_t FS0:4;                      /*!< bit: 0.. 3  Fault Status bits bit 0-3 */
    uint32_t Domain:4;                   /*!< bit: 4.. 7  Fault on which domain */
    uint32_t _reserved0:2;               /*!< bit: 8.. 9  Reserved */
    uint32_t FS1:1;                      /*!< bit:    10  Fault Status bits bit 4 */
    uint32_t WnR:1;                      /*!< bit:    11  Write not Read bit */
    uint32_t ExT:1;                      /*!< bit:    12  External abort type */
    uint32_t CM:1;                       /*!< bit:    13  Cache maintenance fault */
    uint32_t _reserved1:18;              /*!< bit:14..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} DFSR_Type;

#define DFSR_CM_Pos                      13U                                    /*!< DFSR: CM Position */
#define DFSR_CM_Msk                      (1UL << DFSR_CM_Pos)                   /*!< DFSR: CM Mask */

#define DFSR_Ext_Pos                     12U                                    /*!< DFSR: Ext Position */
#define DFSR_Ext_Msk                     (1UL << DFSR_Ext_Pos)                  /*!< DFSR: Ext Mask */

#define DFSR_WnR_Pos                     11U                                    /*!< DFSR: WnR Position */
#define DFSR_WnR_Msk                     (1UL << DFSR_WnR_Pos)                  /*!< DFSR: WnR Mask */

#define DFSR_FS1_Pos                     10U                                    /*!< DFSR: FS1 Position */
#define DFSR_FS1_Msk                     (1UL << DFSR_FS1_Pos)                  /*!< DFSR: FS1 Mask */

#define DFSR_Domain_Pos                  4U                                     /*!< DFSR: Domain Position */
#define DFSR_Domain_Msk                  (0xFUL << DFSR_Domain_Pos)             /*!< DFSR: Domain Mask */

#define DFSR_FS0_Pos                     0U                                     /*!< DFSR: FS0 Position */
#define DFSR_FS0_Msk                     (0xFUL << DFSR_FS0_Pos)                /*!< DFSR: FS0 Mask */


/* CP15 Register IFSR */
typedef union
{
  struct
  {
    uint32_t FS0:4;                      /*!< bit: 0.. 3  Fault Status bits bit 0-3 */
    uint32_t _reserved0:6;               /*!< bit: 4.. 9  Reserved */
    uint32_t FS1:1;                      /*!< bit:    10  Fault Status bits bit 4 */
    uint32_t _reserved1:1;               /*!< bit:    11  Reserved */
    uint32_t ExT:1;                      /*!< bit:    12  External abort type */
    uint32_t _reserved2:19;              /*!< bit:13..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} IFSR_Type;

#define IFSR_ExT_Pos                     12U                                    /*!< IFSR: ExT Position */
#define IFSR_ExT_Msk                     (1UL << IFSR_ExT_Pos)                  /*!< IFSR: ExT Mask */

#define IFSR_FS1_Pos                     10U                                    /*!< IFSR: FS1 Position */
#define IFSR_FS1_Msk                     (1UL << IFSR_FS1_Pos)                  /*!< IFSR: FS1 Mask */

#define IFSR_FS0_Pos                     0U                                     /*!< IFSR: FS0 Position */
#define IFSR_FS0_Msk                     (0xFUL << IFSR_FS0_Pos)                /*!< IFSR: FS0 Mask */


/* CP15 Register ISR */
typedef union
{
  struct
  {
    uint32_t _reserved0:6;               /*!< bit: 0.. 5  Reserved */
    uint32_t F:1;                        /*!< bit:     6  FIQ pending bit */
    uint32_t I:1;                        /*!< bit:     7  IRQ pending bit */
    uint32_t A:1;                        /*!< bit:     8  External abort pending bit */
    uint32_t _reserved1:23;              /*!< bit:14..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} ISR_Type;

#define ISR_A_Pos                        13U                                    /*!< ISR: A Position */
#define ISR_A_Msk                        (1UL << ISR_A_Pos)                     /*!< ISR: A Mask */

#define ISR_I_Pos                        12U                                    /*!< ISR: I Position */
#define ISR_I_Msk                        (1UL << ISR_I_Pos)                     /*!< ISR: I Mask */

#define ISR_F_Pos                        11U                                    /*!< ISR: F Position */
#define ISR_F_Msk                        (1UL << ISR_F_Pos)                     /*!< ISR: F Mask */


/* Mask and shift a bit field value for use in a register bit range. */
#define _VAL2FLD(field, value)    ((value << field ## _Pos) & field ## _Msk)

/* Mask and shift a register value to extract a bit filed value. */
#define _FLD2VAL(field, value)    ((value & field ## _Msk) >> field ## _Pos)



/*******************************************************************************
 *                 CP15 Access Functions
 ******************************************************************************/
FORCEDINLINE __STATIC_INLINE uint32_t __get_SCTLR(void)
{
  return __MRC(15, 0, 1, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_SCTLR(uint32_t sctlr)
{
  __MCR(15, 0, sctlr, 1, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_ACTLR(void)
{
  return __MRC(15, 0, 1, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_ACTLR(uint32_t actlr)
{
  __MCR(15, 0, actlr, 1, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_CPACR(void)
{
  return __MRC(15, 0, 1, 0, 2);
}

FORCEDINLINE __STATIC_INLINE void __set_CPACR(uint32_t cpacr)
{
  __MCR(15, 0, cpacr, 1, 0, 2);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_TTBR0(void)
{
  return __MRC(15, 0, 2, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_TTBR0(uint32_t ttbr0)
{
  __MCR(15, 0, ttbr0, 2, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_TTBR1(void)
{
  return __MRC(15, 0, 2, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_TTBR1(uint32_t ttbr1)
{
  __MCR(15, 0, ttbr1, 2, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_TTBCR(void)
{
  return __MRC(15, 0, 2, 0, 2);
}

FORCEDINLINE __STATIC_INLINE void __set_TTBCR(uint32_t ttbcr)
{
  __MCR(15, 0, ttbcr, 2, 0, 2);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_DACR(void)
{
  return __MRC(15, 0, 3, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_DACR(uint32_t dacr)
{
  __MCR(15, 0, dacr, 3, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_DFSR(void)
{
  return __MRC(15, 0, 5, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_DFSR(uint32_t dfsr)
{
  __MCR(15, 0, dfsr, 5, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_IFSR(void)
{
  return __MRC(15, 0, 5, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_IFSR(uint32_t ifsr)
{
  __MCR(15, 0, ifsr, 5, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_DFAR(void)
{
  return __MRC(15, 0, 6, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_DFAR(uint32_t dfar)
{
  __MCR(15, 0, dfar, 6, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_IFAR(void)
{
  return __MRC(15, 0, 6, 0, 2);
}

FORCEDINLINE __STATIC_INLINE void __set_IFAR(uint32_t ifar)
{
  __MCR(15, 0, ifar, 6, 0, 2);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_VBAR(void)
{
  return __MRC(15, 0, 12, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_VBAR(uint32_t vbar)
{
  __MCR(15, 0, vbar, 12, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_ISR(void)
{
  return __MRC(15, 0, 12, 1, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_ISR(uint32_t isr)
{
  __MCR(15, 0, isr, 12, 1, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_CONTEXTIDR(void)
{
  return __MRC(15, 0, 13, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_CONTEXTIDR(uint32_t contextidr)
{
  __MCR(15, 0, contextidr, 13, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_CBAR(void)
{
  return __MRC(15, 4, 15, 0, 0);
}


/*******************************************************************************
 *                 GIC Functions
 ******************************************************************************/
typedef struct
{
        uint32_t RESERVED0[1024];
  __IOM uint32_t D_CTLR;                 /*!< Offset: 0x1000 (R/W) Distributor Control Register */
  __IM  uint32_t D_TYPER;                /*!< Offset: 0x1004 (R/ )  Interrupt Controller Type Register */
  __IM  uint32_t D_IIDR;                 /*!< Offset: 0x1008 (R/ )  Distributor Implementer Identification Register */
        uint32_t RESERVED1[29];
  __IOM uint32_t D_IGROUPR[16];          /*!< Offset: 0x1080 - 0x0BC (R/W) Interrupt Group Registers */
        uint32_t RESERVED2[16];
  __IOM uint32_t D_ISENABLER[16];        /*!< Offset: 0x1100 - 0x13C (R/W) Interrupt Set-Enable Registers */
        uint32_t RESERVED3[16];
  __IOM uint32_t D_ICENABLER[16];        /*!< Offset: 0x1180 - 0x1BC (R/W) Interrupt Clear-Enable Registers */
        uint32_t RESERVED4[16];
  __IOM uint32_t D_ISPENDR[16];          /*!< Offset: 0x1200 - 0x23C (R/W) Interrupt Set-Pending Registers */
        uint32_t RESERVED5[16];
  __IOM uint32_t D_ICPENDR[16];          /*!< Offset: 0x1280 - 0x2BC (R/W) Interrupt Clear-Pending Registers */
        uint32_t RESERVED6[16];
  __IOM uint32_t D_ISACTIVER[16];        /*!< Offset: 0x1300 - 0x33C (R/W) Interrupt Set-Active Registers */
        uint32_t RESERVED7[16];
  __IOM uint32_t D_ICACTIVER[16];        /*!< Offset: 0x1380 - 0x3BC (R/W) Interrupt Clear-Active Registers */
        uint32_t RESERVED8[16];
  __IOM uint8_t  D_IPRIORITYR[512];      /*!< Offset: 0x1400 - 0x5FC (R/W) Interrupt Priority Registers */
        uint32_t RESERVED9[128];
  __IOM uint8_t  D_ITARGETSR[512];       /*!< Offset: 0x1800 - 0x9FC (R/W) Interrupt Targets Registers */
        uint32_t RESERVED10[128];
  __IOM uint32_t D_ICFGR[32];            /*!< Offset: 0x1C00 - 0xC7C (R/W) Interrupt configuration registers */
        uint32_t RESERVED11[32];
  __IM  uint32_t D_PPISR;                /*!< Offset: 0x1D00 (R/ ) Private Peripheral Interrupt Status Register */
  __IM  uint32_t D_SPISR[15];            /*!< Offset: 0x1D04 - 0xD3C (R/ ) Shared Peripheral Interrupt Status Registers */
        uint32_t RESERVED12[112];
  __OM  uint32_t D_SGIR;                 /*!< Offset: 0x1F00 ( /W) Software Generated Interrupt Register */
        uint32_t RESERVED13[3];
  __IOM uint8_t  D_CPENDSGIR[16];        /*!< Offset: 0x1F10 - 0xF1C (R/W) SGI Clear-Pending Registers */
  __IOM uint8_t  D_SPENDSGIR[16];        /*!< Offset: 0x1F20 - 0xF2C (R/W) SGI Set-Pending Registers */
        uint32_t RESERVED14[40];
  __IM  uint32_t D_PIDR4;                /*!< Offset: 0x1FD0 (R/ ) Peripheral ID4 Register */
  __IM  uint32_t D_PIDR5;                /*!< Offset: 0x1FD4 (R/ ) Peripheral ID5 Register */
  __IM  uint32_t D_PIDR6;                /*!< Offset: 0x1FD8 (R/ ) Peripheral ID6 Register */
  __IM  uint32_t D_PIDR7;                /*!< Offset: 0x1FDC (R/ ) Peripheral ID7 Register */
  __IM  uint32_t D_PIDR0;                /*!< Offset: 0x1FE0 (R/ ) Peripheral ID0 Register */
  __IM  uint32_t D_PIDR1;                /*!< Offset: 0x1FE4 (R/ ) Peripheral ID1 Register */
  __IM  uint32_t D_PIDR2;                /*!< Offset: 0x1FE8 (R/ ) Peripheral ID2 Register */
  __IM  uint32_t D_PIDR3;                /*!< Offset: 0x1FEC (R/ ) Peripheral ID3 Register */
  __IM  uint32_t D_CIDR0;                /*!< Offset: 0x1FF0 (R/ ) Component ID0 Register */
  __IM  uint32_t D_CIDR1;                /*!< Offset: 0x1FF4 (R/ ) Component ID1 Register */
  __IM  uint32_t D_CIDR2;                /*!< Offset: 0x1FF8 (R/ ) Component ID2 Register */
  __IM  uint32_t D_CIDR3;                /*!< Offset: 0x1FFC (R/ ) Component ID3 Register */

  __IOM uint32_t C_CTLR;                 /*!< Offset: 0x2000 (R/W) CPU Interface Control Register */
  __IOM uint32_t C_PMR;                  /*!< Offset: 0x2004 (R/W) Interrupt Priority Mask Register */
  __IOM uint32_t C_BPR;                  /*!< Offset: 0x2008 (R/W) Binary Point Register */
  __IM  uint32_t C_IAR;                  /*!< Offset: 0x200C (R/ ) Interrupt Acknowledge Register */
  __OM  uint32_t C_EOIR;                 /*!< Offset: 0x2010 ( /W) End Of Interrupt Register */
  __IM  uint32_t C_RPR;                  /*!< Offset: 0x2014 (R/ ) Running Priority Register */
  __IM  uint32_t C_HPPIR;                /*!< Offset: 0x2018 (R/ ) Highest Priority Pending Interrupt Register */
  __IOM uint32_t C_ABPR;                 /*!< Offset: 0x201C (R/W) Aliased Binary Point Register */
  __IM  uint32_t C_AIAR;                 /*!< Offset: 0x2020 (R/ ) Aliased Interrupt Acknowledge Register */
  __OM  uint32_t C_AEOIR;                /*!< Offset: 0x2024 ( /W) Aliased End Of Interrupt Register */
  __IM  uint32_t C_AHPPIR;               /*!< Offset: 0x2028 (R/ ) Aliased Highest Priority Pending Interrupt Register */
        uint32_t RESERVED15[41];
  __IOM uint32_t C_APR0;                 /*!< Offset: 0x20D0 (R/W) Active Priority Register */
        uint32_t RESERVED16[3];
  __IOM uint32_t C_NSAPR0;               /*!< Offset: 0x20E0 (R/W) Non-secure Active Priority Register */
        uint32_t RESERVED17[6];
  __IM  uint32_t C_IIDR;                 /*!< Offset: 0x20FC (R/ ) CPU Interface Identification Register */
        uint32_t RESERVED18[960];
  __OM  uint32_t C_DIR;                  /*!< Offset: 0x3000 ( /W) Deactivate Interrupt Register */
} GIC_Type;


/* For simplicity, we only use group0 of GIC */
FORCEDINLINE __STATIC_INLINE void GIC_Init(void)
{
  uint32_t i;
  uint32_t irqRegs;
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);  /* GIC Base address */

  irqRegs = (gic->D_TYPER & 0x1FUL) + 1;  /* maximum number of interrupts */

  /* On POR, all SPI is in group 0, level-sensitive and using 1-N model */

  /* Disable all PPI, SGI and SPI */
  for (i = 0; i < irqRegs; i++)
    gic->D_ICENABLER[i] = 0xFFFFFFFFUL;

  /* Make all interrupts have higher priority */
  gic->C_PMR = (0xFFUL << (8 - __GIC_PRIO_BITS)) & 0xFFUL;

  /* No subpriority, all priority level allows preemption */
  gic->C_BPR = 7 - __GIC_PRIO_BITS;

  /* Enable group0 distribution */
  gic->D_CTLR = 1UL;

  /* Enable group0 signaling */
  gic->C_CTLR = 1UL;
}

FORCEDINLINE __STATIC_INLINE void GIC_EnableIRQ(IRQn_Type IRQn)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  gic->D_ISENABLER[((uint32_t)(int32_t)IRQn) >> 5] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}

FORCEDINLINE __STATIC_INLINE void GIC_DisableIRQ(IRQn_Type IRQn)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  gic->D_ICENABLER[((uint32_t)(int32_t)IRQn) >> 5] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}

/* Return IRQ number (and CPU source in SGI case) */
FORCEDINLINE __STATIC_INLINE uint32_t GIC_AcknowledgeIRQ(void)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  return gic->C_IAR & 0x1FFFUL;
}

/* value should be got from GIC_AcknowledgeIRQ() */
FORCEDINLINE __STATIC_INLINE void GIC_DeactivateIRQ(uint32_t value)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  gic->C_EOIR = value;
}

FORCEDINLINE __STATIC_INLINE uint32_t GIC_GetRunningPriority(void)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  return gic->C_RPR & 0xFFUL;
}

FORCEDINLINE __STATIC_INLINE void GIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  gic->C_BPR = PriorityGroup & 0x7UL;
}

FORCEDINLINE __STATIC_INLINE uint32_t GIC_GetPriorityGrouping(void)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  return gic->C_BPR & 0x7UL;
}

FORCEDINLINE __STATIC_INLINE void GIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  gic->D_IPRIORITYR[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8UL - __GIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}

FORCEDINLINE __STATIC_INLINE uint32_t GIC_GetPriority(IRQn_Type IRQn)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  return(((uint32_t)gic->D_IPRIORITYR[((uint32_t)(int32_t)IRQn)] >> (8UL - __GIC_PRIO_BITS)));
}


#endif /* __CORE_CA7_H */
View Code

core_ca7.h文件中比較重點的函數如下列表所示:

函數名 函數功能
GIC_Init
GIC控制器初始化
GIC_EnableIRQ
使能指定的IRQ外設中斷
GIC_DisableIRQ
禁止指定的IRQ外設中斷
GIC_AcknowledgeIRQ
返回IRQ外設中斷號
GIC_DeactivateIRQ
使指定的IRQ外設中斷失效
GIC_GetRunningPriority
獲取當前運行的中斷優先級
GIC_SetPriorityGrouping
設置搶占優先級位數
GIC_GetPriorityGrouping
獲取搶占優先級位數
GIC_SetPriority
設置指定IRQ外設中斷優先級
GIC_GetPriority
獲取指定IRQ外設中斷優先級

core_ca7.h文件的內容比較復雜,想要了解GIC驅動的實現,可以仔細研究其源碼。

接下來,需要修改匯編源文件start.S,添加中斷向量表,並實現相應的中斷服務處理函數,start.S的內容如下所示:

.global _start

/**
 *  _start函數,程序先在這開始執行,用來設置C語言運行環境
 */
_start:
    /* 創建中斷向量表 */
    ldr pc, =Reset_Handler      /* 復位中斷 */
    ldr pc, =Undefined_Handler  /* 未定義指令中斷 */
    ldr pc, =SVC_Handler        /* Supervisor中斷 */
    ldr pc, =PrefAbort_Handler  /* 預取終止中斷 */
    ldr pc, =DataAbort_Handler  /* 數據終止中斷 */
    ldr pc, =NotUsed_Handler    /* 未使用中斷 */
    ldr pc, =IRQ_Handler        /* IRQ中斷 */
    ldr pc, =FIQ_Handler        /* FIQ中斷 */

/* 復位中斷服務函數 */
Reset_Handler:
    cpsid i                     /* 關閉全局IRQ中斷 */

    /* 關閉I/D Cache以及MMU */
    mrc p15, 0, r0, c1, c0, 0   /* 讀取CP15協處理器的c1寄存器值到R0中 */
    bic r0, r0, #(1 << 12)      /* 清除c1的I位,關閉I Cache */
    bic r0, r0, #(1 << 2)       /* 清除c1的C位,關閉D Cache */
    bic r0, r0, #(1 << 1)       /* 清除c1的A位,關閉對齊檢查 */
    bic r0, r0, #(1 << 11)      /* 清除c1的Z位,關閉分支預測 */
    bic r0, r0, #(1 << 0)       /* 清除c1的M位,關閉MMU */
    mcr p15, 0, r0, c1, c0, 0   /* 將R0的值寫入到CP15協處理器的c1寄存器中 */

#if 0
    /* 匯編版本設置中斷向量表偏移 */
    ldr r0, =0x87800000

    dsb
    isb
    mcr p15, 0, r0, c12, c0, 0  /* 將R0的值寫入到CP15協處理器的c12寄存器中 */
    dsb
    isb
#endif

    /* SoC進入IRQ運行模式 */
    mrs r0, cpsr            /* 將cpsr寄存器的值讀取到R0中 */
    bic r0, r0, #0x1f       /* 將cpsr寄存器的M[4:0]清0 */
    orr r0, r0, #0x12       /* SoC進入到IRQ運行模式 */
    msr cpsr, r0            /* 將R0的值回寫到cpsr寄存器 */
    ldr sp, =0x80600000     /* 設置IRQ模式下棧指針0x80600000,大小為2MB */

    /* SoC進入System運行模式 */
    mrs r0, cpsr            /* 將cpsr寄存器的值讀取到R0中 */
    bic r0, r0, #0x1f       /* 將cpsr寄存器的M[4:0]清0 */
    orr r0, r0, #0x1f       /* SoC進入到SYS運行模式 */
    msr cpsr, r0            /* 將R0的值回寫到cpsr寄存器 */
    ldr sp, =0x80400000     /* 設置IRQ模式下棧指針0x80400000,大小為2MB */

    /* SoC進入Supervisor運行模式 */
    mrs r0, cpsr            /* 將cpsr寄存器的值讀取到R0中 */
    bic r0, r0, #0x1f       /* 將cpsr寄存器的M[4:0]清0 */
    orr r0, r0, #0x13       /* SoC進入到SVC運行模式 */
    msr cpsr, r0            /* 將R0的值回寫到cpsr寄存器 */
    ldr sp, =0x80200000     /* 設置IRQ模式下棧指針0x80200000,大小為2MB */

    cpsie i                 /* 打開全局IRQ中斷 */

#if 0
    /* 使能IRQ中斷 */
    mrs r0, cpsr            /* 將cpsr寄存器的值讀取到R0中 */
    bic r0, r0, #0x80       /* 將R0寄存器中的bit7清0,允許IRQ中斷 */
    msr cpsr, r0            /* 將R0的值回寫到cpsr寄存器中 */
#endif

    b main                  /* 跳轉到main函數運行 */

/* 未定義指令中斷函數 */
Undefined_Handler:
    ldr r0, =Undefined_Handler
    bx  r0

/* Supervisor中斷服務函數 */
SVC_Handler:
    ldr r0, =SVC_Handler
    bx  r0

/* 預取終止中斷服務函數 */
PrefAbort_Handler:
    ldr r0, =PrefAbort_Handler
    bx  r0

/* 數據終止中斷服務函數 */
DataAbort_Handler:
    ldr r0, =DataAbort_Handler
    bx  r0

/* 未使用的中斷服務函數 */
NotUsed_Handler:
    ldr r0, =NotUsed_Handler
    bx  r0

/* IRQ中斷服務函數 */
IRQ_Handler:
    /* 中斷發生時保護現場 */
    push {lr}           /* 保存lr寄存器(中斷發生時保存PC的值) */
    push {r0-r3, r12}   /* 保存r0-r3,r12寄存器中的值 */

    mrs r0, spsr        /* 讀取spsr寄存器的值到R0寄存器中 */
    push {r0}           /* 保存spsr寄存器 */

    mrc p15, 4, r1, c15, c0, 0  /* 讀取CP15協處理器的c15寄存器值(保存GIC基地址) */
    /* r1=r1+0x2000,得到GIC的CPU Interface端基地址 */
    add r1, r1, #0x2000

    /**
     * CPU Interface端基地址加上0x0C得到
     * GICC_IAR寄存器地址,該寄存器保存着當前
     * 發生IRQ中斷的中斷號,需要根據這個中斷號
     * 調用相應的中斷服務函數。
     */
    ldr r0, [r1, #0x0C]     /* 將GICC_IAR寄存器中的值保存到R0 */
    push {r0, r1}           /* 保存r0(發生IRQ的中斷號),r1(GIC的CPU Interface基地址) */

    cps #0x13               /* SoC進入到SVC模式,允許其它中斷再次進入 */

    push {lr}               /* 保存SVC模式下的lr寄存器 */
    ldr r2, =system_irqhandler  /* 將C中斷服務處理函數地址加載到R2寄存器 */
    blx r2                  /* 調用C中斷服務處理函數(參數為r0) */

    pop {lr}                /* 執行完C中斷服務處理函數,lr出棧 */
    cps #0x12               /* SoC進入到IRQ模式 */
    pop {r0, r1}
    str r0, [r1, #0x10]     /* 中斷執行完成,寫GICC_EOIR寄存器 */

    /* 中斷執行完成需要恢復現場 */
    pop {r0}
    msr spsr_cxsf, r0   /* 恢復spsr寄存器 */

    pop {r0-r3, r12}    /* r0-r3,r12出棧 */
    pop {lr}            /* lr出棧 */
    subs pc, lr, #4     /* 將lr-4賦給pc寄存器 */

/* FIQ中斷服務函數 */
FIQ_Handler:
    ldr r0, =FIQ_Handler
    bx  r0

在start.S文件中,重點關注復位中斷函數Reset_Handler和IRQ中斷服務函數IRQ_Handler,I.MX6UL嵌入式SoC上電復位后進入到復位中斷服務函數Reset_Handler處執行,該函數用來完成一些初始化工作,搭建好C運行環境,最后跳轉到C版本的main函數執行,Reset_Handler進來后,先使用cpsid i指令將全局IRQ中斷關閉,然后通過配置CP15協處理器的相關寄存器,將處理器的I/D Cache、MMU等功能關閉,接下來,初始化不同運行模式下的SP指針,不同運行模式下的棧大小都是2MB,最后,使用cpsie i指令將全局IRQ中斷使能,並跳轉到C版本的main函數處執行。

接下來,就是IRQ中斷服務函數IRQ_Handler,當I.MX6UL芯片的外設產生中斷后,最終處理器會進入IRQ模式,並執行IRQ_Handler中斷服務函數,該函數主要的工作就是進行中斷現場保護,然后去判斷當前發生的外設中斷(通過中斷ID),並針對不同的外設中斷做出相應的處理,中斷處理完成后,需要恢復中斷現場,返回到斷點處繼續執行原來的程序,GICC_IAR寄存器保存了發生IRQ中斷的中斷號,讀取出來后,將中斷號保存到r0寄存器,然后帶參調用C函數system_irqhandler,參數為r0的值,也就是中斷號,system_irqhandler函數就是通過得到的中斷號,進行相應的外設中斷處理的,中斷處理完成后,需要向GICC_EOIR寄存器寫入處理完成的中斷號,以表示外設中斷已經處理完成。

中斷處理完成后,需要將中斷現場恢復,返回到斷點處繼續執行。

接下來,需要實現通用中斷的驅動函數,進入到bsp目錄下,新創建int目錄:

$ cd bsp/bsp
$ mkdir int
$ cd int
$ touch bsp_int.h
$ touch bsp_int.c

bsp_int.h文件的內容如下所示:

#ifndef __BSP_INT_H
#define __BSP_INT_H

#include "imx6ul.h"

/* 中斷處理函數形式 */
typedef void (*system_irq_handler_t)(unsigned int giccIar, void *param);

/* 中斷處理函數結構體 */
struct _sys_irq_handle {
    system_irq_handler_t irqHandler;    /* 中斷處理函數指針 */
    void *userParam;                    /* 中斷處理函數參數 */
};

typedef struct _sys_irq_handle sys_irq_handle_t;

/* 相關函數聲明 */
void system_irqhandler(unsigned int giccIar);
void default_irqhandler(unsigned int giccIar, void *userParam);
void system_register_irqhandler(IRQn_Type irq,
    system_irq_handler_t handler, void *userParam);
void system_irqtable_init(void);
void interrupt_init(void);

#endif

sys_irq_handle_t定義了中斷處理函數結構體,system_irq_handler_t是定義的函數指針,為外設中斷的具體處理,函數有兩個,第一參數為中斷號,第二個為用戶參數,該函數的具體實現過程需要用戶自己具體實現。

bsp_int.c則是通用中斷的驅動函數的實現,文件的內容如下所示:

#include "bsp_int.h"

/* 中斷嵌套計數器 */
static unsigned int irqNesting;

/* 中斷處理函數表 */
static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];

/**
 * default_irqhandler() - 默認的中斷服務處理函數
 * 
 * @giccIar: 中斷號
 * @userParam: 中斷服務處理函數參數
 * 
 * @return: 無
 */
void default_irqhandler(unsigned int giccIar, void *userParam)
{
    while (1) {

    }
}

/**
 * system_irqhandler() - 中斷服務處理函數
 * 匯編中的IRQ中斷服務函數將調用該函數,該
 * 函數通過在中斷服務列表中查找指定中斷號所
 * 對應的中斷處理函數並執行
 * 
 * @giccIar: 中斷號
 * 
 * @return: 無
 */
void system_irqhandler(unsigned int giccIar)
{
    unsigned int intNum = giccIar & 0x3FFUL; /* 獲取中斷號 */

    /* 判斷中斷號是否符合要求 */
    if (intNum >= NUMBER_OF_INT_VECTORS)
        return;
    
    irqNesting++;   /* 中斷嵌套計數器加1 */

    /* 根據傳遞的中斷號,在中斷列表中調用對應的外設中斷處理函數 */
    irqTable[intNum].irqHandler(intNum, irqTable[intNum].userParam);

    irqNesting--;   /* 中斷嵌套計數器減1 */
}

/**
 * system_register_irqhandler() - 注冊中斷服務函數
 * 
 * @irq: 要注冊的中斷號
 * @handler: 要注冊的中斷處理函數
 * @userParam: 中斷處理函數參數
 * 
 * @return: 無
 */
void system_register_irqhandler(IRQn_Type irq,
    system_irq_handler_t handler, void *userParam)
{
    irqTable[irq].irqHandler = handler;
    irqTable[irq].userParam = userParam;
}

/**
 * system_irqtable_init() - 初始化中斷服務函數列表
 * 
 * @param: 無
 * @return: 無
 */
void system_irqtable_init(void)
{
    unsigned int i;
    irqNesting = 0;

    /* 將所有的中斷處理服務函數設置為默認值 */
    for (i = 0; i < NUMBER_OF_INT_VECTORS; i++) {
        system_register_irqhandler((IRQn_Type)i,
            default_irqhandler, NULL);
    }
}

/**
 * interrupt_init() - 中斷初始化函數
 * 
 * @param: 無
 * @return: 無
 */
void interrupt_init(void)
{
    GIC_Init();                             /* 初始化GIC中斷控制器 */
    system_irqtable_init();                 /* 初始化中斷表 */
    __set_VBAR((unsigned int)0x87800000);   /* 設置中斷向量表偏移地址 */
}
NUMBER_OF_INT_VECTORS宏定義在文件MCIMX6G2.h,宏定義的值為160,因為I.MX6UL的中斷源個數為160個,irqTable是實現的具體中斷處理函數表,其實就是一個數組,數組的下標和相應的外設中斷號進行聯系,system_irqhandler()函數就是實現的C版本中斷服務函數,在IRQ_Handler函數執行后,將會調用此函數,通過IRQ中斷號,調用irqTable數組中具體的外設中斷處理函數,interrupt_init()是用來初始化中斷的,包括對GIC中斷控制器初始化,初始化好irqTable中斷函數表,最后,設置中斷向量表的偏移地址為0x87800000。
修改bsp/gpio目錄下的通用GPIO驅動模塊,使得該GPIO驅動模塊除了能實現GPIO的基本輸出和輸入功能以外,還能支持GPIO外部中斷功能:
$ cd bsp/gpio
$ cd gpio
$ vim bsp_gpio.h
$ vim bsp_gpio.c

bsp_gpio.h文件的內容如下所示:

#ifndef __BSP_GPIO_H
#define __BSP_GPIO_H

#include "imx6ul.h"

/* GPIO輸入方向定義 */
typedef enum _gpio_pin_direction {
    kGPIO_DigitalInput = 0U,    /* 表示GPIO方向輸入 */
    kGPIO_DigitalOutput = 1U,   /* 表示GPIO方向輸出 */
} gpio_pin_direction_t;

/* 枚舉GPIO外部中斷觸發類型 */
typedef enum _gpio_interrupt_mode {
    kGPIO_NoIntmode = 0U,               /* 無中斷觸發功能 */
    kGPIO_IntLowLevel = 1U,             /* 低電平觸發 */
    kGPIO_IntHighLevel = 2U,            /* 高電平觸發 */
    kGPIO_IntRisingEdge = 3U,           /* 上升沿觸發 */
    kGPIO_IntFallingEdge = 4U,          /* 下降沿觸發 */
    kGPIO_IntRisingOrFallingEdge = 5U,  /* 雙邊沿觸發 */
} gpio_interrupt_mode_t;

/* GPIO引腳配置結構體 */
typedef struct _gpio_pin_config {
    gpio_pin_direction_t direction;         /* GPIO的方向 */
    unsigned char value;                    /* GPIO輸出時默認引腳電平值 */
    gpio_interrupt_mode_t interruptmode;    /* 中斷觸發方式 */
} gpio_pin_config_t;

/* GPIO操作函數相關聲名 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config);
int gpio_pin_read(GPIO_Type *base, int pin);
void gpio_pin_write(GPIO_Type *base, int pin, int value);

/* GPIO中斷相關操作函數聲明 */
void gpio_interrupt_config(GPIO_Type *base, int pin,
        gpio_interrupt_mode_t interruptmode);
void gpio_enable_interrupt(GPIO_Type *base, int pin);
void gpio_disable_interrupt(GPIO_Type *base, int pin);
void gpio_clear_int_flags(GPIO_Type *base, int pin);

#endif

gpio_interrupt_mode_t為枚舉類型,枚舉了GPIO所支持的所有中斷觸發類型,在GPIO引腳配置結構體gpio_pin_config_t添加interruptmode成員變量,用來表示GPIO中斷的觸發類型。

bsp_gpio.c為通用GPIO驅動模塊的具體實現,該文件的內容如下所示:

#include "bsp_gpio.h"

/**
 * gpio_init() - GPIO初始化函數
 * 
 * @base: 要初始化的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要初始化的GPIO組的pin編號
 * @config: gpio引腳配置結構體
 * 
 * @return: 無
 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
    if (config->direction == kGPIO_DigitalInput) /* GPIO方向為輸入 */
        base->GDIR &= ~(1 << pin);
    else {
        base->GDIR |= (1 << pin);
        gpio_pin_write(base, pin, config->value);
    }

    gpio_interrupt_config(base, pin, config->interruptmode); /* GPIO中斷配置 */
}

/**
 * gpio_pin_read() - 讀取GPIO引腳的電平
 * 
 * @base: 要讀取的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要讀取的GPIO組的pin編號
 * 
 * @return: 0表示低電平,1表示高電平
 */
int gpio_pin_read(GPIO_Type *base, int pin)
{
    return (((base->DR) >> pin) & 0x1);
}

/**
 * gpio_pin_write() - 設置GPIO引腳的電平
 * 
 * @base: 要設置的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要設置的GPIO組的pin編號
 * @value: 引腳要設置的電平值:0->低電平,1->高電平
 * 
 * @return: 無
 */
void gpio_pin_write(GPIO_Type *base, int pin, int value)
{
    if (0 == value)
        base->DR &= ~(1 << pin); /* 引腳輸出低電平 */
    else
        base->DR |= (1 << pin); /* 引腳輸出高電平 */
}

/**
 * gpio_interrupt_config() - 設置GPIO中斷觸發配置
 * 
 * @base: 要設置的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要設置的GPIO組的pin編號
 * @interruptmode: 要設置的GPIO中斷觸發方式
 * 
 * @return: 無
 */
void gpio_interrupt_config(GPIO_Type *base, int pin,
        gpio_interrupt_mode_t interruptmode)
{
    volatile unsigned int *icr;
    unsigned int icrshift = pin;

    base->EDGE_SEL &= ~(1 << pin);  /* 雙邊沿觸發寄存器清0 */
    base->IMR &= ~(1 << pin);   /* 禁止GPIO中斷 */

    if (pin < 16) {
        icr = &(base->ICR1);    /* GPIOx_IO00~GPIOx_IO15 */
    } else {
        icr = &(base->ICR2);    /* GPIOx_IO16~GPIOx_IO31 */
        icrshift -= 16;
    }

    *icr &= ~(3 << (2 * icrshift));
    switch (interruptmode) {
    case (kGPIO_IntLowLevel):
        *icr |= (0 << (2 * icrshift));
        break;
    case (kGPIO_IntHighLevel):
        *icr |= (1 << (2 * icrshift));
        break;
    case (kGPIO_IntRisingEdge):
        *icr |= (2 << (2 * icrshift));
        break;
    case (kGPIO_IntFallingEdge):
        *icr |= (3 << (2 * icrshift));
        break;
    case (kGPIO_IntRisingOrFallingEdge):
        base->EDGE_SEL |= (1 << pin);
        break;
    default:
        break;
    }
}

/**
 * gpio_enable_interrupt() - 使能GPIO引腳中斷
 * 
 * @base: 要設置的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要設置的GPIO組的pin編號
 * 
 * @return: 無
 */
void gpio_enable_interrupt(GPIO_Type *base, int pin)
{
    base->IMR |= (1 << pin);
}

/**
 * gpio_disable_interrupt() - 禁止GPIO引腳中斷
 * 
 * @base: 要設置的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要設置的GPIO組的pin編號
 * 
 * @return: 無
 */
void gpio_disable_interrupt(GPIO_Type *base, int pin)
{
    base->IMR &= ~(1 << pin);
}

/**
 * gpio_clear_int_flags() - 清除GPIO中斷標志位
 * 
 * @base: 要設置的GPIO組,例如:GPIO1、GPIO2
 * @pin: 要設置的GPIO組的pin編號
 * 
 * @return: 無
 */
void gpio_clear_int_flags(GPIO_Type *base, int pin)
{
    base->ISR |= (1 << pin);    /* 寫1清除中斷標志位 */
}

需要添加GPIO外部中斷的驅動函數實現,和GPIO中斷相關的函數功能如下:

函數 實現功能
gpio_interrupt_config
對GPIO中斷進行配置
gpio_enable_interrupt
GPIO中斷使能
gpio_disable_interrupt
GPIO中斷禁止
gpio_clear_int_flags
清除GPIO中斷標志位

實現按鍵驅動模塊,按鍵驅動就是GPIO外部中斷的簡單實例,使用到的是CSI_DATA02這個引腳,需要將該引腳復用為GPIO功能,復用后,該引腳的標簽為GPIO4_IO23,新創建bsp/exit目錄,用來保存按鍵驅動模塊的文件:

$ cd bsp
$ mkdir exit
$ cd exit
$ touch bsp_exit.h
$ touch bsp_exit.c

bsp_exit.h文件的內容如下所示:

#ifndef __BSP_EXIT_H
#define __BSP_EXIT_H

#include "imx6ul.h"

void gpio_exit_init(void);
void gpio4_io23_irqhander(unsigned int giccIar, void *userParam);

#endif

該文件主要是按鍵中斷函數的相關聲明,bsp_exit.c文件的內容如下:

#include "bsp_exit.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_delay.h"
#include "bsp_led.h"

/**
 * gpio_exit_init() - GPIO外部中斷初始化
 * 
 * @param: 無
 * @return: 無
 */
void gpio_exit_init(void)
{
    gpio_pin_config_t key_config;

    /* 設置CSI_DATA02引腳IO口復用為GPIO4_IO23 */
    IOMUXC_SetPinMux(IOMUXC_CSI_DATA02_GPIO4_IO23, 0);

    /**
     * 配置GPIO4_IO23引腳電氣屬性
     * bit[16]: 0 關閉HYS
     * bit[15:14]: 11 pull up 22k
     * bit[13]: 1 pull
     * bit[12]: 1 pull/keeper使能
     * bit[11]: 0 禁止開路輸出
     * bit[10:8]: 000 resered
     * bit[7:6]: 10 速度為100MHz
     * bit[5:3]: 000 關閉輸出
     * bit[2:1]: 00 resered
     * bit[0]: 0 低擺率
     */
    IOMUXC_SetPinConfig(IOMUXC_CSI_DATA02_GPIO4_IO23, 0xF080);

    /* 將按鍵相關的GPIO方向設置為輸入,並配置中斷 */
    key_config.direction = kGPIO_DigitalInput;
    key_config.interruptmode = kGPIO_IntFallingEdge;
    key_config.value = 1;
    gpio_init(GPIO4, 23, &key_config);

    /* 使能GIC中斷控制器,注冊GPIO中斷服務函數並使能中斷 */
    GIC_EnableIRQ(GPIO4_Combined_16_31_IRQn);
    system_register_irqhandler(GPIO4_Combined_16_31_IRQn,
        (system_irq_handler_t)gpio4_io23_irqhander, NULL);
    gpio_enable_interrupt(GPIO4, 23);
}

/**
 * gpio4_io23_irqhander() - GPIO4_IO23中斷服務處理函數
 * 
 * @giccIar: 中斷號
 * @userParam: 用戶參數
 * 
 * @return: 無
 */
void gpio4_io23_irqhander(unsigned int giccIar, void *userParam)
{
    static unsigned char led2_state = OFF;

    /**
     * 采用簡單延時消抖,但是中斷服務處理函數中
     * 禁止使用延時函數,因為中斷服務處理需要快進
     * 快出。
     */
    delay(10);
    if (gpio_pin_read(GPIO4, 23) == 0) {
        led2_state = !led2_state;
        led_switch(LED2, led2_state);
    }

    gpio_clear_int_flags(GPIO4, 23); /* 清除GPIO4_IO23中斷標志位 */
}
gpio_exit_init()是GPIO外部中斷的初始化函數,函數調用后,先要設置CSI_DATA02引腳復用為GPIO4_IO23,然后配置GPIO4_IO23引腳的電氣特性,設置GPIO的方向為輸入,並且配置中斷的觸發類型為下降沿觸發,調用GIC_EnableIRQ()在GIC中斷控制器中使能IRQ,另外還需要注冊GPIO外部中斷服務函數gpio4_io23_irqhander(),該函數就是IRQ中斷發生后,需要具體處理外設設備的中斷函數,該函數的實現比較簡單,GPIO外部中斷產生后,進行LED燈狀態的翻轉,效果就是,每當按鍵按下后,LED燈的狀態進行翻轉,最后,還需要清除GPIO外部中斷標志位。
編寫app.c文件,實現main()函數,文件內容如下:
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_gpio.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_exit.h"

/**
 * main() - 主函數
 */
int main(void)
{
    unsigned char led1_state = OFF;

    interrupt_init();       /* 中斷初始化 */
    imx6ul_clk_init();      /* 初始化相關時鍾 */
    system_clk_enable();    /* 系統外設時鍾使能 */
    led_init();             /* LED燈初始化 */
    gpio_exit_init();       /* GPIO外部中斷初始化 */

    while (1) {
        led1_state = !led1_state;
        led_switch(LED1, led1_state);
        delay(500);
    }

    return 0;
}

main()函數比較簡單,函數調用后,將相關的外設進行初始化后即可。

 

3、小結

本文主要簡單介紹了I.MX6UL嵌入式SoC中的GPIO外部中斷功能的使用,通過一個簡單的按鍵驅動實例進行介紹。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM