MDK环境 GPIO输入中断分析
通过GPIO终端输入例程来学习了中断配置。 例程例程:按键K3触发中断,进入中断后,通过串口打印出按键信息。
一、硬件电路:
<ignore_js_op>
<ignore_js_op>
K3按键进入RT1052的L6引脚,对应的端口是GPIO5_IO00。
<ignore_js_op>
二、程序:
2.1、主程序:
int main(void)
{
gpio_pin_config_t sw_config = {
kGPIO_DigitalInput, 0, //端口设置为输入
kGPIO_IntRisingEdge, //端口设置为上升沿中断
};
BOARD_ConfigMPU();
BOARD_InitPins(); //初始化引脚
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("GPIO Driver example.\r\n");
EnableIRQ(EXAMPLE_SW_IRQ); //使能中断
GPIO_PinInit(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN, &sw_config); //初始化GPIO5_IO00引脚
GPIO_PortEnableInterrupts(EXAMPLE_SW_GPIO, 1U << EXAMPLE_SW_GPIO_PIN);
while(1)
{
if(g_InputSignal)
{
delay();
if(1 == GPIO_PinRead(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN))
{
PRINTF("%s is turned on.\r\n", EXAMPLE_SW_NAME);
}
g_InputSignal = false;
}
}
}
//中断程序
void EXAMPLE_GPIO_IRQHandler(void)
{
GPIO_PortClearInterruptFlags(EXAMPLE_SW_GPIO, 1U << EXAMPLE_SW_GPIO_PIN);
g_InputSignal = true;
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}
2.2、对上面红色字体的函数进行分析
2.2.1、 BOARD_InitPins(); //初始化引脚
这个函数在 pin_mux.c中定义
void BOARD_InitPins(void)
{
CLOCK_EnableClock(kCLOCK_Iomuxc);
CLOCK_EnableClock(kCLOCK_IomuxcSnvs);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0U); //复用GPIO引脚设置为串口1
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0U);
IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00, 0U); //GPIO5_IO00配置为输入
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0x10B0u);
}
2.2.2、 EnableIRQ(EXAMPLE_SW_IRQ); //使能中断
这个函数在fsl_common.h中定义
static inline status_t EnableIRQ(IRQn_Type interrupt)
{
if (NotAvail_IRQn == interrupt)
{
return kStatus_Fail;
}
NVIC_EnableIRQ(interrupt);
return kStatus_Success;
}
IRQn_Type结构中有关GPIO口的定义:
typedef enum IRQn {
/* Auxiliary constants */
NotAvail_IRQn = -128, /**< Not available device specific interrupt */
GPIO1_INT0_IRQn = 72, /**< Active HIGH Interrupt from INT0 from GPIO */
GPIO1_INT1_IRQn = 73, /**< Active HIGH Interrupt from INT1 from GPIO */
GPIO1_INT2_IRQn = 74, /**< Active HIGH Interrupt from INT2 from GPIO */
GPIO1_INT3_IRQn = 75, /**< Active HIGH Interrupt from INT3 from GPIO */
GPIO1_INT4_IRQn = 76, /**< Active HIGH Interrupt from INT4 from GPIO */
GPIO1_INT5_IRQn = 77, /**< Active HIGH Interrupt from INT5 from GPIO */
GPIO1_INT6_IRQn = 78, /**< Active HIGH Interrupt from INT6 from GPIO */
GPIO1_INT7_IRQn = 79, /**< Active HIGH Interrupt from INT7 from GPIO */
GPIO1_Combined_0_15_IRQn = 80, /**< Combined interrupt indication for GPIO1 signal 0 throughout 15 */
GPIO1_Combined_16_31_IRQn = 81, /**< Combined interrupt indication for GPIO1 signal 16 throughout 31 */
GPIO2_Combined_0_15_IRQn = 82, /**< Combined interrupt indication for GPIO2 signal 0 throughout 15 */
GPIO2_Combined_16_31_IRQn = 83, /**< Combined interrupt indication for GPIO2 signal 16 throughout 31 */
GPIO3_Combined_0_15_IRQn = 84, /**< Combined interrupt indication for GPIO3 signal 0 throughout 15 */
GPIO3_Combined_16_31_IRQn = 85, /**< Combined interrupt indication for GPIO3 signal 16 throughout 31 */
GPIO4_Combined_0_15_IRQn = 86, /**< Combined interrupt indication for GPIO4 signal 0 throughout 15 */
GPIO4_Combined_16_31_IRQn = 87, /**< Combined interrupt indication for GPIO4 signal 16 throughout 31 */
GPIO5_Combined_0_15_IRQn = 88, /**< Combined interrupt indication for GPIO5 signal 0 throughout 15 */
GPIO5_Combined_16_31_IRQn = 89, /**< Combined interrupt indication for GPIO5 signal 16 throughout 31 */
} IRQn_Type;
>中断使能参数定义:
#define EXAMPLE_SW_IRQ BOARD_USER_BUTTON_IRQ
#define BOARD_USER_BUTTON_IRQ GPIO5_Combined_0_15_IRQn
调用EnableIRQ(EXAMPLE_SW_IRQ); 函数的参数就是上面定义的中断号为88
NVIC_EnableIRQ(interrupt);函数定义:
#define NVIC_EnableIRQ __NVIC_EnableIRQ
__NVIC_EnableIRQ函数定义:
/**
\brief Enable Interrupt
\details Enables a device specific interrupt in the NVIC interrupt controller.
\param [in] IRQn Device specific interrupt number.
\note IRQn must not be negative.
*/
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
}
NVIC内存映射地址:
#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
NVIC结构体的定义:
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC)
\brief Type definitions for the NVIC Registers
@{
*/
typedef struct
{
__IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[24U];
__IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[24U];
__IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[24U];
__IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[24U];
__IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */
uint32_t RESERVED4[56U];
__IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644U];
__OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */
} NVIC_Type;
ISER映射的地址就是:0xE000E100UL
这个地址在RT1052手册中没有找到,从上面的定义说明可以看出来,这是CMSIS_core_register 内核寄存器。
没有找到M7内核资料,从Cortex-M3权威指南中找到相关寄存器:
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
2.2.3、GPIO_PortEnableInterrupts(EXAMPLE_SW_GPIO, 1U << EXAMPLE_SW_GPIO_PIN);
这个函数在fsl_gpio.c中定义
void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *Config)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable GPIO clock. */
CLOCK_EnableClock(s_gpioClock[GPIO_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/* Register reset to default value */
base->IMR &= ~(1U << pin);
/* Configure GPIO pin direction */
if (Config->direction == kGPIO_DigitalInput) //GPIO设置为输入
{
base->GDIR &= ~(1U << pin);
}
else
{
GPIO_PinWrite(base, pin, Config->outputLogic);
base->GDIR |= (1U << pin);
}
/* Configure GPIO pin interrupt mode */
GPIO_SetPinInterruptConfig(base, pin, Config->interruptMode); //配置中断模式,程序开始就设置为上升沿中断模式
}
RT1052手册中有关GPIO中断配置相关的寄存器
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
三、实验结果:
通过对上面寄存器的分析,对GPIO中断配置有了新的认识。
<ignore_js_op>
一、硬件电路:
<ignore_js_op>
<ignore_js_op>
K3按键进入RT1052的L6引脚,对应的端口是GPIO5_IO00。
<ignore_js_op>
二、程序:
2.1、主程序:
int main(void)
{
gpio_pin_config_t sw_config = {
kGPIO_DigitalInput, 0, //端口设置为输入
kGPIO_IntRisingEdge, //端口设置为上升沿中断
};
BOARD_ConfigMPU();
BOARD_InitPins(); //初始化引脚
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("GPIO Driver example.\r\n");
EnableIRQ(EXAMPLE_SW_IRQ); //使能中断
GPIO_PinInit(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN, &sw_config); //初始化GPIO5_IO00引脚
GPIO_PortEnableInterrupts(EXAMPLE_SW_GPIO, 1U << EXAMPLE_SW_GPIO_PIN);
while(1)
{
if(g_InputSignal)
{
delay();
if(1 == GPIO_PinRead(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN))
{
PRINTF("%s is turned on.\r\n", EXAMPLE_SW_NAME);
}
g_InputSignal = false;
}
}
}
//中断程序
void EXAMPLE_GPIO_IRQHandler(void)
{
GPIO_PortClearInterruptFlags(EXAMPLE_SW_GPIO, 1U << EXAMPLE_SW_GPIO_PIN);
g_InputSignal = true;
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}
2.2、对上面红色字体的函数进行分析
2.2.1、 BOARD_InitPins(); //初始化引脚
这个函数在 pin_mux.c中定义
void BOARD_InitPins(void)
{
CLOCK_EnableClock(kCLOCK_Iomuxc);
CLOCK_EnableClock(kCLOCK_IomuxcSnvs);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0U); //复用GPIO引脚设置为串口1
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0U);
IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00, 0U); //GPIO5_IO00配置为输入
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0x10B0u);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0x10B0u);
}
2.2.2、 EnableIRQ(EXAMPLE_SW_IRQ); //使能中断
这个函数在fsl_common.h中定义
static inline status_t EnableIRQ(IRQn_Type interrupt)
{
if (NotAvail_IRQn == interrupt)
{
return kStatus_Fail;
}
NVIC_EnableIRQ(interrupt);
return kStatus_Success;
}
IRQn_Type结构中有关GPIO口的定义:
typedef enum IRQn {
/* Auxiliary constants */
NotAvail_IRQn = -128, /**< Not available device specific interrupt */
GPIO1_INT0_IRQn = 72, /**< Active HIGH Interrupt from INT0 from GPIO */
GPIO1_INT1_IRQn = 73, /**< Active HIGH Interrupt from INT1 from GPIO */
GPIO1_INT2_IRQn = 74, /**< Active HIGH Interrupt from INT2 from GPIO */
GPIO1_INT3_IRQn = 75, /**< Active HIGH Interrupt from INT3 from GPIO */
GPIO1_INT4_IRQn = 76, /**< Active HIGH Interrupt from INT4 from GPIO */
GPIO1_INT5_IRQn = 77, /**< Active HIGH Interrupt from INT5 from GPIO */
GPIO1_INT6_IRQn = 78, /**< Active HIGH Interrupt from INT6 from GPIO */
GPIO1_INT7_IRQn = 79, /**< Active HIGH Interrupt from INT7 from GPIO */
GPIO1_Combined_0_15_IRQn = 80, /**< Combined interrupt indication for GPIO1 signal 0 throughout 15 */
GPIO1_Combined_16_31_IRQn = 81, /**< Combined interrupt indication for GPIO1 signal 16 throughout 31 */
GPIO2_Combined_0_15_IRQn = 82, /**< Combined interrupt indication for GPIO2 signal 0 throughout 15 */
GPIO2_Combined_16_31_IRQn = 83, /**< Combined interrupt indication for GPIO2 signal 16 throughout 31 */
GPIO3_Combined_0_15_IRQn = 84, /**< Combined interrupt indication for GPIO3 signal 0 throughout 15 */
GPIO3_Combined_16_31_IRQn = 85, /**< Combined interrupt indication for GPIO3 signal 16 throughout 31 */
GPIO4_Combined_0_15_IRQn = 86, /**< Combined interrupt indication for GPIO4 signal 0 throughout 15 */
GPIO4_Combined_16_31_IRQn = 87, /**< Combined interrupt indication for GPIO4 signal 16 throughout 31 */
GPIO5_Combined_0_15_IRQn = 88, /**< Combined interrupt indication for GPIO5 signal 0 throughout 15 */
GPIO5_Combined_16_31_IRQn = 89, /**< Combined interrupt indication for GPIO5 signal 16 throughout 31 */
} IRQn_Type;
>中断使能参数定义:
#define EXAMPLE_SW_IRQ BOARD_USER_BUTTON_IRQ
#define BOARD_USER_BUTTON_IRQ GPIO5_Combined_0_15_IRQn
调用EnableIRQ(EXAMPLE_SW_IRQ); 函数的参数就是上面定义的中断号为88
NVIC_EnableIRQ(interrupt);函数定义:
#define NVIC_EnableIRQ __NVIC_EnableIRQ
__NVIC_EnableIRQ函数定义:
/**
\brief Enable Interrupt
\details Enables a device specific interrupt in the NVIC interrupt controller.
\param [in] IRQn Device specific interrupt number.
\note IRQn must not be negative.
*/
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
}
NVIC内存映射地址:
#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
NVIC结构体的定义:
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC)
\brief Type definitions for the NVIC Registers
@{
*/
typedef struct
{
__IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[24U];
__IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[24U];
__IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[24U];
__IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[24U];
__IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */
uint32_t RESERVED4[56U];
__IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644U];
__OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */
} NVIC_Type;
ISER映射的地址就是:0xE000E100UL
这个地址在RT1052手册中没有找到,从上面的定义说明可以看出来,这是CMSIS_core_register 内核寄存器。
没有找到M7内核资料,从Cortex-M3权威指南中找到相关寄存器:
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
2.2.3、GPIO_PortEnableInterrupts(EXAMPLE_SW_GPIO, 1U << EXAMPLE_SW_GPIO_PIN);
这个函数在fsl_gpio.c中定义
void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *Config)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Enable GPIO clock. */
CLOCK_EnableClock(s_gpioClock[GPIO_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/* Register reset to default value */
base->IMR &= ~(1U << pin);
/* Configure GPIO pin direction */
if (Config->direction == kGPIO_DigitalInput) //GPIO设置为输入
{
base->GDIR &= ~(1U << pin);
}
else
{
GPIO_PinWrite(base, pin, Config->outputLogic);
base->GDIR |= (1U << pin);
}
/* Configure GPIO pin interrupt mode */
GPIO_SetPinInterruptConfig(base, pin, Config->interruptMode); //配置中断模式,程序开始就设置为上升沿中断模式
}
RT1052手册中有关GPIO中断配置相关的寄存器
<ignore_js_op>
<ignore_js_op>
<ignore_js_op>
三、实验结果:
通过对上面寄存器的分析,对GPIO中断配置有了新的认识。
<ignore_js_op>