2.2. GPIO

2.2.1. Overview

本文介绍GPIO(General purpose input/output)。AC792N的IO有如下特性:

  • 支持配置强驱电流档位;

  • 支持配置内部上/下拉电阻;

  • 支持EXTI外部中断(PR口和PV口除外);

  • 支持crossbar映射外设模块接口(PR口和PV口除外);

    分类

    IO

    普通IO

    PA00~PA15、PB00~PB15、PC00~PC13、PD00~PD15、PE00~PE15、PF00~PF05

    特殊IO

    PR00和PR01、PV00和PV01、FUSB_DM和FUSB_DP、HUSB_DM和HUSB_DP

示例工程:可在demo_hello工程中的apps/demo/demo_hello/include/app_config.h中打开USE_GPIO_TEST_DEMO宏测试。

例程路径:apps/common/example/peripheral/gpio/gpio_test.c

2.2.2. GPIO特性

2.2.2.1. 内部上/下拉电阻

AC792N的IO内部上/下拉阻值精度±20%

  • 内部上拉电阻值

    IO

    内部上拉阻值

    PA00~PA15、PB00~PB15、PC00~PC13、PD00~PD15、PE00~PE15、PF00~PF05

    10K

    HUSBDP

    1.5K(PU=1)、 1K(PU=2/3)

    FUSBDP

    1.5K

  • 内部下拉电阻值

    IO

    内部下拉阻值

    PA00~PA15、PB00~PB15、PC00~PC13、PD00~PD15、PE00~PE15、PF00~PF05

    10K

    HUSBDP、HUSBDM、FUSBDP、FUSBDM

    15K

2.2.2.2. 电源域

AC792N系列芯片的IO电源域有四个:IOVDD、IOVDD2、IOVDD3、RTCVDD,不同电源域的IO电平可以不一样。

有什么用呢?比如有这种情况,主控IO电平3.3V,而某个外设芯片的IO电平是1.8V,两者要通讯,就需要通过电平转换电路才能接到一起。主控有了多个电源域,那就可以实现一部分IO电平3.3V,一部分电平1.8V,从而省去电平转换电路。将IOVDD2电源供电1.8V,那么PE10~PE15的IO高电平为1.8V,这部分IO就可以直连到电平为1.8V的外设芯片上了。

需要注意的是,不同封装,4个电源域供电口不一定会全部拉出来,尤其是IOVDD2和IOVDD3。没有拉出来的电源域供电口一般会在芯片封装内部直连到IOVDD。

电源域

IO

IOVDD

PA12~PA15、PB00~PB15、PC00~PC13、PD00~PD15、PE00~PE09、PF00~PF05、HUSBDP、HUSBDM、FUSBDP、FUSBDM、PV00和PV01

IOVDD2

PE10~PE15

IOVDD3

PA00~PA11

RTCVDD

PR00和PR01

2.2.2.3. MCLR

PD08脚有一个特殊的功能,MCLR复位输入。MCLR低电平复位,可软件关闭(当然,得保证芯片能跑到关闭MCLR的代码前不复位)。该引脚在进行IO分配时需要特别注意。该引脚上电默认上拉。

p33_or_1byte(P3_PR_PWR, BIT(3));         ///< 开启MCLR
p33_and_1byte(P3_PR_PWR, (u8)~(BIT(3))); ///< 关闭MCLR

2.2.2.4. 长按复位

PD01脚有一个特殊的功能,支持长按复位,即该IO处于低/高电平状态N秒后系统复位。参数可配:

  • 有效电平可配:0低电平、1高电平。比如配置为0时,当该引脚被拉到低电平N秒后,系统复位。

  • 长按复位时间可配:1S、2S、4S、8S、16S。

  • 复位释放时刻配置:timeout后,立刻释放系统 或者 等待复位IO恢复后释放系统。

该引脚上电默认上拉。

配置接口:

