我是靠谱客的博主 迷你小猫咪,最近开发中收集的这篇文章主要介绍13_pinctrl子系统,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

总结

pinctrl作为驱动
iomuxc节点在设备树里面 存储全部所需的引脚配置信息
最后因为犯傻,写了裸机使用datasheet的过程,不然脱离裸机太久

iomux节点匹配pinctrl子系统

控制硬件外设的时候 要知道有哪些gpio 再看gpio有哪些服用寄存器
接着在程序配置gpio相关寄存器 这样搞效率很低
所以用iomux节点保存所有的引脚组 pinctrl驱动起来的时候获得所有引脚信息 保存在内存

pinctrl子系统预先确定引脚的数量和名字

  • 为每个引脚的配置信息分配内存
  • pinctrl子系统统一管理每个引脚的使用状态
    -iomux节点存放了各种引脚属性,pinctrl驱动解析iomux节点,存放引脚信息进入内存

iomux节点里如何填写

//iomuxc节点
//imx6ull.dtsi
iomuxc: iomuxc@20e0000 {
				compatible = "fsl,imx6ul-iomuxc";
				reg = <0x20e0000 0x4000>;
			};
//继续扩展 引用iomux节点 **imx6ull-seeed-npi.dts**
&iomuxc {
	pinctrl-names = "default""init","sleep";  //选定引脚状态
	pinctrl-0 = <&pinctrl_uart1>;  //一个状态就是一组引脚,比如对应下面
	pinctrl-1 =<&xxx>;
	pinctrl-2 =<&yyy>;
...
	pinctrl_uart1: uart1grp {
		fsl,pins = <
			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
		>;
	};

...
}

上面 引脚里面的宏是什么意思

MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX
#define MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x0084 0x0310 0x0000 0 0
< mux_reg conf_reg input_reg mux_mode input_val >
 0x0084    0x0310    0x0000     0x0      0x0

mux_reg:引脚复用设置寄存器 基地址+mux_reg 就是 PIN 的复用寄存器地址。
conf_reg : 设置这个引脚的电气属性的寄存器地址 基地址+conf_reg =设置pin的电气属性地址
input_reg:引脚输入设置寄存器 有些外设有 input_reg 寄存器
引脚需要输入功能时设置
mux_mode:复用寄存器设置值
设置引脚复用
input_val:输入寄存器设置值
设置引脚输入特性

宏的最后跟随了一串数字 用来设置PIN的电气属性值 比如IO 的上/下拉、驱动能力和速度等
在这里插入图片描述
在这里插入图片描述

引脚状态初始化

在设备树里面节点 会变成plantform_dev 会执行probe进行匹配驱动
但是执行probe和drv配对之前 先回执行really_porbe() 这个函数和下面的引脚状态关系很大
用来初始化引脚值

//iomuxc节点
//imx6ull.dtsi
iomuxc: iomuxc@20e0000 {
				compatible = "fsl,imx6ul-iomuxc";
				reg = <0x20e0000 0x4000>;
			};
//继续扩展 引用iomux节点 **imx6ull-seeed-npi.dts**
&iomuxc {
	pinctrl-names = "default""init","sleep";  //选定引脚状态
	pinctrl-0 = <&pinctrl_uart1>;  //一个状态就是一组引脚,比如对应下面
	pinctrl-1 =<&xxx>;
	pinctrl-2 =<&yyy>;
...
	pinctrl_uart1: uart1grp {
		fsl,pins = <
			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
		>;
	};

...
}

还是用上一个设备树举例 看了下面的例子
就知道驱动的引脚其实在 probe之前就已经初始化好了电气属性了

drivers/base/dd.c
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = -EPROBE_DEFER;
...
re_probe:
	dev->driver = drv;

	ret = pinctrl_bind_pins(dev);  //这里根据iomux节点的 几个引脚状态来初始化引脚组
...

	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev); //这个是熟悉的probe
		if (ret)
			goto probe_failed;
	}

...
	}
int pinctrl_bind_pins(struct device *dev)
	dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);//从设备节点状态找到指定状态
														//本次是default状态
	dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_INIT); /这次找init状态
	if (IS_ERR(dev->pins->init_state))
		pinctrl_select_state(dev->pins->p,dev->pins->default_state);//没有init状态变成default状态
	else
		ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);//有的话引脚变成init状态

裸机流程

因为犯傻,一时候对裸机流程和这个分不清楚,datasheet忘记啥玩了 写在这里
问了mcu同学,如果是mcu怎么玩的: mcu都是物理地址,在mcu访问的寄存器中
从0开始到0x80000000这样 都是寄存器地址, 往后就是片内的flash地址 再往后就是rom地址
那我们如果裸机配置gpio的话 过程为 时钟打开->引脚复用->电气属性配置->设置gpio属性->设置中断属性

datasheet第30章 iomux章 包含了所有的引脚的复用配置寄存器 比如:IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B
UART1_CTS_B 这个有点像原理图上的pad_name或pin_name 用来定义不同的引脚名字
也包含了所有引脚的电气属性配置寄存器 比如 IOMUXC_SW_CTL_PAD_UART1_CTS_B
用来配置 迟滞比较器 来设置上下拉电阻 或IO作为输入的时候 设置IO使用上下拉还是状态保持器
或者禁止上下拉/状态保持器功能 或禁止或者使能开路输出 或IO_SPEED 或IO用作输出驱动能力 压摆率(io在0和1跳变要的时间)
上面已经给引脚选择了复用为gpio功能
下面翻到 datasheet到gpio章 找其他寄存器配置gpio
一组gpio最大32个,一个寄存器32位 刚刚好能配置一组状态

配置 GPIO_DR寄存器 决定这一组gpio如果输出的话 输出状态
配置 GPIO_GDIR寄存器 决定这一组gpio用作输入还是输出
配置 GPIO_ICR1或2寄存器 两个寄存器决定了中断触发方式,用两个32位寄存器决定了一组gpio中断触发方式
配置 GPIO_IMR寄存器 决定这组gpio是否打开中断
读取 GPIO_ISR寄存器 知道这组gpio中哪个gpio中断触发
@@@@@@@@@@参考正点的汇编点灯

最后

以上就是迷你小猫咪为你收集整理的13_pinctrl子系统的全部内容,希望文章能够帮你解决13_pinctrl子系统所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部