16. GPIO

16.1. 概述

GPIO示例工程演示了控制GPIO引脚输出电平变化和输入引脚触发中断的功能。

16.2. 硬件设置

无特殊设置

16.3. 已知问题

当GPIO用作按键输入引脚检测时,受按键机械抖动影响,输入电平抖动,会造成GPIO多次检测到输入电平变化的情况。

16.4. 运行现象

  • 支持双沿触发模式的芯片,工程配置的是双沿触发模式,每次按键按下和释放都会翻转一次LED状态,并打印两次LED切换输出。

  • 当工程正确运行后,可以观察到LED闪烁5次,之后按下GPIO按键(请确认具体开发板 按键 部分描述)可以翻转LED的状态,串口终端会输出如下信息:

toggling led 5 times in total
toggling led 1/5 times
toggling led 2/5 times
toggling led 3/5 times
toggling led 4/5 times
toggling led 5/5 times
input interrupt
user led will be switched on off based on user switch
toggle led pin output
toggle led pin output

16.5. API使用说明

  • 输入输出模块包括通用IO控制模块IOC,GPIO控制器和快速GPIO控制器,以及GPIO管理器。

  • 更多内容请参考 hpm_gpio_drv.h 的API说明以及相关用户手册。

  • 快速GPIO控制器,以及GPIO管理器的使用可参考 gpiom 例子

16.5.1. IO初始化

  • 主要是初始化通用IO控制模块IOC,包括配置IO的属性 PAD_CTL 以及IO的外设功能 FUNC_CTL

  • 电源管理域IO控制器PIOC,控制PY端口,功能与通用IOC一致。

  • 电池备份域IO控制器BIOC,控制PZ端口,功能与通用IOC一致。

16.5.1.1. 配置IO的属性 PAD_CTL

  • PAD_CTL 主要用来配置IO的电气特性,比如开漏选择、驱动强度、上下拉等。 对应的定义可以查看 hpm_ioc_regs.h 头文件 。

  • 举例:

    /* 配置 PA09的IO属性为上拉使能,施密特触发器使能  */
    HPM_IOC->PAD[IOC_PAD_PA09].PAD_CTL = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_HYS_SET(1);
    

16.5.1.2. IO的外设功能 FUNC_CTL

  • FUNC_CTL 包括输出回送功能(LOOP_BACK),模拟功能(ANALOG)和外设功能映(ALT_SELECT)。 对应的定义可以查看 hpm_iomux.h 头文件 。

    • 输出回送功能(LOOP_BACK)主要作用于一些需要时钟反馈的外设,比如SPI的SCLK,I2C的SCL等等。

    • 模拟功能(ANALOG)主要作用于一些需要模拟信号的外设,比如ADC,MIPI信号等等。

    • 外设功能映(ALT_SELECT)主要作用于一些需要映射到特定功能的IO,比如GPIO,I2C,SPI等等。

  • 注意

    • 对于GPIOY的IO,需要在IOC的FUNC_CTL配置IO的功能为GPIO。

      • 例如:配置PY06的功能为uart1的rxd。

        HPM_PIOC->PAD[IOC_PAD_PY06].FUNC_CTL = PIOC_PY06_FUNC_CTL_SOC_PY_06;
        HPM_IOC->PAD[IOC_PAD_PY06].FUNC_CTL = IOC_PY06_FUNC_CTL_UART1_RXD;
        
    • 对于GPIOZ的IO,需要在IOC的FUNC_CTL配置IO的功能为GPIO。

      • 例如:配置PZ02的功能为GPIO。

        HPM_IOC->PAD[IOC_PAD_PZ02].FUNC_CTL = IOC_PZ02_FUNC_CTL_GPIO_Z_02;
        HPM_BIOC->PAD[IOC_PAD_PZ02].FUNC_CTL = BIOC_PZ02_FUNC_CTL_SOC_PZ_02;
        
  • 举例:

    /* 配置SPI引脚的功能为SPI1_SCLK,SPI1_MISO,SPI1_MOSI,并且配置SPI1_SCLK的输出回送功能 */
    HPM_IOC->PAD[IOC_PAD_PA26].FUNC_CTL = IOC_PA26_FUNC_CTL_SPI1_CS_0;
    HPM_IOC->PAD[IOC_PAD_PA27].FUNC_CTL = IOC_PA27_FUNC_CTL_SPI1_SCLK | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1);
    HPM_IOC->PAD[IOC_PAD_PA28].FUNC_CTL = IOC_PA28_FUNC_CTL_SPI1_MISO;
    HPM_IOC->PAD[IOC_PAD_PA29].FUNC_CTL = IOC_PA29_FUNC_CTL_SPI1_MOSI;
    

