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:解锁