目录
概述
本文主要介绍Nordic GPIO核心特性、配置方法和实战技巧。nRF52 系列(如 nRF52832)的 GPIO 控制器提供业界领先的灵活性与低功耗特性,支持 32 个可配置引脚(P0.00-P0.31)。
1 GPIO相关的寄存器
nRF52 系列(如 nRF52832)的 GPIO 控制器提供业界领先的灵活性与低功耗特性,支持 32 个可配置引脚(P0.00-P0.31)。以下是其核心特性、配置方法和实战技巧.
1.1 寄存器特性介绍
1.2 GPIO 核心架构
1.3 关键特性
1)引脚复用(PIN_CNF[n])
每个引脚独立配置为:
GPIO
外设功能(UART/SPI/TWI/PWM)
模拟输入(ADC/LPCOMP)
配置寄存器:
NRF_P0->PIN_CNF[n]
(n=0~31)
2) 可编程驱动强度
值 | 驱动强度 | 适用场景 |
---|---|---|
0 | 标准 (2mA) | 通用数字IO |
1 | 高 (5mA) | LED驱动/高速信号 |
2 | 低 (0.5mA) | 低功耗模式 |
3 | 标准 (2mA) | 兼容模式 |
3)智能感应模式
休眠唤醒功耗:仅 0.1μA/引脚
nrf_gpio_cfg_sense_set(pin, NRF_GPIO_PIN_SENSE_LOW); // 低电平唤醒
nrf_gpio_cfg_sense_set(pin, NRF_GPIO_PIN_SENSE_HIGH); // 高电平唤醒
4)输入缓冲控制
INPUT
位:
0:断开输入缓冲(省 3μA/引脚)
1:启用输入缓冲(默认)
5) 开漏输出模式
支持 I²C 总线电平匹配
NRF_P0->PIN_CNF[pin] = GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos;
6)虚拟引脚断开
nrf_gpio_cfg_default(pin); // 高阻态,防漏电
2 GPIO 配置方法
2.1 寄存器级配置(最高效)
// 配置 P0.06 为输出,驱动强度5mA,初始高电平
NRF_P0->DIRSET = (1 << 6); // 设为输出
NRF_P0->OUTSET = (1 << 6); // 输出高电平
NRF_P0->PIN_CNF[6] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
2.2 HAL 库配置(nrfx_gpio)
#include "nrfx_gpio.h"
// 配置 P0.08 为输入,上拉电阻,高电平唤醒
nrfx_gpio_cfg_input(8, NRF_GPIO_PIN_PULLUP);
nrfx_gpio_cfg_sense_set(8, NRF_GPIO_PIN_SENSE_HIGH);
2.3 Zephyr RTOS 配置(跨平台)
/* 设备树配置 */
gpio0: gpio@50000000 {
compatible = "nordic,nrf-gpio";
gpio-controller;
#gpio-cells = <2>;
};
/* 应用代码 */
#include <zephyr/drivers/gpio.h>
const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
3 低功耗优化技巧
3.1 休眠前配置
void enter_sleep(void) {
// 1. 关闭所有输出
NRF_P0->OUTCLR = 0xFFFFFFFF;
// 2. 配置未使用引脚为高阻态
for (int i=0; i<32; i++) {
if (!is_pin_used(i)) {
nrf_gpio_cfg_default(i);
}
}
// 3. 启用唤醒感应
nrf_gpio_cfg_sense_set(BUTTON_PIN, NRF_GPIO_PIN_PULLUP,
NRF_GPIO_PIN_SENSE_LOW);
}
3.2 动态驱动强度切换
// 高负载时增强驱动
void drive_led(bool high_power) {
if (high_power) {
NRF_P0->PIN_CNF[LED_PIN] |= (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos);
} else {
NRF_P0->PIN_CNF[LED_PIN] |= (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos);
}
}
3.3 ADC 引脚漏电防护
void adc_pin_safe(int pin) {
// ADC采样前
nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL);
// ADC完成后
NRF_SAADC->ENABLE = 0; // 禁用SAADC
nrf_gpio_cfg_default(pin);
}
4 外设复用
4.1 UART 引脚配置
// 配置 P0.06 为 TX,P0.08 为 RX
NRF_UARTE0->PSEL.TXD = 6;
NRF_UARTE0->PSEL.RXD = 8;
// 自动切换引脚功能
NRF_P0->PIN_CNF[6] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos);
4.2 PWM 引脚配置
// 配置 P0.12 为 PWM 输出
NRF_PWM0->PSEL.OUT[0] = 12 | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
// 保留GPIO控制权
NRF_P0->PIN_CNF[12] &= ~GPIO_PIN_CNF_INPUT_Msk; // 禁用输入
5 中断高级应用
5.1 多引脚中断分组
// 配置 P0.04、P0.05 共享中断
nrf_gpio_cfg_input(4, NRF_GPIO_PIN_PULLDOWN);
nrf_gpio_cfg_input(5, NRF_GPIO_PIN_PULLDOWN);
nrf_gpio_int_enable(NRF_GPIO_PIN_MAP(0,4) | NRF_GPIO_PIN_MAP(0,5));
// 中断处理中识别引脚
void GPIOTE_IRQHandler() {
uint32_t status = NRF_GPIOTE->EVENTS_IN[0];
if (status & (1<<4)) {
// P0.04 触发
NRF_GPIOTE->EVENTS_IN[0] = 0; // 清除事件
}
}
5.2 边沿捕获时序
// 精确测量脉冲宽度
void start_pulse_capture() {
NRF_TIMER0->CC[0] = 0;
NRF_TIMER0->TASKS_CLEAR = 1;
// 上升沿开始计时
nrf_gpio_cfg_input(SIG_PIN, NRF_GPIO_PIN_NOPULL);
NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) |
(SIG_PIN << GPIOTE_CONFIG_PSEL_Pos) |
(GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos);
// 下降沿结束计时
NRF_GPIOTE->CONFIG[1] = ...; // 配置为HiToLo
}
6 调试与诊断
6.1 寄存器快照
void gpio_reg_dump(int pin) {
printk("P0.%02d CNF: %08X\n", pin, NRF_P0->PIN_CNF[pin]);
printk("OUT: %08X DIR: %08X\n", NRF_P0->OUT, NRF_P0->DIR);
}
6.2 电流异常排查
症状 | 可能原因 | 解决方案 |
---|---|---|
休眠功耗 > 5μA | 输入缓冲未禁用 | INPUT=Disconnected |
特定引脚增加 50μA | 外部组件漏电 | 检查并联传感器电源 |
所有引脚额外 3μA | 未配置的引脚悬空 | 批量设置 cfg_default() |
唤醒后功耗不恢复 | 外设未正确重新初始化 | 检查 PIN_CNF 恢复流程 |
6.3 逻辑分析仪连接
// 使用 P0.30/P0.31 输出调试信号
NRF_P0->DIRSET = (1<<30) | (1<<31);
NRF_P0->OUTSET = (1<<30); // 触发信号
7 Nordic 特有功能
7.1 高精度低功耗比较器 (LPCOMP)
// 配置 P0.02 为模拟比较输入
NRF_LPCOMP->PSEL = LPCOMP_PSEL_PSEL_AnalogInput2;
7.2 QDEC 旋转解码器
// 配置 P0.15/A 和 P0.16/B 为正交编码输入
NRF_QDEC->PSEL.A = 15;
NRF_QDEC->PSEL.B = 16;
7.3 NFC 天线引脚复用
// 释放 P0.09/P0.10 为 GPIO
NRF_UICR->NFCPINS = UICR_NFCPINS_PROTECT_Disabled;
8 Zephyr 最佳实践
8.1 动态引脚控制
#include <zephyr/drivers/gpio.h>
const struct gpio_dt_spec sensor_power = GPIO_DT_SPEC_GET(DT_PATH(sensor), power_gpios);
void enable_sensor(bool on) {
gpio_pin_set_dt(&sensor_power, on);
k_msleep(10); // 等待电源稳定
}
8.2 中断驱动按键
static struct gpio_callback button_cb;
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) {
// 处理按键
}
void init_button() {
gpio_pin_configure_dt(&button, GPIO_INPUT);
gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE);
gpio_init_callback(&button_cb, button_pressed, BIT(button.pin));
gpio_add_callback(button.port, &button_cb);
}