/* ------------------------------------------------------------------------------------*/
/**
 * @brief gpio_longpress_pin0_reset_config
 *
 * @Params pin          固定为IO_POARTD_01。
 * @Params level        只能是0或1。0-低电平,1-高电平。
 * @Params time         只能是0/1/2/4/8/16,其中,参数为0时,表示关闭长按复位功能。
 * @Params release      只能是0或1。0-等待复位IO恢复后释放系统,1-立刻释放系统。
 * @Params pull_enable  上/下拉使能。非0-使能。level为0时,IO被配置为上拉;level为1时,IO被配置为下拉。
 *
 * @note   使用该接口配置长按复位后,该IO的配置将锁死,需要断电后才能解锁(硬件锁死,无法取消)。
 */
/* ------------------------------------------------------------------------------------*/
void gpio_longpress_pin0_reset_config(u32 pin, u32 level, u32 time, u32 release, u32 pull_enable);

2.2.2.5. EXTI外部中断

AC792N的IO支持EXTI外部中断,PR口和PV口除外。API接口:

// exti.h

/**
 * @brief 注册外部中断
 *
 * @param gpio 参考宏IO_PORTx_xx,如IO_PORTA_00
 * @param edge 触发边沿
 * @param callback_in_irq 中断回调函数
 * @param priv 中断回调函数的私有指针
 *
 * @return 非负数: 注册成功的外部中断序号  负值: 参数有误注册失败
 */
int exti_init(unsigned int gpio, trigger_edge_t edge, void (*callback_in_irq)(void *priv, unsigned int gpio), void *priv);


/**
 * @brief 卸载外部中断
 *
 * @param index 注册时返回的外部中断序号
 *
 * @return 0: 成功  负值: 失败
 */
int exti_uninit(int index);

exti_init()接口中传入的edge参数不同,IO会被配置为不同的上/下拉输入状态:

  • EDGE_POSITIVE,上升沿触发中断,对应IO会被配置为下拉输入。

  • EDGE_NEGATIVE,下降沿触发中断,对应IO会被配置为上拉输入。

2.2.3. 特殊IO

2.2.3.1. PV口

PV口可作IO,也是两个内部LDO的输出口。

  • PV00:AVDD28内部LDO输出口。

  • PV01:AVDD18内部LDO输出口。

作为IO使用时的api接口如下:

// avdd_config.h

/**
 * @brief 设置PV口的方向
 * @param gpio 参考宏IO_PORT_PV_0X
 * @param dir 1: 输入       0: 输出
 * @return 0: 成功  非0: 失败
 */
int avdd_port_pv_dir(int port, u8 dir);


/**
 * @brief 获取PV口输入电平
 * @param gpio 参考宏IO_PORT_PV_0X
 * @return 0: 低电平  1: 高电平
 */
int avdd_port_pv_read(int port);


/**
 * @brief 设置PV口的输出电平
 * @param gpio 参考宏IO_PORT_PV_0X
 * @param on 1: 高电平       0: 低电平
 * @return 0: 成功  非0: 失败
 */
int avdd_port_pv_out(int port, u8 on);


/**
 * @brief 设置PV口的强驱
 * @param gpio 参考宏IO_PORT_PV_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int avdd_port_pv_hd(int port, u8 on);


/**
 * @brief 设置PV口的上拉电阻
 * @param gpio 参考宏IO_PORT_PV_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int avdd_port_pv_pu(int port, u8 on);


/**
 * @brief 设置PV口的下拉电阻
 * @param gpio 参考宏IO_PORT_PV_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int avdd_port_pv_pd(int port, u8 on);


/**
 * @brief 设置PV口的数字输入功能
 * @param gpio 参考宏IO_PORT_PV_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int avdd_port_pv_die(int port, u8 on);

2.2.3.2. PR口

PR口属于RTC模块的IO,可被配置为RTC的晶振脚 或 IO使用。作为IO使用时的api接口如下:

// rtc.h


/**
 * @brief 设置PR口的方向
 * @param gpio  参考宏IO_PORT_PR_0X
 * @param dir   1: 输入  0: 输出
 * @return      0: 成功  非0: 失败
 */
