HPM6750系列--第九篇 GPIO详解(中断操作)

一、目的

        在上篇中《HPM6750系列--第九篇 GPIO详解(基本操作)》我们讲解了GPIO的基本操作,本篇继续讲解GPIO的中断处理。

        

二、介绍

        将一个引脚设置为中断涉及到以下几个步骤(此处我们以PZ02举例):

        1.设置IOC/PIOC/BIO中对应的引脚复用为gpio功能
void init_gpio_pins(void)
{
    uint32_t pad_ctl = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1);

#ifdef USING_GPIO0_FOR_GPIOZ
    HPM_IOC->PAD[IOC_PAD_PZ02].FUNC_CTL = IOC_PZ02_FUNC_CTL_GPIO_Z_02;  //②
    HPM_IOC->PAD[IOC_PAD_PZ02].PAD_CTL = pad_ctl; //③
    /* PZ port IO needs to configure BIOC as well */
    HPM_BIOC->PAD[IOC_PAD_PZ02].FUNC_CTL = IOC_PZ02_FUNC_CTL_SOC_PZ_02; //①
#endif 
}

        PZ02是电池备份域的IO,由HPM_BIOC设置复用功能,如果需要GPIO0来控制的话,需要先映射到IOC,再由HPM_IOC来复用成GPIO。

        ①HPM_BIOC将PZ02复用为SOC_PZ_02,也就是由HPM_IOC来决定其复用功能

        ②HPM_IOC将PZ02复用为GPIO

        ③设置为内部上拉

        经过上面的设置之后,PZ02就由GPIO0来进行后续的方向设置、中断配置        

        2.设置引脚为输入

        


/**
 * @brief   Set pin to output mode
 *
 * @param ptr GPIO base address
 * @param port Port index
 * @param pin Pin index
 */
static inline void gpio_set_pin_output(GPIO_Type *ptr, uint32_t port, uint8_t pin)
{
    ptr->OE[port].SET = 1 << pin;
}

void gpio_config_pin_interrupt(GPIO_Type *ptr, uint32_t gpio_index, uint8_t pin_index, gpio_interrupt_trigger_t trigger)
{
    switch (trigger) {
    case gpio_interrupt_trigger_level_high:
    case gpio_interrupt_trigger_level_low:
        ptr->TP[gpio_index].CLEAR = 1 << pin_index;
        if (trigger == gpio_interrupt_trigger_level_high) {
            ptr->PL[gpio_index].CLEAR = 1 << pin_index;
        } else {
            ptr->PL[gpio_index].SET = 1 << pin_index;
        }
        break;
    case gpio_interrupt_trigger_edge_falling:
    case gpio_interrupt_trigger_edge_rising:
#if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)
        ptr->PD[gpio_index].CLEAR = 1 << pin_index;
#endif
        ptr->TP[gpio_index].SET = 1 << pin_index;
        if (trigger == gpio_interrupt_trigger_edge_rising) {
            ptr->PL[gpio_index].CLEAR = 1 << pin_index;
        } else {
            ptr->PL[gpio_index].SET = 1 << pin_index;
        }
        break;
#if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)
    case gpio_interrupt_trigger_edge_both:
        ptr->TP[gpio_index].SET = 1 << pin_index;
        ptr->PD[gpio_index].SET = 1 << pin_index;
        break;
#endif
    default:
        return;
    }
}