16.5.2. GPIO控制器

  • GPIO控制器主要是用来控制IO的输入或者输出模式,读取IO的输入状态,设置IO的输出状态,以及设置IO的中断触发模式等等。

  • IO默认选择的是GPIO控制器,如果需要选择FGPIO,可以使用GPIO管理器指定,可参考 gpiom 例子

  • hpm_ioc_regs.h 的头文件中,定义了每个IO的PAD寄存器组,比如 PA26 则定义 IOC_PAD_PA26

  • hpm_gpio_drv.h 的头文件中,使用 GPIO_GET_PORT_INDEXGPIO_GET_PIN_INDEX 定义了每个IO所属的port端口号和引脚号

  • 从上述可快速知道IO的port端口号和引脚号,比如 IOC_PAD_PA26 的port端口号为 GPIO_GET_PORT_INDEX(IOC_PAD_PA26),引脚号为 GPIO_GET_PIN_INDEX(IOC_PAD_PA26)。

16.5.2.1. 设置IO的输入输出模式

  • 设置IO为输出模式,提供两种方式:一种带初始化电平的设置方式,一种不带初始化电平的设置方式。

    • 带初始化电平的设置方式 API:

      void gpio_set_pin_output_with_initial(GPIO_Type *ptr, uint32_t port, uint8_t pin, uint8_t initial);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DO_GPIOA

        pin

        uint8_t

        GPIO引脚号,取值范围为0~31

        initial

        uint8_t

        初始化电平,取值范围为0~1,0表示低电平,1表示高电平。

      • 举例:这里使用PA26作为输出引脚,初始化电平为高电平。

        gpio_set_pin_output_with_initial(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26), 1);
        
    • 不带初始化电平的设置方式 API:

      void gpio_set_pin_output(GPIO_Type *ptr, uint32_t port, uint8_t pin);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DO_GPIOA

        pin

        uint8_t

        GPIO引脚号,取值范围为0~31

      • 举例:这里使用PA26作为输出引脚.

        gpio_set_pin_output(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26));
        
  • 设置IO为输入模式API:

    void gpio_set_pin_input(GPIO_Type *ptr, uint32_t port, uint8_t pin);
    
    • 参数说明:

      参数名

      类型

      描述

      ptr

      GPIO_Type *

      GPIO控制器的基地址

      port

      uint32_t

      GPIO端口号,比如GPIO_DI_GPIOA

      pin

      uint8_t

      GPIO引脚号,取值范围为0~31

    • 举例:这里使用PA26作为输入引脚。

      gpio_set_pin_input(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26));
      

16.5.2.2. IO电平的设置与获取

  • 设置IO输出API:可以设置单个IO的输出电平、设置单个IO的电平翻转;设置Port端口下的所有IO的输出电平。

    • 需要将IO提前设置为输出模式

    • 设置单个IO的输出电平API:

      void gpio_write_pin(GPIO_Type *ptr, uint32_t port, uint8_t pin, uint8_t high);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DO_GPIOA

        pin

        uint8_t

        GPIO引脚号,取值范围为0~31

        high

        uint8_t

        输出电平,取值范围为0~1,0表示低电平,1表示高电平。

      • 举例:将PA26设置输出电平为高电平。

        gpio_write_pin(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26), 1);
        
    • 设置单个IO的电平翻转API:

      void gpio_toggle_pin(GPIO_Type *ptr, uint32_t port, uint8_t pin);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DO_GPIOA

        pin

        uint8_t

        GPIO引脚号,取值范围为0~31

      • 举例:将PA26翻转输出电平。

        gpio_toggle_pin(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26));
        
    • 设置Port端口下的所有IO的输出电平API:

      void gpio_write_port(GPIO_Type *ptr, uint32_t port, uint32_t value);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DO_GPIOA

        value

        uint32_t

        输出电平,取值范围为0~0xFFFFFFFF,0表示低电平,1表示高电平。

      • 举例:这里使用PA端口设置输出电平为高电平。

        gpio_write_port(HPM_GPIO, GPIO_DO_GPIOA, 0xFFFFFFFF);
        
    • 设置Port端口下指定的IO电平清除为低电平API:

      void gpio_set_port_low_with_mask(GPIO_Type *ptr, uint32_t port, uint32_t mask);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DO_GPIOA

        mask

        uint32_t

        对应的位为1则表示对应的IO输出电平为低电平,取值范围为0~0xFFFFFFFF。

      • 举例:这里使用PA端口的PA01,PA02为低电平,其余的电平保持不变。

        uint32_t mask = (1 << GPIO_GET_PIN_INDEX(IOC_PAD_PA01)) | (1 << GPIO_GET_PIN_INDEX(IOC_PAD_PA02));
        gpio_set_port_low_with_mask(HPM_GPIO, GPIO_DO_GPIOA, mask);
        
  • 读取IO输入状态API:

    • 即使IO功能为外设,比如SPI的MISO,也可以读取IO的输入状态。

    • 读取IO的电平状态API:

      uint8_t gpio_read_pin(GPIO_Type *ptr, uint32_t port, uint8_t pin);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DI_GPIOA

        pin

        uint8_t

        GPIO引脚号,取值范围为0~31

      • 举例:读取PA26的输入电平状态。

        uint8_t level = gpio_read_pin(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26));
        
    • 读取Port端口下的所有IO的输入状态API:

      uint32_t gpio_read_port(GPIO_Type *ptr, uint32_t port);
      
      • 参数说明:

        参数名

        类型

        描述

        ptr

        GPIO_Type *

        GPIO控制器的基地址

        port

        uint32_t

        GPIO端口号,比如GPIO_DI_GPIOA

      • 举例:读取PA端口的所有IO的输入状态。

        uint32_t level = gpio_read_port(HPM_GPIO, GPIO_DI_GPIOA);
        

