3. GPIO与引脚复用驱动开发
在 nRF54 系列 SoC 上,GPIO 外设(GPIO0/GPIO1/GPIO2)与引脚复用控制器(PINMUX)是板级适配中最先接触、也最容易出问题的一层。nRF54 的每个物理引脚都通过 PINMUX 与某个外设信号绑定,GPIO 只是其中一种可选功能。理解“引脚—复用—外设信号”这条链路,是后续 UART、SPI、I2C、PWM 等驱动能否正常工作的前提。
GPIO 的输入输出模式与上下拉
nRF54 的 GPIO 通过 nrf_gpio_cfg_input()、nrf_gpio_cfg_output() 以及更底层的 nrf_gpio_cfg() 完成配置。一个引脚的配置由四个维度决定:方向(输入/输出)、上下拉(Pull-up / Pull-down / 无)、驱动能力(标准/高驱动)、初始电平。在 Zephyr 下,这些通常由设备树的 gpio-keys、gpio-leds 或自定义 gpios 属性描述,再由 gpio_pin_configure() 在运行时应用。
输入模式下,上下拉的选择直接决定空闲电平。按键检测是典型场景:按键一端接引脚、另一端接 GND,则引脚必须配置上拉,按下时读到低电平;若按键接 VCC,则配置下拉,按下读到高电平。悬空输入(无上下拉)在 nRF54 上会因输入阻抗极高而随机翻转,是常见的“按键误触发”根因。输出模式下,上下拉通常关闭,但若引脚外接 LED 且采用灌电流接法(LED 阳极接 VCC、阴极接引脚),则引脚输出低电平时点亮,此时需注意驱动能力是否足够。
中断触发方式
GPIO 中断在 nRF54 上通过 GPIOTE 外设实现,支持四种触发边沿:上升沿、下降沿、双边沿、高/低电平。Zephyr 中通过 GPIO_INT_EDGE_TO_ACTIVE、GPIO_INT_EDGE_BOTH 等标志配置,并注册回调。机械按键必须考虑抖动:典型抖动时间为 5~20 ms,若直接使用双边沿中断,一次按下可能触发多次回调。工程上常用两种处理:一是硬件 RC 滤波,二是在回调中启动 10~20 ms 的定时器,到期后再读取引脚电平确认。对于低功耗场景,还需注意 GPIOTE 的 IN 事件会唤醒系统,而 PORT 事件(整组引脚)在 nRF54 上功耗更低,适合多引脚同时监听的场合。
引脚复用矩阵与板级分配表
nRF54 的 PINMUX 允许同一物理引脚在不同时刻映射到不同外设信号,但同一时刻只能有一个外设占用。板级适配的核心工作,就是产出一张“引脚分配表”,明确每个引脚的功能、方向、上下拉、复用归属和冲突状态。下表是一个示例(参数为教学假设,非实测):
| 引脚 | 功能 | 方向 | 上下拉 | 复用归属 | 冲突 |
|---|---|---|---|---|---|
| P1.00 | UART0 TX | 输出 | 无 | UARTE0 | — |
| P1.01 | UART0 RX | 输入 | 上拉 | UARTE0 | — |
| P1.02 | 按键 KEY1 | 输入 | 上拉 | GPIO1 | — |
| P1.03 | LED1 | 输出 | 无 | GPIO1 | — |
| P1.04 | SPI SCK | 输出 | 无 | SPIM1 | 与 PWM 冲突 |
冲突排查遵循三条规则:第一,同一引脚不能同时被两个外设声明;第二,复用功能切换时必须先关闭原外设,再配置新外设,否则 PINMUX 寄存器可能保留旧映射;第三,低功耗引脚(如 NFC 天线引脚)不可随意复用为普通 GPIO。在 Zephyr 中,设备树编译阶段会检测部分冲突,但跨外设的运行时冲突仍需人工核对分配表。
板级引脚分配表设计与冲突排查实操
设计分配表时,建议按“外设需求 → 引脚候选 → 复用检查 → 电气检查”四步推进。以一块带 UART、SPI、两个按键、两个 LED 的 nRF54 板为例:先列出各外设所需信号数(UART 2、SPI 4、按键 2、LED 2,共 10 个引脚),再从数据手册的引脚功能表中筛选支持目标外设的引脚,优先选择同一 GPIO 端口以减少跨端口操作。随后逐条核对复用矩阵,确认没有两个外设争用同一引脚。最后检查电气特性:I2C 的 SDA/SCL 必须上拉(通常 4.7 kΩ),UART RX 建议上拉防止悬空误触发,LED 引脚需确认灌电流/拉电流方向与驱动能力匹配。
在 Zephyr 设备树中,分配表最终体现为 pinctrl 节点。例如 UART0 的引脚配置:
&uart0 {
status = "okay";
pinctrl-0 = <&uart0_default>;
pinctrl-1 = <&uart0_sleep>;
pinctrl-names = "default", "sleep";
};
&pinctrl {
uart0_default: uart0_default {
group1 {
psels = <NRF_PSEL(UART_TX, 1, 0)>,
<NRF_PSEL(UART_RX, 1, 1)>;
};
};
};
若编译时出现 pin conflict 或运行时外设无响应,排查顺序为:先确认设备树中该引脚是否被其他节点声明;再检查 pinctrl 的 psels 是否与实际硬件一致;最后用万用表或逻辑分析仪测量引脚电平,判断是配置问题还是焊接问题。对于按键类输入,若中断频繁误触发,优先检查上下拉配置和抖动处理,而非怀疑芯片本身。