int rtc_port_pr_dir(int port, u8 dir);


/**
 * @brief 获取PR口输入电平
 * @param gpio 参考宏IO_PORT_PR_0X
 * @return 0: 低电平  1: 高电平
 */
int rtc_port_pr_read(int port);


/**
 * @brief 设置PR口的输出电平
 * @param gpio 参考宏IO_PORT_PR_0X
 * @param on 1: 高电平       0: 低电平
 * @return 0: 成功  非0: 失败
 */
int rtc_port_pr_out(int port, u8 on);


/**
 * @brief 设置PR口的强驱
 * @param gpio 参考宏IO_PORT_PR_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int rtc_port_pr_hd(int port, u8 on);


/**
 * @brief 设置PR口的上拉电阻
 * @param gpio 参考宏IO_PORT_PR_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int rtc_port_pr_pu(int port, u8 on);


/**
 * @brief 设置PR口的下拉电阻
 * @param gpio 参考宏IO_PORT_PR_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int rtc_port_pr_pd(int port, u8 on);


/**
 * @brief 设置PR口的数字输入功能
 * @param gpio 参考宏IO_PORT_PR_0X
 * @param on 1: 打开       0: 关闭
 * @return 0: 成功  非0: 失败
 */
int rtc_port_pr_die(int port, u8 on);

2.2.3.3. USB_IO

AC792N有两个USB口,对应的DP和DM脚在非USB模式下,可以作为IO使用,并且使用的API接口与普通GPIO一样(参考gpio.h)。比如:

SDK驱动中,引脚定义关系如下:

引脚

SDK定义

FUSB_DP

IO_PORT_USB_DPA

FUSB_DM

IO_PORT_USB_DMA

HUSB_DP

IO_PORT_USB_DPB

HUSB_DM

IO_PORT_USB_DMB

即A口对应FUSB,B口对应HUSB。

2.2.4. 常见问题说明

  • 为什么PD08软件配置为低电平后系统复位?

    答:PD08开了MCLR功能,低电平复位,可软件关闭该功能。

  • 软关机怎么保持IO状态?

    答:软关机流程中,SDK驱动会统一将所有非保护的IO的配置成高阻态。如果需要保持IO状态,可在在board.c文件中找到gpio_config_soft_poweroff(),并用PORT_PROTECT()保护IO。

    static void gpio_config_soft_poweroff(void)
    {
        PORT_TABLE(g);
    // ...
    #if TCFG_ADKEY_ENABLE
        PORT_PROTECT(adkey_data.adkey_pin);
    #endif
    
    #if TCFG_LOWPOWER_WAKEUP_PORT0_ENABLE
        PORT_PROTECT(TCFG_LOWPOWER_WAKEUP_PORT0_IO);
    #endif
    
    #if TCFG_LOWPOWER_WAKEUP_PORT1_ENABLE
        PORT_PROTECT(TCFG_LOWPOWER_WAKEUP_PORT1_IO);
    #endif
    
    #if TCFG_LOWPOWER_WAKEUP_PORT2_ENABLE
        PORT_PROTECT(TCFG_LOWPOWER_WAKEUP_PORT2_IO);
    #endif
    // ...
        __port_init((u32)gpio_config);
    }
    
  • __gpio和gpio接口有什么不同?

    答:两套接口函数实现的功能是一样的,只是gpio的这套接口在操作寄存器的时候都上了锁,确保操作时不会影响到同组引脚。 如果同一组引脚之间没有互斥,针对用户有高速度要求,并且不需要考虑同一组引脚之间操作互斥推荐使用 __gpio这套api。

2.2.5. API参考


Functions

void gpio_port_lock(unsigned int port)