16.5.2.3. IO中断

  • FGPIO不支持中断

  • 相关枚举介绍:

    • 中断触发模式枚举:

      typedef enum gpio_interrupt_trigger {
      
          /* 高电平触发中断 只要在高电平阶段会一直触发中断 */
          gpio_interrupt_trigger_level_high = 0,
      
          /* 低电平触发中断 只要在低电平阶段会一直触发中断 */
          gpio_interrupt_trigger_level_low,
      
          /* 上升沿触发中断 上升沿阶段会一直触发中断 */
          gpio_interrupt_trigger_edge_rising,
      
          /* 下降沿触发中断 下降沿阶段会一直触发中断 */
          gpio_interrupt_trigger_edge_falling,
      
          /* 双沿触发中断 上升沿和下降沿阶段都会触发中断 */
      #if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)
          gpio_interrupt_trigger_edge_both,
      #endif
      } gpio_interrupt_trigger_t;
      
      • 注意:

        • 对于双沿触发模式,并不是所有SOC都支持,此项支持需要看SOC的 hpm_soc_feature.h 是否定义 GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT

        • 在使用中断时,需要将IO提前设置为输入模式,并且需要配置IO的中断触发模式。

  • 中断触发模式配置API:

    void gpio_config_pin_interrupt(GPIO_Type *ptr, uint32_t gpio_index, uint8_t pin_index, gpio_interrupt_trigger_t trigger);
    
    • 参数说明:

      参数名

      类型

      描述

      ptr

      GPIO_Type *

      GPIO控制器的基地址

      gpio_index

      uint32_t

      GPIO端口号,比如GPIO_DI_GPIOA

      pin_index

      uint8_t

      GPIO引脚号,取值范围为0~31

      trigger

      gpio_interrupt_trigger_t

      中断触发模式,具体看 gpio_interrupt_trigger_t 枚举。

    • 举例:这里使用PA26作为输入引脚,配置为上升沿触发模式。

      gpio_config_pin_interrupt(HPM_GPIO, GPIO_GET_PORT_INDEX(IOC_PAD_PA26), GPIO_GET_PIN_INDEX(IOC_PAD_PA26), gpio_interrupt_trigger_edge_rising);
      
  • 中断使能API:

    void gpio_enable_pin_interrupt(GPIO_Type *ptr, uint32_t port, uint8_t pin);
    
    • 参数说明:

      参数名

      类型

      描述

      ptr

      GPIO_Type *

      GPIO控制器的基地址

      port

      uint32_t

      GPIO端口号,比如GPIO_DI_GPIOA

      pin

      uint8_t

      GPIO引脚号,取值范围为0~31

  • 中断禁能API:

    void gpio_disable_pin_interrupt(GPIO_Type *ptr, uint32_t port, uint8_t pin);
    
    • 参数说明:

      参数名

      类型

      描述

      ptr

      GPIO_Type *

      GPIO控制器的基地址

      port

      uint32_t

      GPIO端口号,比如GPIO_DI_GPIOA

      pin

      uint8_t

      GPIO引脚号,取值范围为0~31

  • 中断清除API:在中断服务函数中调用。

    bool gpio_check_clear_interrupt_flag(GPIO_Type *ptr, uint32_t port, uint8_t pin);
    
    • 参数说明:

      参数名

      类型

      描述

      ptr

      GPIO_Type *

      GPIO控制器的基地址

      port

      uint32_t

      GPIO端口号,比如GPIO_DI_GPIOA

      pin

      uint8_t

      GPIO引脚号,取值范围为0~31

    • 返回值:

      • 如果中断标志被清除,则返回true,否则返回false。