3. GPIO与基础外设的低功耗配置
在 nRF 系列 SoC 上,GPIO 本身并不耗电,真正让电流悄悄升高的,往往是引脚电平处于“中间态”、上下拉电阻持续导通、外设时钟一直开着,或者悬空引脚随环境电压漂移导致输入级反复翻转。本章围绕 GPIO Sense、引脚复用、上下拉配置、未使用引脚处理、外设时钟门控和低功耗 GPIO 唤醒六个方面,说明如何把基础外设的静态电流压到微安级,并保留可靠的唤醒能力。
一、先理解 GPIO 的静态电流来源
nRF52/nRF53 的 GPIO 由 P0、P1 两组端口组成,每个引脚可独立配置方向、输入缓冲、上下拉和驱动能力。引脚电流主要来自三处:
- 输入缓冲翻转:引脚悬空且输入缓冲使能时,电压停在阈值附近,输入级会因噪声反复翻转,产生动态电流。
- 上下拉电阻:内部上下拉约 13 kΩ,若引脚被外部电路强制拉到相反电平,会持续流过约 VDD/13 kΩ 的电流,3 V 下可达 200 µA 以上。
- 外设时钟:GPIO 本身不需要时钟,但驱动引脚的 SPI、TWI、UART、PWM 等外设若时钟未门控,会持续消耗电流。
因此低功耗 GPIO 配置的核心思路是:让每个引脚都有确定的电平,且不形成持续电流通路;让不用的外设时钟彻底关闭。
二、GPIO Sense:把引脚变成唤醒源
GPIO Sense(DETECT 机制)允许在系统进入 System OFF 后,由指定引脚的指定电平触发复位唤醒。它与普通 GPIOTE 中断不同:GPIOTE 需要 CPU 和时钟运行,而 Sense 在 System OFF 下由 Always-On 域监测,功耗极低。
配置 Sense 的关键步骤:
- 将目标引脚设为输入,并根据外部电路选择上拉或下拉,确保空闲电平确定。
- 通过
nrf_gpio_cfg_sense_input(pin, pull, sense)一次性完成方向、上下拉和 Sense 极性配置。 - Sense 极性可选
NRF_GPIO_PIN_SENSE_LOW或NRF_GPIO_PIN_SENSE_HIGH,必须与按键按下时的实际电平一致。 - 调用
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF)进入 System OFF。
例如按键一端接 P0.14、另一端接 GND,按下为低电平,则应配置上拉并选择低电平 Sense:
nrf_gpio_cfg_sense_input(14,
NRF_GPIO_PIN_PULLUP,
NRF_GPIO_PIN_SENSE_LOW);
唤醒后芯片会复位重启,程序从复位向量重新执行,因此唤醒后的状态恢复逻辑必须放在初始化流程中,而不能依赖掉电前的 RAM 内容。
三、引脚复用与上下拉配置
nRF 的引脚复用通过外设的 PSEL 寄存器完成,同一引脚同一时刻只能分配给一个外设。低功耗配置时要注意:
- 外设未使用时,应将其 PSEL 设为
0xFFFFFFFF(断开),避免外设内部逻辑继续驱动引脚。 - UART 的 TX 空闲时应保持高电平;若外部没有上拉,可配置内部上拉,避免浮空。
- I²C 的 SDA/SCL 必须外部上拉,内部上拉阻值偏大,不适合作为 I²C 的唯一上拉。
- SPI 的 SCK、MOSI 在空闲时建议配置为输出低或输入下拉,避免悬空翻转。
上下拉选择的原则是:让引脚在空闲状态下的电平与外部电路的自然电平一致,不产生持续电流。例如按键接 GND,用上拉;按键接 VDD,用下拉。若外部已有上拉,内部再开上拉只会略微降低阻值,通常可以关闭内部上下拉以省电。
四、未使用引脚的处理
未使用引脚是低功耗设计中最容易被忽视的漏电源。推荐做法是:
- 配置为输入 + 上下拉,或配置为输出固定电平,二者选其一,不要悬空。
- 若引脚在 PCB 上已接地,配置为输入上拉或输出高;若已接 VDD,配置为输入下拉或输出低。
- 若引脚完全悬空,优先配置为输出低,或输入下拉,避免输入缓冲翻转。
- 不要将未使用引脚配置为输出高又外部接地,否则会形成持续灌电流。
main() 开头统一遍历所有未使用引脚,按 PCB 实际连接批量配置,避免遗漏。五、外设时钟门控
nRF 外设默认在复位后处于关闭状态,但一旦被使能,即使不传输数据也会消耗电流。低功耗运行时应遵循“用完即关”的原则:
- SPI/TWI/UART 传输完成后,调用
nrf_drv_xxx_disable()或写ENABLE=0关闭外设。 - PWM 停止输出后关闭 PWM 模块,并将输出引脚配置为确定电平。
- ADC/TEMP 采集完成后关闭,避免持续采样。
- 使用
nrf_pwr_mgmt_run()进入 idle 前,确认没有外设仍处于使能状态。
下面这张图展示了从“外设使能”到“进入 System OFF”的引脚与外设状态变化关系,重点标出了哪些节点会产生额外电流,以及正确的关闭顺序。
六、低功耗 GPIO 唤醒实践
下面给出一个完整的按键唤醒示例,目标是在 System OFF 下由 P0.14 按键唤醒,唤醒后点亮 LED 并重新进入低功耗。示例参数基于 nRF52832,实际使用时需按芯片型号和 SDK 版本调整。
#include "nrf_gpio.h"
#include "nrf_pwr_mgmt.h"
#define KEY_PIN 14
#define LED_PIN 17
static void key_wakeup_init(void)
{
/* 按键接 GND,按下为低电平,上拉 + 低电平 Sense */
nrf_gpio_cfg_sense_input(KEY_PIN,
NRF_GPIO_PIN_PULLUP,
NRF_GPIO_PIN_SENSE_LOW);
/* LED 输出低,避免上电瞬间点亮 */
nrf_gpio_cfg_output(LED_PIN);
nrf_gpio_pin_clear(LED_PIN);
}
int main(void)
{
key_wakeup_init();
/* 判断是否为按键唤醒:读取复位原因 */
if (nrf_pwr_mgmt_shutdown_check() == NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF) {
/* 示例:点亮 LED 200 ms 表示已唤醒 */
nrf_gpio_pin_set(LED_PIN);
nrf_delay_ms(200);
nrf_gpio_pin_clear(LED_PIN);
}
/* 重新进入 System OFF,等待下一次按键 */
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
while (1) { }
}
验证时可用 Nordic Power Profiler Kit 或万用表串联在 VDD 上观察电流:进入 System OFF 后电流应降到 1 µA 量级;按下按键瞬间出现一个短脉冲,随后芯片复位重启,电流回到运行态。若静态电流明显偏高,按以下顺序排查:
- 是否有未使用引脚悬空,导致输入缓冲翻转;
- 是否有外设(尤其是 UART、SPI)未关闭,时钟仍在运行;
- 是否有引脚被外部电路强制拉到与内部上下拉相反的电平;
- Sense 极性是否与按键实际电平一致,导致无法唤醒或误唤醒。
把上述配置落实到工程中,建议形成一张引脚配置表,逐脚记录方向、上下拉、Sense 极性和所属外设,在每次修改硬件或固件后复核。GPIO 低功耗没有复杂算法,关键在于“每个引脚都有确定状态、每个外设用完即关、每个唤醒源都经过实测验证”。