gpio_port_lock,自旋锁,即不能被另一个cpu打断,也不能被中断打断

Parameters

gpio – 参考宏GPIO2PORT(IO_PORTx_xx),如GPIO2PORT(IO_PORTA_00)

void gpio_port_unlock(unsigned int port)

gpio_port_unlock,解除自旋锁

Parameters

gpio – 参考宏GPIO2PORT(IO_PORTx_xx),如GPIO2PORT(IO_PORTA_00)

int gpio_direction_input(unsigned int gpio)

gpio_direction_input,将引脚直接设为输入模式

Parameters

gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

Returns

0:成功 非0:失败

int gpio_direction_output(unsigned int gpio, int value)

gpio_direction_output,设置引脚的方向为输出,并设置一下电平

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • value – 1:输出高电平, 0:输出低电平

Returns

0:成功 非0:失败

int gpio_set_pull_up(unsigned int gpio, gpio_pull_up_mode_t mode)

gpio_set_pull_up,设置引脚的上拉电阻等级

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • mode – gpio_pull_up_mode_t

Returns

0:成功 非0:失败

int gpio_set_pull_down(unsigned int gpio, gpio_pull_down_mode_t mode)

gpio_set_pull_down,设置引脚的下拉电阻等级

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • mode – gpio_pull_down_mode_t

Returns

0:成功 非0:失败

int gpio_set_hd(unsigned int gpio, gpio_drive_strength_t mode)

gpio_set_hd, 设置引脚的强驱等级

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • mode – gpio_drive_strength_t

Returns

0:成功 非0:失败

int gpio_set_die(unsigned int gpio, int value)

gpio_set_die,设置引脚为数字功能还是模拟功能,比如引脚作为ADC的模拟输入,则die要置0

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • value – 1:数字输入功能 0:跟电压相关的模拟功能

Returns

0:成功 非0:失败

int gpio_set_dieh(unsigned int gpio, int value)

gpio_set_dieh,设置引脚P33输入功能

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • dir – 1:打开 0:关闭

Returns

0:成功 非0:失败

int gpio_set_direction(unsigned int gpio, unsigned int dir)

gpio_set_direction,设置引脚方向

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • dir – 1:输入 0:输出

Returns

0:成功 非0:失败

int gpio_read(unsigned int gpio)

gpio_read,读取引脚的输入电平,引脚为数字输入模式时才有效

Parameters

gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

Returns

电平值

int gpio_set_spl(unsigned int gpio, int keep)

gpio_set_spl,设置引脚输出时是否维持上下拉电阻

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • keep – 1:维持 0:不维持

Returns

0:成功 非0:失败

int gpio_set_mode(unsigned int gpio, gpio_mode_t mode)

gpio_set_mode,设置引脚工作模式

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • mode – gpio_mode_t

Returns

0:成功 非0:失败

int gpio_enable_function(unsigned int gpio, gpio_function_t fn, int io_init)

gpio_enable_function,打开引脚映射功能

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • fn – gpio_function_t

  • io_init – 是否使用映射功能的默认IO初始化状态

Returns

0:成功 非0:失败

int gpio_disable_function(unsigned int gpio, gpio_function_t fn, int io_uninit)

gpio_disable_function,关闭引脚映射功能

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • fn – gpio_function_t

  • io_init – 是否还原IO的初始状态(输入高阻)

Returns

0:成功 非0:失败

void usb_iomode(unsigned char usb_id, int enable)

usb_iomode, usb引脚设为普通IO

Parameters
  • usb_id – usb名称号,0是usb0,1是usb1

  • enable – 1:使能;0:关闭

void gpio_latch_en(unsigned int gpio, int enable)

gpio_latch_en,锁定引脚状态,解锁前IO电平状态不会再改变

Parameters
  • gpio – 参考宏IO_PORTx_xx,如IO_PORTA_00

  • en – 1:锁定;0:解锁