13 管脚管理(PINCTRL)
13.1 功能概述
PINCTRL 模块管理芯片所有 IO 管脚的功能,包括外设 IO 的映射,上拉、下拉选择,输入模式控制, 输出驱动能力设置等。
每个 IO 管脚都可以配置为数字或模拟模式,当配置为数字模式时,特性如下:
- 每个 IO 管脚可以映射多种不同功能的外设
- 每个 IO 管脚都支持上拉或下拉
- 每个 IO 管脚都支持施密特触发输入方式
- 每个 IO 管脚支持四种输出驱动能力
鉴于片内外设丰富、IO 管脚多,进行管脚全映射并不现实,为此,PINCTRL 尽量保证灵活性的前提下做了一定取舍、优化。
部分常用外设的输入、输出功能管脚可与 \(\{{0 .. 17, 21, 22, 31, 34, 35\}}\) 这 23 个常用 IO 之间任意连接(全映射),
这部分常用外设功能管脚总结于表 13.1。
表 13.2 列出了其它外设功能管脚支持映射到哪些 IO 管脚上。
除此以外,所有 IO 管脚都可以配置为 GPIO 或者 DEBUG 模式。GPIO 模式的输入、输出方向由 GIO_SetDirection
控制。
DEBUG 模式为保留功能,具体功能暂不开放。
外设 | 功能管脚 |
---|---|
I2C | I2C0_SCL_I, I2C0_SCL_O, I2C0_SDA_I, I2C0_SDA_O, I2C1_SCL_I, I2C1_SCL_O, I2C1_SDA_I, I2C1_SDA_O |
I2S | I2S_BCLK_I, I2S_BCLK_O, I2S_DIN, I2S_DOUT, I2S_LRCLK_I, I2S_LRCLK_O |
IR | IR_DATIN, IR_DATOUT, IR_WAKEUP |
PCAP | PCAP0_IN, PCAP1_IN, PCAP2_IN, PCAP3_IN, PCAP4_IN, PCAP5_IN |
PDM | PDM_DMIC_IN, PDM_DMIC_MCLK |
QDEC | QDEC_INDEX, QDEC_PHASEA, QDEC_PHASEB |
SPI0 | SPI0_CLK_IN, SPI0_CLK_OUT, SPI0_CSN_IN, SPI0_CSN_OUT, SPI0_HOLD_IN, SPI0_HOLD_OUT, SPI0_MISO_IN, SPI0_MISO_OUT, SPI0_MOSI_IN, SPI0_MOSI_OUT, SPI0_WP_IN, SPI0_WP_OUT |
SPI | SPI1_CLK_IN, SPI1_CLK_OUT, SPI1_CSN_IN, SPI1_CSN_OUT, SPI1_HOLD_IN, SPI1_HOLD_OUT, SPI1_MISO_IN, SPI1_MISO_OUT, SPI1_MOSI_IN, SPI1_MOSI_OUT, SPI1_WP_IN, SPI1_WP_OUT |
SWD | SWDO, SW_TCK, SW_TMS |
UART0 | UART0_CTS, UART0_RTS, UART0_RXD, UART0_TXD |
UART1 | UART1_CTS, UART1_RTS, UART1_RXD, UART1_TXD |
外设功能管脚 | 可连接到的 IO 管脚 |
---|---|
KEY_IN_COL_0 | 0, 23 |
KEY_IN_COL_1 | 1, 24 |
KEY_IN_COL_2 | 2, 25 |
KEY_IN_COL_3 | 3, 29 |
KEY_IN_COL_4 | 4, 30 |
KEY_IN_COL_5 | 5, 31 |
KEY_IN_COL_6 | 6, 32 |
KEY_IN_COL_7 | 7, 33 |
KEY_IN_COL_8 | 8, 34 |
KEY_IN_COL_9 | 9, 35 |
KEY_IN_COL_10 | 10, 36 |
KEY_IN_COL_11 | 11, 37 |
KEY_IN_COL_12 | 12, 38 |
KEY_IN_COL_13 | 13, 39 |
KEY_IN_COL_14 | 14, 40 |
KEY_IN_COL_15 | 15, 41 |
KEY_IN_COL_16 | 16 |
KEY_IN_COL_17 | 17 |
KEY_IN_COL_18 | 21 |
KEY_IN_COL_19 | 22 |
KEY_OUT_ROW_0 | 0, 23 |
KEY_OUT_ROW_1 | 1, 24 |
KEY_OUT_ROW_2 | 2, 25 |
KEY_OUT_ROW_3 | 3, 29 |
KEY_OUT_ROW_4 | 4, 30 |
KEY_OUT_ROW_5 | 5, 31 |
KEY_OUT_ROW_6 | 6, 32 |
KEY_OUT_ROW_7 | 7, 33 |
KEY_OUT_ROW_8 | 8, 34 |
KEY_OUT_ROW_9 | 9, 35 |
KEY_OUT_ROW_10 | 10, 36 |
KEY_OUT_ROW_11 | 11, 37 |
KEY_OUT_ROW_12 | 12, 38 |
KEY_OUT_ROW_13 | 13, 39 |
KEY_OUT_ROW_14 | 14, 40 |
KEY_OUT_ROW_15 | 15, 41 |
KEY_OUT_ROW_16 | 16 |
KEY_OUT_ROW_17 | 17 |
KEY_OUT_ROW_18 | 21 |
KEY_OUT_ROW_19 | 22 |
ANT_SW0 | 0, 3, 6, 9, 12, 15, 21, 34 |
ANT_SW1 | 1, 4, 7, 10, 13, 16, 22, 35 |
ANT_SW2 | 2, 5, 8, 11, 14, 17, 31 |
ANT_SW3 | 0, 3, 6, 9, 12, 15, 21, 34 |
ANT_SW4 | 1, 4, 7, 10, 13, 16, 22, 35 |
ANT_SW5 | 2, 5, 8, 11, 14, 17, 31 |
ANT_SW6 | 0, 3, 6, 9, 12, 15, 21, 34 |
ANT_SW7 | 1, 4, 7, 10, 13, 16, 22, 35 |
PA_RXEN | 11, 12, 13, 14, 15, 16, 17, 34, 35 |
PA_TXEN | 4, 5, 6, 7, 8, 9, 10, 34, 35 |
TIMER0_PWM_0A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
TIMER0_PWM_0B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
TIMER0_PWM_1A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
TIMER0_PWM_1B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
TIMER1_PWM_0A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
TIMER1_PWM_0B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
TIMER1_PWM_1A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
TIMER1_PWM_1B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
TIMER2_PWM_0A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
TIMER2_PWM_0B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
TIMER2_PWM_1A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
TIMER2_PWM_1B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
PWM_0A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
PWM_0B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
PWM_1A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
PWM_1B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
PWM_2A | 0, 2, 4, 6, 8, 10, 12, 14, 16, 21, 31, 35 |
PWM_2B | 1, 3, 5, 7, 9, 11, 13, 15, 17, 22, 34 |
QDEC_EXT_IN_CLK | 3, 9 |
QDEC_TIMER_EXT_IN1_A | 1, 7 |
QDEC_TIMER_EXT_IN2_A | 2, 8 |
QDEC_TIMER_EXT_IN2_B | 5, 11 |
QDEC_TIMER_EXT_OUT0_A | 0, 6 |
QDEC_TIMER_EXT_OUT1_A | 1, 7 |
QDEC_TIMER_EXT_OUT2_A | 2, 8 |
QDEC_TIMER_EXT_OUT0_B | 3, 9 |
QDEC_TIMER_EXT_OUT1_B | 4, 10 |
QDEC_TIMER_EXT_OUT2_B | 5, 11 |
SPI0_CLK_IN | 19 |
SPI0_CLK_OUT | 19 |
SPI0_CSN_IN | 18 |
SPI0_CSN_OUT | 18 |
SPI0_HOLD_IN | 20 |
SPI0_HOLD_OUT | 20 |
SPI0_MISO_IN | 27 |
SPI0_MISO_OUT | 27 |
SPI0_MOSI_IN | 28 |
SPI0_MOSI_OUT | 28 |
SPI0_WP_IN | 26 |
SPI0_WP_OUT | 26 |
SPI2AHB_CS | 16 |
SPI2AHB_DI | 17 |
SPI2AHB_DO | 17 |
SPI2AHB_SCLK | 15 |
13.2 使用说明
13.2.1 为外设配置 IO 管脚
将外设输出连接到 IO 管脚
通过
PINCTRL_SetPadMux
将外设输出连接到 IO 管脚。 注意按照表 13.1 和 表 13.2 确认硬件是否支持。对于不支持的配置,显然无法生效,函数将返回非 0 值。int PINCTRL_SetPadMux( const uint8_t io_pin_index, // IO 序号 (0 .. IO_PIN_NUMBER - 1) const io_source_t source // IO 源 );
例如将 IO 管脚 10 配置为 GPIO 模式:
PINCTRL_SetPadMux(10, IO_SOURCE_GPIO);
将 IO 管脚连接到外设的输入
对于有些外设的输入同样通过
PINCTRL_SetPadMux
配置。对于另一些输入, PINCTRL 为不同的外设分别提供了 API 用以配置输入。比如 UART 的数据输入 RXD 和用于硬件流控的 CTS,需要通过PINCTRL_SelUartIn
配置 :int PINCTRL_SelUartIn( , // UART 序号 uart_port_t portuint8_t io_pin_rxd, // 连接到 RXD 输入的 IO 管脚 uint8_t io_pin_cts); // 连接到 CTS 输入的 IO 管脚
对于不需要配置的输入,可在对应的参数上填入值
IO_NOT_A_PIN
。表 13.3 罗列了为各外设提供的输入配置函数。
表 13.3: 各外设的输入配置函数 外设 配置函数 KeyScan PINCTRL_SelKeyScanColIn
I2C PINCTRL_SelI2cIn
I2S PINCTRL_SelI2sIn
IR PINCTRL_SelIrIn
PDM PINCTRL_SelPdmIn
PCAP PINCTRL_SelPCAPIn
QDEC PINCTRL_SelQDECIn
SWD PINCTRL_SelSwIn
SPI PINCTRL_SelSpiIn
UART PINCTRL_SelUartIn
USB PINCTRL_SelUSB
13.2.2 配置上拉、下拉
IO 管脚的上拉、下拉模式通过 PINCTRL_Pull
配置:
void PINCTRL_Pull(
const uint8_t io_pin_index, // IO 管脚序号
const pinctrl_pull_mode_t mode // 模式
);
表 13.4 列出了各管脚默认的上下拉配置。
管脚 | 默认配置 |
---|---|
1 | 上拉 |
2 | 上拉 |
3 | 上拉 |
4 | 上拉 |
15 | 下拉 |
16 | 下拉 |
17 | 下拉 |
其它 | 禁用上下拉 |
13.2.3 配置驱动能力
通过 PINCTRL_SetDriveStrength
配置 IO 管脚的驱动能力:
void PINCTRL_SetDriveStrength(
const uint8_t io_pin_index,
const pinctrl_drive_strength_t strength);
默认驱动能力共分 4 档,分别为 \(2mA\)、\(4mA\)、\(8mA\)、\(12mA\)。除了 IO1 驱动能力默认为 \(12mA\) 之外, 其它管脚驱动能力默认 \(8mA\)。
13.2.4 配置天线切换控制管脚
支持最多 8 个管脚用于天线切换控制,相应地,天线切换模板(switching pattern)内每个数字包含 8 个比特,
取值范围为 \(0..255\)。这 8 个比特可依次通过 IO_SOURCE_ANT_SW0
、……、IO_SOURCE_ANT_SW7
选择。
例如,查表 13.2 可知管脚 0 能够映射为 ANT_SW0,即比特 0。
通过下面这行代码就可将管脚 0 映射为 ANT_SW0:
(0, IO_SOURCE_ANT_SW0); PINCTRL_SetPadMux
通过函数 PINCTRL_EnableAntSelPins
可批量配置用于天线切换控制的管脚:
int PINCTRL_EnableAntSelPins(
int count, // 数目
const uint8_t *io_pins); // 管脚数组
管脚数组 io_pins
里的第 n 个元素代表第 n 个比特所要映射的管脚。如果不需要为某个比特配置管脚,则在 io_pins
的对应位置填入 IO_NOT_A_PIN
。比如,只选用第 0、第 2 等两个比特用作控制,分别映射到管脚 0 和 5:
const uint8_t io_pins[] = {0, IO_NOT_A_PIN, 5};
(sizeof(io_pins), io_pins); PINCTRL_EnableAntSelPins
13.2.5 配置模拟模式
通过以下 3 步可将一个管脚配置为模拟模式:
- 配置为 GPIO 模式;
- 禁用上下拉;
- 将 GPIO 配置为高阻态。
函数 PINCTRL_EnableAnalog
封装了以上步骤:
void PINCTRL_EnableAnalog(const uint8_t io_index);
模拟模式适用于以下几种外设。
-
函数
PINCTRL_SelUSB()
内部封装了PINCTRL_EnableAnalog
,开发者不需要再为 USB 管脚调用该函数配置模拟模式。 -
开发者需要调用该函数使能某管脚的 ADC 输入功能。支持 ADC 输入功能的管脚如表 13.5 所示。
表 13.5: 支持 ADC 输入的管脚 管脚 单端模式 差分模式 7 AIN 0 AIN 0 P 8 AIN 1 AIN 0 N 9 AIN 2 AIN 1 P 10 AIN 3 AIN 1 N 11 AIN 4 AIN 2 P 12 AIN 5 AIN 2 N 13 AIN 6 AIN 3 P 14 AIN 7 AIN 3 N 其它还有 模拟比较器,32k 晶体引脚等。