一、历史在zephyr很早期阶段(2016年)年就引入了pinmux, 但由于早期没有统一的抽象,有少部分soc的设备树支持pin配置(nrf),绝大部分soc都是通过board下面的pinmux直接调用hal的PIN MUX接口(imx),因此Zephyr中的pinmux并不统一,导致添加不同soc的board的时候需要有不同的处理方式。Zephyr project在github.com/zephyrprojec,正式提出修改: 2.7.99到3.1之间pinctrl和pinmux共存 3.1完成pinctrl驱动,所有的board和外设驱动都切换为pinctrl 3.2后弃用pinmux,但保存代码 3.4后移除pinmux代码:github.com/zephyrproject,到目前的状态,zephyr已经完全移除了pinmux,并启用了pinctrl,所有的soc均可以通过设备树进行引脚配置,因此掌握pinctrl是变成了使用zephyr的一项基础要求。 背景知识pinctrl主要有两种功能:
不同的soc多路复用的方式不一样常见的复用和配置方式如下面两图(源之zephyr文档) 一种是集中方式,一个alt硬件控制一组复用功能,NXP和ST的soc采用这种方式。 另一种是分布方式,复用影视和配置由多个硬件控制,ESP和NRF的soc采用这种方式。 以上两种方式对使用者最直观的感受就是NXP/ST的soc的一个PIN只能按照spec映射到特定的几种片上设备上的特定功能,例如只能映射连接到SPI/I2C/UART的TX,不能映射到RX或者是SDHC控制器上。 而ESP和NRF的SOC就更为灵活一个PIN可以映射到任意片上设备上。 不同的soc其pin的硬件配置也不一样,例如一些支持硬件消抖动,有一些不支持。 Zephyr Pinctrl的简介在Zephyr中将不同的soc的引脚控制差异全部局限在设备树中 没有pinctrl前rt1062需要一个pinmux.c文件,里面放了大量的代码来配置硬件的复用,例如一个串口的就长这样: IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, 0); IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0); IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_12_LPUART1_TX, IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_SPEED(2) | IOMUXC_SW_PAD_CTL_PAD_DSE(6)); IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_SPEED(2) | IOMUXC_SW_PAD_CTL_PAD_DSE(6)); 有了pinctrl后,只需要修改设备树即可,就变成了这样。 pinmux_lpuart1: pinmux_lpuart1 { group0 { pinmux = <&iomuxc_gpio_ad_b0_13_lpuart1_rx>, <&iomuxc_gpio_ad_b0_12_lpuart1_tx>; drive-strength = "r0-6"; slew-rate = "slow"; nxp,speed = "100-mhz"; }; }; &lpuart1 { status = "okay"; current-speed = <115200>; pinctrl-0 = <&pinmux_lpuart1>; pinctrl-1 = <&pinmux_lpuart1_sleep>; pinctrl-names = "default", "sleep"; }; 设备树中将pinmux和引脚配置分离为不同的node,另外设备树中pinctrl和片上设备绑定要更为简便,设备更能支持多种状态,可以在运行时切换。 设备树说明分析NXP RT1062 UART示例参考zephyr/boards/arm/mm_feather目录中设备树文件mm_feather.dts和mm_feather-pinctrl.dtsi mm_feather-pinctrl.dtsi中定义了引脚的复用和配置 pinmux_lpuart1: pinmux_lpuart1 { group0 { pinmux = <&iomuxc_gpio_ad_b0_13_lpuart1_rx>, <&iomuxc_gpio_ad_b0_12_lpuart1_tx>; drive-strength = "r0-6"; slew-rate = "slow"; nxp,speed = "100-mhz"; }; }; pinmux_lpuart1_sleep: pinmux_lpuart1_sleep { group0 { pinmux = <&iomuxc_gpio_ad_b0_13_gpio1_io13>; drive-strength = "r0-6"; bias-pull-up; bias-pull-up-value = "100k"; slew-rate = "slow"; nxp,speed = "100-mhz"; }; group1 { pinmux = <&iomuxc_gpio_ad_b0_12_lpuart1_tx>; drive-strength = "r0-6"; slew-rate = "slow"; nxp,speed = "100-mhz"; }; ; 上面设备树定义了两组不同的状态 &lpuart1 { status = "okay"; current-speed = <115200>; pinctrl-0 = <&pinmux_lpuart1>; pinctrl-1 = <&pinmux_lpuart1_sleep>; pinctrl-names = "default", "sleep"; }; pinctrl-0和pinctrl-1分别绑定pinmux_lpuart1和pinmux_lpuart1_sleep,在uart的设备驱动代码中通过pinctrl-names指定的default和sleep对Pinctrl节点的状态进行引用 ESP32 UART示例参考zephyr/boards/riscv/esp32c3_devkitm中设备树文件:esp32c3_devkitm.dts和esp32c3_devkitm-pinctrl.dtsi esp32c3_devkitm-pinctrl.dtsi中定义了引脚的复用和和配置 uart0_default: uart0_default { group1 { pinmux = <UART0_TX_GPIO21>; }; group2 { pinmux = <UART0_RX_GPIO20>; bias-pull-up; }; }; 上面设备树只定义了一种状态即工作状态,这意味着串口驱动在睡眠模式下并不需要改变Pin的配置 UART0的TX口使用GPIO21, RX口使用GPIO20, RX口使用上拉 esp32c3_devkitm.dts中将pinctrl的节点和uart0绑定 &uart0 { status = "okay"; current-speed = <115200>; pinctrl-0 = <&uart0_default>; pinctrl-names = "default"; }; 设备树的形式从前面的说明可以看到设备树被拆分开来,dtsi中对引脚进行复用和配置,dts中进行设备绑定。这样做在dts中比较单一,当有硬件上的改动时,只用专注修改Pinctrl的dtsi。 |
|
来自: charlie_linux > 《dts tree》