void test_gpio_input_interrupt(void)
{
    gpio_interrupt_trigger_t trigger;

    printf("input interrupt\n");
#ifdef BOARD_LED_GPIO_CTRL
    printf("user led will be switched on off based on user switch\n");
    gpio_set_pin_output(BOARD_LED_GPIO_CTRL, BOARD_LED_GPIO_INDEX,
                           BOARD_LED_GPIO_PIN);
#endif
    gpio_set_pin_input(BOARD_APP_GPIO_CTRL, BOARD_APP_GPIO_INDEX,
                           BOARD_APP_GPIO_PIN); //①
#if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)
    trigger = gpio_interrupt_trigger_edge_both;
#else
    trigger = gpio_interrupt_trigger_edge_falling;
#endif
    gpio_config_pin_interrupt(BOARD_APP_GPIO_CTRL, BOARD_APP_GPIO_INDEX,
                           BOARD_APP_GPIO_PIN, trigger); //②
    gpio_enable_pin_interrupt(BOARD_APP_GPIO_CTRL, BOARD_APP_GPIO_INDEX,
                           BOARD_APP_GPIO_PIN); //③
    intc_m_enable_irq_with_priority(BOARD_APP_GPIO_IRQ, 1); //④
    while (1) {
        __asm("wfi");
    }
}

         

        ①设置PZ02为输入引脚。 

        ②设置边沿中断,下降沿触发

        ③使能中断

        ④设置中断优先级

        HPM6750系列--第九篇 GPIO详解(中断操作)_第1张图片

        用户可以通过 GPIO 控制器的 IE 寄存器打开 GPIO 中断,IE 寄存器内的对应位置 1 就可以使能对应 IO 的中断。

        HPM6750系列--第九篇 GPIO详解(中断操作)_第2张图片

        用户可以通过 GPIO 控制器的 TP 寄存器来指定中断的类型,对应位置 1,表示中断由边沿触发,对应位置0,表示中断由电平触发

        HPM6750系列--第九篇 GPIO详解(中断操作)_第3张图片

        用户可以通过 GPIO 控制器的 PL 寄存器来指定中断的极性,对应位置 1,表示中断由下降沿或者低电平触发,对应位置 0,表示中断由上升沿或高电平触发。

        HPM6750系列--第九篇 GPIO详解(中断操作)_第4张图片

        用户可以通过 GPIO 控制器的 IF 寄存器来查询中断的状态,对应标志位置 1,表示对应 IO 有中断待处理。

        3.注册中断函数
        
void isr_gpio(void)
{
    gpio_clear_pin_interrupt_flag(BOARD_APP_GPIO_CTRL, BOARD_APP_GPIO_INDEX,
                        BOARD_APP_GPIO_PIN);
#ifdef BOARD_LED_GPIO_CTRL
    gpio_toggle_pin(BOARD_LED_GPIO_CTRL, BOARD_LED_GPIO_INDEX,
                          BOARD_LED_GPIO_PIN);
    printf("toggle led pin output\n");
#else
#if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)
    if (gpio_read_pin(BOARD_APP_GPIO_CTRL, BOARD_APP_GPIO_INDEX, BOARD_APP_GPIO_PIN) == false) {
        printf("user key pressed\n");
    } else {
        printf("user key released\n");
    }
#else
    printf("user key pressed\n");
#endif
#endif

}
SDK_DECLARE_EXT_ISR_M(BOARD_APP_GPIO_IRQ, isr_gpio)

        在中断函数中清除HPM_GPIO0.PZ.02中断标志位。

        

三、实战

        首先拷贝gpio工程

cp -r $HPM_SDK_BASE/samples/drivers/gpio ~/workspace/work/hpm
cd ~/workspace/work/hpm/gpio
cp -r ~/workspace/work/hpm/hello_world/.vscode ~/workspace/work/hpm/gpio/
code .

        HPM6750系列--第九篇 GPIO详解(中断操作)_第5张图片 

HPM6750系列--第九篇 GPIO详解(中断操作)_第6张图片 

        选择flash_xip编译并进入调试窗口,然后我们按一下开发板上的PBUTN按键,就会触发中断,我们在中断中添加断点。

HPM6750系列--第九篇 GPIO详解(中断操作)_第7张图片

        通过查看IF[GPIOZ]我们发现其值为0x4,也就是bit2为1,说明中断触发了。

        然后我们继续执行发现IF[GPIOZ]变成了0x0,因为中断处理函数中我们需要清除中断标志。

        另外串口打印中也有中断触发的打印信息。

HPM6750系列--第九篇 GPIO详解(中断操作)_第8张图片 

        至此本篇的内容就结束了,主要讲解了IO映射、IO中断的类型、中断注册以及中断使能。

        

 

        

        

你可能感兴趣的:(嵌入式硬件,risc-v,mcu)